-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[exporter/bmchelix] New component: BMC Helix Exporter #36964
Open
NassimBtk
wants to merge
11
commits into
open-telemetry:main
Choose a base branch
from
sentrysoftware:feature/issue-36773-new-component-bmc-helix-exporter
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+826
−0
Open
Changes from 6 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
f23de13
[exporter/bmchelix] New component: BMC Helix Exporter
NassimBtk c5ea60b
[exporter/bmchelix] New component: BMC Helix Exporter
NassimBtk 02c1d33
[exporter/bmchelix] New component: BMC Helix Exporter
NassimBtk 9910f82
[exporter/bmchelix] New component: BMC Helix Exporter
NassimBtk 6c4866e
[exporter/bmchelix] New component: BMC Helix Exporter
NassimBtk 28425f7
Merge branch 'main' into feature/issue-36773-new-component-bmc-helix-…
NassimBtk ceec876
Merge branch 'main' into feature/issue-36773-new-component-bmc-helix-…
NassimBtk 5524227
Merge remote-tracking branch 'origin/main' into feature/issue-36773-n…
NassimBtk 9e606a3
[exporter/bmchelix] New component: BMC Helix Exporter
NassimBtk 0869621
[exporter/bmchelix] New component: BMC Helix Exporter
NassimBtk 0aadc01
[exporter/bmchelix] New component: BMC Helix Exporter
NassimBtk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Use this changelog template to create an entry for release notes. | ||
|
||
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' | ||
change_type: new_component | ||
|
||
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) | ||
component: exporter/bmchelix | ||
|
||
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). | ||
note: "Add a new component for exporting metrics to BMC Helix" | ||
|
||
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. | ||
issues: [36773] | ||
|
||
# (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: | ||
|
||
# If your change doesn't affect end users or the exported elements of any package, | ||
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. | ||
# 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: [user] |
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include ../../Makefile.Common |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
# BMC Helix Exporter | ||
|
||
<!-- status autogenerated section --> | ||
| Status | | | ||
| ------------- |-----------| | ||
| Stability | [development]: metrics | | ||
| Distributions | [] | | ||
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aexporter%2Fbmchelix%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aexporter%2Fbmchelix) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aexporter%2Fbmchelix%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aexporter%2Fbmchelix) | | ||
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@bertysentry](https://www.github.com/bertysentry), [@NassimBtk](https://www.github.com/NassimBtk) | | ||
|
||
[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development | ||
<!-- end autogenerated section --> | ||
|
||
This exporter supports sending metrics to [BMC Helix Operations Management](https://www.bmc.com/it-solutions/bmc-helix-operations-management.html) through its [metric ingestion REST API](https://docs.bmc.com/docs/helixoperationsmanagement/244/en/metric-operation-management-endpoints-in-the-rest-api-1392780044.html). | ||
|
||
## Getting Started | ||
|
||
The following settings are **required**: | ||
|
||
- `endpoint`: is the *BMC Helix Portal URL* of your environment, at **onbmc.com** for a BMC Helix SaaS tenant (e.g., `https://company.onbmc.com`), or your own Helix Portal URL for an on-prem instance. | ||
- `api_key`: API key to authenticate the exporter. Connect to BMC Helix Operations Management, go to the Administration > Repository page, and click on the Copy API Key button to get your API Key. Alternatively, it is recommended to create and use a dedicated [authentication key for external integration](https://docs.bmc.com/docs/helixportal244/using-api-keys-for-external-integrations-1391501992.html). | ||
|
||
Example: | ||
|
||
```yaml | ||
exporters: | ||
bmchelix/helix1: | ||
endpoint: https://company.onbmc.com | ||
api_key: <api-key> | ||
``` | ||
|
||
### Optional Settings | ||
|
||
The following settings can be **optionally configured**: | ||
|
||
- `timeout`: (default = `10s`) Timeout for requests made to the BMC Helix. | ||
- `retry_on_failure` [details here](https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter/exporterhelper#configuration) | ||
- `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) The upper bound on backoff; ignored if `enabled` is false. | ||
- `max_elapsed_time` (default = 300s) 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. | ||
- `resource_to_telemetry_conversion`: [details here](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/pkg/resourcetotelemetry#configuration) | ||
- `enabled` (default = true): If enabled is true, all the resource attributes will be converted to metric labels by default. | ||
|
||
Example: | ||
|
||
```yaml | ||
exporters: | ||
bmchelix/helix2: | ||
endpoint: https://company.onbmc.com | ||
api_key: <api-key> | ||
timeout: 20s | ||
retry_on_failure: | ||
enabled: true | ||
initial_interval: 5s | ||
max_interval: 1m | ||
max_elapsed_time: 8m | ||
resource_to_telemetry_conversion: | ||
enabled: true | ||
``` | ||
|
||
### Resource to Telemetry Conversion | ||
|
||
To ensure resource attributes (e.g., `host.name`) are available for all metrics, keep `resource_to_telemetry_conversion` enabled by default. Disabling it will remove resource attributes from metrics unless explicitly configured. | ||
|
||
--- | ||
|
||
## Setting Required Attributes for Metrics | ||
|
||
To ensure metrics are correctly populated in BMC Helix, the following attributes must be set either at the *Resource* level, or at the *Metric* level: | ||
|
||
- `entityName`: Unique identifier for the entity. Used as display name if `instanceName` is missing. | ||
- `entityTypeId`: Type identifier for the entity. | ||
- `instanceName`: Display name of the entity. | ||
|
||
> **Note:** If `entityName` or `entityTypeId` is missing, the metric will not be exported. | ||
|
||
To ensure the necessary attributes are present, it is recommended to leverage the [transform processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/transformprocessor) with [OTTL](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/pkg/ottl), and include it in the configuration of the telemetry pipeline. | ||
|
||
The minimal pipeline most often looks like: `OTEL metrics --> (batch/memory limit) --> transform processor --> bmchelix exporter`. | ||
|
||
### Transformer Example for Hardware Metrics | ||
|
||
You can use the following OpenTelemetry Transformation Language (OTTL) configuration to map these attributes dynamically: | ||
|
||
```yaml | ||
transform/hw_to_helix: | ||
# Apply transformations to all metrics | ||
metric_statements: | ||
|
||
- context: datapoint | ||
statements: | ||
# Create a new attribute 'entityName' with the value of 'id' | ||
- set(attributes["entityName"], attributes["id"]) where attributes["id"] != nil | ||
# Create a new attribute 'instanceName' with the value of 'name' | ||
- set(attributes["instanceName"], attributes["name"]) where attributes["name"] != nil | ||
|
||
- context: datapoint | ||
conditions: | ||
- IsMatch(metric.name, ".*\\.agent\\..*") | ||
statements: | ||
- set(attributes["entityName"], attributes["host.id"]) where attributes["host.id"] != nil | ||
- set(attributes["instanceName"], attributes["service.name"]) where attributes["service.name"] != nil | ||
- set(attributes["entityTypeId"], "agent") | ||
|
||
- context: datapoint | ||
statements: | ||
# Mapping entityTypeId based on metric names and attributes | ||
- set(attributes["entityTypeId"], "connector") where IsMatch(metric.name, ".*\\.connector\\..*") | ||
- set(attributes["entityTypeId"], "host") where IsMatch(metric.name, ".*\\.host\\..*") or attributes["hw.type"] == "host" | ||
- set(attributes["entityTypeId"], "battery") where IsMatch(metric.name, "hw\\.battery\\..*") or attributes["hw.type"] == "battery" | ||
- set(attributes["entityTypeId"], "blade") where IsMatch(metric.name, "hw\\.blade\\..*") or attributes["hw.type"] == "blade" | ||
- set(attributes["entityTypeId"], "cpu") where IsMatch(metric.name, "hw\\.cpu\\..*") or attributes["hw.type"] == "cpu" | ||
- set(attributes["entityTypeId"], "disk_controller") where IsMatch(metric.name, "hw\\.disk_controller\\..*") or attributes["hw.type"] == "disk_controller" | ||
- set(attributes["entityTypeId"], "enclosure") where IsMatch(metric.name, "hw\\.enclosure\\..*") or attributes["hw.type"] == "enclosure" | ||
- set(attributes["entityTypeId"], "fan") where IsMatch(metric.name, "hw\\.fan\\..*") or attributes["hw.type"] == "fan" | ||
- set(attributes["entityTypeId"], "gpu") where IsMatch(metric.name, "hw\\.gpu\\..*") or attributes["hw.type"] == "gpu" | ||
- set(attributes["entityTypeId"], "led") where IsMatch(metric.name, "hw\\.led\\..*") or attributes["hw.type"] == "led" | ||
- set(attributes["entityTypeId"], "logical_disk") where IsMatch(metric.name, "hw\\.logical_disk\\..*") or attributes["hw.type"] == "logical_disk" | ||
- set(attributes["entityTypeId"], "lun") where IsMatch(metric.name, "hw\\.lun\\..*") or attributes["hw.type"] == "lun" | ||
- set(attributes["entityTypeId"], "memory") where IsMatch(metric.name, "hw\\.memory\\..*") or attributes["hw.type"] == "memory" | ||
- set(attributes["entityTypeId"], "network") where IsMatch(metric.name, "hw\\.network\\..*") or attributes["hw.type"] == "network" | ||
- set(attributes["entityTypeId"], "other_device") where IsMatch(metric.name, "hw\\.other_device\\..*") or attributes["hw.type"] == "other_device" | ||
- set(attributes["entityTypeId"], "physical_disk") where IsMatch(metric.name, "hw\\.physical_disk\\..*") or attributes["hw.type"] == "physical_disk" | ||
- set(attributes["entityTypeId"], "power_supply") where IsMatch(metric.name, "hw\\.power_supply\\..*") or attributes["hw.type"] == "power_supply" | ||
- set(attributes["entityTypeId"], "robotics") where IsMatch(metric.name, "hw\\.robotics\\..*") or attributes["hw.type"] == "robotics" | ||
- set(attributes["entityTypeId"], "tape_drive") where IsMatch(metric.name, "hw\\.tape_drive\\..*") or attributes["hw.type"] == "tape_drive" | ||
- set(attributes["entityTypeId"], "temperature") where IsMatch(metric.name, "hw\\.temperature.*") or attributes["hw.type"] == "temperature" | ||
- set(attributes["entityTypeId"], "vm") where IsMatch(metric.name, "hw\\.vm\\..*") or attributes["hw.type"] == "vm" | ||
- set(attributes["entityTypeId"], "voltage") where IsMatch(metric.name, "hw\\.voltage.*") or attributes["hw.type"] == "voltage" | ||
``` | ||
|
||
This transformer dynamically sets the attributes required for BMC Helix based on metric names and resource attributes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package bmchelixexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/bmchelixexporter" | ||
|
||
import ( | ||
"errors" | ||
"time" | ||
|
||
"go.opentelemetry.io/collector/config/configretry" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry" | ||
) | ||
|
||
// Config struct is used to store the configuration of the exporter | ||
type Config struct { | ||
Endpoint string `mapstructure:"endpoint"` | ||
ApiKey string `mapstructure:"api_key"` | ||
Timeout time.Duration `mapstructure:"timeout"` | ||
RetryConfig configretry.BackOffConfig `mapstructure:"retry_on_failure"` | ||
ResourceToTelemetryConfig resourcetotelemetry.Settings `mapstructure:"resource_to_telemetry_conversion"` | ||
} | ||
|
||
// validate the configuration | ||
func (c *Config) Validate() error { | ||
if c.Endpoint == "" { | ||
return errors.New("endpoint is required") | ||
} | ||
if c.ApiKey == "" { | ||
return errors.New("api key is required") | ||
} | ||
if c.Timeout <= 0 { | ||
return errors.New("timeout must be a positive integer") | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package bmchelixexporter | ||
|
||
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/configretry" | ||
"go.opentelemetry.io/collector/confmap/confmaptest" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/bmchelixexporter/internal/metadata" | ||
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/resourcetotelemetry" | ||
) | ||
|
||
func TestLoadConfig(t *testing.T) { | ||
t.Parallel() | ||
|
||
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) | ||
require.NoError(t, err) | ||
|
||
tests := []struct { | ||
id component.ID | ||
expected component.Config | ||
errorMessage string | ||
}{ | ||
{ | ||
id: component.NewIDWithName(metadata.Type, "helix1"), | ||
expected: &Config{ | ||
Endpoint: "https://helix1:8080", | ||
ApiKey: "api_key", | ||
Timeout: 10 * time.Second, | ||
RetryConfig: configretry.NewDefaultBackOffConfig(), | ||
ResourceToTelemetryConfig: resourcetotelemetry.Settings{ | ||
Enabled: true, | ||
}, | ||
}, | ||
}, | ||
{ | ||
id: component.NewIDWithName(metadata.Type, "helix2"), | ||
expected: &Config{ | ||
Endpoint: "https://helix2:8080", | ||
ApiKey: "api_key", | ||
Timeout: 20 * time.Second, | ||
RetryConfig: configretry.BackOffConfig{ | ||
Enabled: true, | ||
InitialInterval: 5 * time.Second, | ||
RandomizationFactor: 0.5, | ||
Multiplier: 1.5, | ||
MaxInterval: 1 * time.Minute, | ||
MaxElapsedTime: 8 * time.Minute, | ||
}, | ||
ResourceToTelemetryConfig: resourcetotelemetry.Settings{ | ||
Enabled: true, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.id.String(), func(t *testing.T) { | ||
factory := NewFactory() | ||
cfg := factory.CreateDefaultConfig() | ||
|
||
sub, err := cm.Sub(tt.id.String()) | ||
require.NoError(t, err) | ||
require.NoError(t, sub.Unmarshal(cfg)) | ||
|
||
assert.NoError(t, component.ValidateConfig(cfg)) | ||
assert.Equal(t, tt.expected, cfg) | ||
}) | ||
} | ||
} | ||
|
||
func TestValidateConfig(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
config *Config | ||
err string | ||
}{ | ||
{ | ||
name: "valid_config", | ||
config: &Config{ | ||
Endpoint: "https://helix:8080", | ||
ApiKey: "api_key", | ||
Timeout: 10 * time.Second, | ||
}, | ||
}, | ||
{ | ||
name: "invalid_config1", | ||
config: &Config{ | ||
ApiKey: "api_key", | ||
}, | ||
err: "endpoint is required", | ||
}, | ||
{ | ||
name: "invalid_config2", | ||
config: &Config{ | ||
Endpoint: "https://helix:8080", | ||
}, | ||
err: "api key is required", | ||
}, | ||
{ | ||
name: "invalid_config3", | ||
config: &Config{ | ||
Endpoint: "https://helix:8080", | ||
ApiKey: "api_key", | ||
Timeout: -1, | ||
}, | ||
err: "timeout must be a positive integer", | ||
}, | ||
{ | ||
name: "invalid_config4", | ||
config: &Config{ | ||
Endpoint: "https://helix:8080", | ||
ApiKey: "api_key", | ||
Timeout: 0, | ||
}, | ||
err: "timeout must be a positive integer", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if tt.err != "" { | ||
err := tt.config.Validate() | ||
assert.Error(t, err) | ||
assert.Equal(t, tt.err, err.Error()) | ||
} else { | ||
assert.NoError(t, tt.config.Validate()) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
//go:generate mdatagen metadata.yaml | ||
|
||
// Package bmchelixexporter implements an exporter that sends data to BMC Helix. | ||
package bmchelixexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/bmchelixexporter" |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This option (
resource_to_telemetry_conversion
) should probably be removed as it's difficult to understand and is pretty useless in BMC Helix use case.