forked from open-telemetry/opentelemetry-collector-contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add huaweicloudlogsreceiver skelethon
- Loading branch information
narcis.gemene
committed
Sep 10, 2024
1 parent
6926554
commit 801a22e
Showing
23 changed files
with
2,113 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
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,205 @@ | ||
# Huawei Cloud CES Receiver | ||
|
||
<!-- status autogenerated section --> | ||
| Status | | | ||
| ------------- |-----------| | ||
| Stability | [development]: logs | | ||
| Distributions | [] | | ||
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fhuaweicloudlogs%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fhuaweicloudlogs) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fhuaweicloudlogs%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fhuaweicloudlogs) | | ||
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@heitorganzeli](https://www.github.com/heitorganzeli), [@narcis96](https://www.github.com/narcis96) | | ||
|
||
[development]: https://github.com/open-telemetry/opentelemetry-collector#development | ||
<!-- end autogenerated section --> | ||
|
||
This receiver contains the implementation of the Huawei Cloud [Log Tank Service](https://www.huaweicloud.com/intl/en-us/product/lts.html) (LTS) receiver for the OpenTelemetry Collector. The receiver collects logs from Huawei Cloud's LTS service and sends them to the OpenTelemetry Collector for processing and exporting. | ||
|
||
## Configuration | ||
|
||
The following settings are required: | ||
|
||
- `project_id`: The ID of the project in Huawei Cloud. This is used to identify which project's logs are to be collected. See [Obtaining a Project ID](https://support.huaweicloud.com/intl/en-us/devg-apisign/api-sign-provide-proid.html). | ||
|
||
- `region_id`: The ID of the Huawei Cloud region from which logs are collected. For example, `eu-west-101`. The full list of the available regions can be found [here](https://pkg.go.dev/github.com/huaweicloud/[email protected]/services/lts/v2/region). | ||
|
||
- `log_group_id`: A string indicating the ID of the log group. | ||
|
||
- `log_stream_id`: A string indicating the ID of the log stream. See [Obtaining Log Group and Log Stream IDs](https://support.huaweicloud.com/intl/en-us/api-lts/lts_api_0006.html#section1). | ||
|
||
- `no_verify_ssl`: A boolean flag indicating whether SSL verification should be disabled. Set to True to disable SSL verification. | ||
|
||
- `access_key`: The access key needed for LTS authentification. Check `Huawei Cloud SDK Authentication Setup` section for more details. | ||
|
||
- `secret_key`: The secret key needed for LTS authentification. Check `Huawei Cloud SDK Authentication Setup` section for more details. | ||
|
||
The following settings are optional: | ||
|
||
- `initial_delay`: The delay before the first collection of logs begins. This is a duration field, such as 5s for 5 seconds. | ||
|
||
- `collection_interval` (default = `60s`): This is the interval at which this receiver collects logs. This value must be a string readable by Golang's [time.ParseDuration](https://pkg.go.dev/time#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. We recommend a polling interval of at least one minute. | ||
|
||
- `retry_on_failure`: The following configurations can be used to control the retry policy of the LTS client. The default values are suitable for most deployment scenarios. | ||
- `enabled` (default true) | ||
- `initial_interval` (default 100ms) | ||
- `max_interval` (default 1s) | ||
- `max_elapsed_time` (default 15s) | ||
- `randomization_factor` (default 0.5) | ||
- `multiplier` (default 1.5) | ||
|
||
### Example Configuration | ||
|
||
```yaml | ||
receivers: | ||
huaweicloudlogsreceiver: | ||
collection_interval: 3h | ||
initial_delay: 5s | ||
access_key: ${env:HUAWEICLOUD_SDK_AK} | ||
secret_key: ${env:HUAWEICLOUD_SDK_SK} | ||
project_id: project_1 | ||
region_id: eu-west-101 | ||
log_group_id: test-group-id | ||
log_stream_id: test-stream-id | ||
no_verify_ssl: True | ||
``` | ||
The full list of settings exposed for this receiver are documented [here](./config.go). | ||
### Huawei Cloud SDK Authentication Setup | ||
To ensure secure authentication, the Access Key (AK) and Secret Key (SK) used by the Huawei Cloud SDK must be stored in environment variables. See [Obtaining an AK/SK](https://support.huaweicloud.com/intl/en-us/devg-apisign/api-sign-provide-aksk.html). | ||
Before running the application, you need to set the environment variables `HUAWEICLOUD_SDK_AK` and `HUAWEICLOUD_SDK_SK` in your local environment. Here’s how you can do it: | ||
|
||
1. Open your terminal. | ||
2. Set the environment variables by executing the following commands: | ||
|
||
```sh | ||
export HUAWEICLOUD_SDK_AK=your-access-key | ||
export HUAWEICLOUD_SDK_SK=your-secret-key | ||
``` | ||
|
||
3. Verify that the variables are set correctly: | ||
|
||
```sh | ||
echo $HUAWEICLOUD_SDK_AK | ||
echo $HUAWEICLOUD_SDK_SK | ||
``` | ||
|
||
## Error handling | ||
If you encounter any LTS errors, please refer to the [Huawei Cloud Error Codes](https://support.huaweicloud.com/intl/en-us/ae-ad-1-api-lts/lts_api_0021.html). | ||
|
||
## Converting LTS Log Representation to OpenTelemetry Log Representation | ||
|
||
| Source Field | Target Field | Description | | ||
|---------------------------|----------------------------------------------------|---------------------------------------------------------------------------------------------------| | ||
| **Log Content (timestamp)** | `logRecord.observedTimestamp` | The timestamp extracted from the log content. It follows the layout `"2006-01-02/15:04:05"`. Converted to Unix time in nanoseconds. | | ||
| **Log Content (body)** | `logRecord.body` | The main content of the log. Stored as a string in the OTLP log body. | | ||
| **Labels (key)** | `logRecord.attributes` | Each label from the LTS log is converted to an attribute in the OTLP log, where the label's key is used as the attribute's key. | | ||
| **Labels (value)** | `logRecord.attributes` | The corresponding value of each LTS log label key is stored as the attribute's value. | | ||
| **Line Number** | `logRecord.attributes.lineNum` | The line number from the LTS log, if available. Stored as an attribute with the key `lineNum`. | | ||
| **Project ID** | `resource.attributes.project.id` | The project ID used in the configuration file of the receiver.. | | ||
| **Region ID** | `resource.attributes.region.id` | The region id used in the configuration file of the receiver. | | ||
| **Group ID** | `resource.attributes.group.id` | The log group id used in the configuration file of the receiver. | | ||
| **Stream ID** | `resource.attributes.stream.id` | The log stream id used in the configuration file of the receiver. | | ||
| *N/A* | `resource.attributes.cloud.provider` | Set to `"huawei_cloud"` as the cloud provider. | | ||
| *N/A* | `scopeLogs.scope.name` | Set to `"huawei_cloud_lts"` as the scope name. | | ||
| *N/A* | `scopeLogs.scope.version` | Set to `"v2"` as the scope version. | | ||
|
||
This mapping ensures that logs from Huawei Cloud's LTS can be seamlessly integrated into systems using the OpenTelemetry Protocol for observability. | ||
|
||
|
||
### Notes | ||
|
||
- The `timestamp` field in the source is converted from milliseconds to nanoseconds in the target field. | ||
- Some fields are added in the target format with constant values to provide additional context and metadata. | ||
|
||
### Example: | ||
|
||
```json | ||
[ | ||
{ | ||
"content": "2020-07-25/14:40:00 this logis Error NO 2", | ||
"line_num": "123", | ||
"labels": { | ||
"hostIP": "192.168.0.156", | ||
"hostId": "9787ef31-f171-4eff-ba71-72d580f11f60", | ||
"podName": "default_procname", | ||
"clusterId": "CONFIG_FILE", | ||
"nameSpace":"CONFIG_FILE", | ||
"category": "LTS", | ||
} | ||
}, | ||
{ | ||
"content": "2020-07-25/14:50:00 this logis Error NO 3", | ||
"line_num": "456", | ||
"labels": { | ||
"hostIP": "192.168.0.156", | ||
"hostId": "9787ef31-f171-4eff-ba71-72d580f11f60", | ||
"podName": "default_procname", | ||
"clusterId": "CONFIG_FILE", | ||
"nameSpace":"CONFIG_FILE", | ||
"category": "LTS", | ||
} | ||
}, | ||
] | ||
``` | ||
|
||
converts to | ||
|
||
```json | ||
{ | ||
"resourceLogs": [ | ||
{ | ||
"resource": { | ||
"attributes": { | ||
"cloud.provider": "huawei_cloud", | ||
"project.id": "project1", | ||
"region.id": "region1", | ||
"group.id": "group1", | ||
"stream.id":"stream1" | ||
}, | ||
"scopeLogs": [ | ||
{ | ||
"scope": { | ||
"name": "huawei_cloud_lts", | ||
"version": "v2" | ||
}, | ||
"logRecords": [ | ||
{ | ||
"observedTimeUnixNano": "1595688000000000000", | ||
"body": { | ||
"stringValue": "2020-07-25/14:40:00 this log is Error NO 2" | ||
}, | ||
"attributes": { | ||
"hostIP": "192.168.0.156", | ||
"hostId": "9787ef31-f171-4eff-ba71-72d580f11f60", | ||
"podName": "default_procname", | ||
"clusterId": "CONFIG_FILE", | ||
"nameSpace":"CONFIG_FILE", | ||
"category": "LTS", | ||
"lineNum": "123" | ||
}, | ||
}, | ||
{ | ||
"observedTimeUnixNano": "1595688600000000000", | ||
"body": { | ||
"stringValue": "2020-07-25/14:50:00 this log is Error NO 3" | ||
}, | ||
"attributes": { | ||
"hostIP": "192.168.0.156", | ||
"hostId": "9787ef31-f171-4eff-ba71-72d580f11f60", | ||
"podName": "default_procname", | ||
"clusterId": "CONFIG_FILE", | ||
"nameSpace":"CONFIG_FILE", | ||
"category": "LTS", | ||
"lineNum": "456" | ||
}, | ||
} | ||
] | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
``` |
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,122 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package huaweicloudlogsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/huaweicloudlogsreceiver" | ||
|
||
import ( | ||
"errors" | ||
"net/url" | ||
"strconv" | ||
|
||
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/config" | ||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/config/confighttp" | ||
"go.opentelemetry.io/collector/config/configopaque" | ||
"go.opentelemetry.io/collector/config/configretry" | ||
"go.opentelemetry.io/collector/receiver/scraperhelper" | ||
"go.uber.org/multierr" | ||
) | ||
|
||
var ( | ||
// Predefined error responses for configuration validation failures | ||
errMissingProjectID = errors.New(`"project_id" is not specified in config`) | ||
errMissingRegionID = errors.New(`"region_id" is not specified in config`) | ||
errMissingGroupID = errors.New(`"log_group_id" is not specified in config`) | ||
errMissingStreamID = errors.New(`"log_stream_id" is not specified in config`) | ||
|
||
errInvalidProxy = errors.New(`"proxy_address" must be specified if "proxy_user" or "proxy_password" is set"`) | ||
) | ||
|
||
// Config represent a configuration for the CloudWatch logs exporter. | ||
type Config struct { | ||
scraperhelper.ControllerConfig `mapstructure:",squash"` | ||
confighttp.ClientConfig `mapstructure:",squash"` | ||
// Set of attributes used to configure huawei's CES SDK connection | ||
HuaweiSessionConfig `mapstructure:",squash"` | ||
|
||
// ProjectID is a string to reference project where logs should be associated with. | ||
// If ProjectID is not filled in, the SDK will automatically call the IAM service to query the project id corresponding to the region. | ||
ProjectID string `mapstructure:"project_id"` | ||
|
||
// RegionID is the ID of the LTS region. | ||
RegionID string `mapstructure:"region_id"` | ||
|
||
// GroupID is the ID of the LTS log group. | ||
GroupID string `mapstructure:"log_group_id"` | ||
|
||
// Stream is the ID of the LTS log stream. | ||
StreamID string `mapstructure:"log_stream_id"` | ||
|
||
BackOffConfig configretry.BackOffConfig `mapstructure:"retry_on_failure"` | ||
} | ||
|
||
type HuaweiSessionConfig struct { | ||
AccessKey configopaque.String `mapstructure:"access_key"` | ||
|
||
SecretKey configopaque.String `mapstructure:"secret_key"` | ||
// Number of seconds before timing out a request. | ||
NoVerifySSL bool `mapstructure:"no_verify_ssl"` | ||
// Upload segments to AWS X-Ray through a proxy. | ||
ProxyAddress string `mapstructure:"proxy_address"` | ||
ProxyUser string `mapstructure:"proxy_user"` | ||
ProxyPassword string `mapstructure:"proxy_password"` | ||
} | ||
|
||
var _ component.Config = (*Config)(nil) | ||
|
||
// Validate config | ||
func (config *Config) Validate() error { | ||
var err error | ||
if config.ProjectID == "" { | ||
err = multierr.Append(err, errMissingProjectID) | ||
} | ||
if config.RegionID == "" { | ||
err = multierr.Append(err, errMissingRegionID) | ||
} | ||
if config.GroupID == "" { | ||
err = multierr.Append(err, errMissingGroupID) | ||
} | ||
if config.StreamID == "" { | ||
err = multierr.Append(err, errMissingStreamID) | ||
} | ||
|
||
// Validate that ProxyAddress is provided if ProxyUser or ProxyPassword is set | ||
if (config.ProxyUser != "" || config.ProxyPassword != "") && config.ProxyAddress == "" { | ||
err = multierr.Append(err, errInvalidProxy) | ||
} | ||
|
||
return err | ||
} | ||
|
||
func createHTTPConfig(cfg HuaweiSessionConfig) (*config.HttpConfig, error) { | ||
if cfg.ProxyAddress == "" { | ||
return config.DefaultHttpConfig().WithIgnoreSSLVerification(cfg.NoVerifySSL), nil | ||
} | ||
proxy, err := configureHTTPProxy(cfg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return config.DefaultHttpConfig().WithProxy(proxy), nil | ||
} | ||
|
||
func configureHTTPProxy(cfg HuaweiSessionConfig) (*config.Proxy, error) { | ||
proxyURL, err := url.Parse(cfg.ProxyAddress) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
proxy := config.NewProxy(). | ||
WithSchema(proxyURL.Scheme). | ||
WithHost(proxyURL.Hostname()) | ||
if len(proxyURL.Port()) > 0 { | ||
if i, err := strconv.Atoi(proxyURL.Port()); err == nil { | ||
proxy = proxy.WithPort(i) | ||
} | ||
} | ||
|
||
// Configure the username and password if the proxy requires authentication | ||
if len(cfg.ProxyUser) > 0 { | ||
proxy = proxy.WithUsername(cfg.ProxyUser).WithPassword(cfg.ProxyPassword) | ||
} | ||
return proxy, nil | ||
} |
Oops, something went wrong.