Skip to content
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

[feature] Solarwinds Extension #4

Merged
merged 43 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
69f0517
Extension
david-sevcik Dec 9, 2024
0783718
Create extension_test.go
david-sevcik Dec 10, 2024
8c92f1e
Update metadata.yaml
david-sevcik Dec 10, 2024
861044e
Fix Tests
simek-m Dec 10, 2024
07fb2af
Update go version to 1.23.4
david-sevcik Dec 10, 2024
0db8be1
Update go docker image to 1.23.4
david-sevcik Dec 10, 2024
b23d5c6
Add licences
david-sevcik Dec 10, 2024
d34d89b
Avoid checking generated files
david-sevcik Dec 10, 2024
6dbe76e
Fix licence
david-sevcik Dec 10, 2024
39510a5
Use Correct Iface
simek-m Dec 10, 2024
56ef9a3
Fix found extension
david-sevcik Dec 11, 2024
66da104
Follow Collector Cfg Format for Extension
simek-m Dec 11, 2024
f211fbf
Update Exporter README
simek-m Dec 12, 2024
4b11ae0
Use component.ID.UnmarshallText Directly
simek-m Dec 12, 2024
2d55746
Improve Error Handling
simek-m Dec 12, 2024
e2d96df
Refactor the heartbeat encapsulation
david-sevcik Dec 12, 2024
f5e74b1
Fix shutdown
david-sevcik Dec 12, 2024
9748518
Pipeline break test
david-sevcik Dec 12, 2024
dfb5a5d
Fix not breaking the pipeline when tests fail
david-sevcik Dec 12, 2024
cd620de
Fix test
david-sevcik Dec 12, 2024
16cb6d4
Use Sentinel Error
simek-m Dec 12, 2024
9525a7d
Merge branch 'main' into NH-95440-solarwinds-extension
david-sevcik Dec 12, 2024
5c98788
Add Simple Test for Hearthbeat
simek-m Dec 13, 2024
535b3a1
Add Config Tests
simek-m Dec 16, 2024
dbfbc00
Fix Build
simek-m Dec 16, 2024
6362c9e
Fix Docstring
simek-m Dec 16, 2024
a5dabb5
Expose 'insecure' Config Flag to Disable TLS in Tests
simek-m Dec 16, 2024
464a11b
Merge branch 'main' into NH-95440-solarwinds-extension
david-sevcik Dec 16, 2024
eaeaf07
Separating testing configuration
david-sevcik Dec 16, 2024
3242584
Documentation
david-sevcik Dec 16, 2024
52e09d0
New line
david-sevcik Dec 16, 2024
37baef7
Error rename
david-sevcik Dec 16, 2024
413b882
Use Standard Library Conventions for Error Naming
simek-m Dec 17, 2024
53e7753
Add Test for Insecure
simek-m Dec 17, 2024
1f6e7ea
Validate Extension Name in Exporter
simek-m Dec 17, 2024
e6a91ea
Add comment
david-sevcik Dec 17, 2024
ff4c816
Update extension/solarwindsextension/README.md
david-sevcik Dec 17, 2024
a1c5372
Replace SWO with SolarWinds Observability SaaS
david-sevcik Dec 17, 2024
5fd5d88
Update exporter/solarwindsexporter/README.md
david-sevcik Dec 18, 2024
1f1e241
Update README.md
david-sevcik Dec 18, 2024
81d5596
Update README.md
david-sevcik Dec 18, 2024
0e3e6da
Downgrade confmap to Match Other OTEL Deps
simek-m Dec 18, 2024
dd69d6c
Fix Test
simek-m Dec 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## v0.113.1
Adds [SolarWinds Extension](./extension/solarwindsextension). The [SolarWinds Exporter](./exporter/solarwindsexporter) is now dependent on the extension.

## v0.113.0
Initial version of SolarWinds OpenTelemetry Collector.
The collector provides all available components (receivers, processors, exporters, connectors, providers)
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
include Makefile.Common

ALL_SRC := $(shell find . \( -name "*.go" -o -name "*.sh" \) \
-not -path '*generated*' \
simek-m marked this conversation as resolved.
Show resolved Hide resolved
-type f | sort)

.PHONY: ci-check-licenses
Expand Down
9 changes: 9 additions & 0 deletions Makefile.Common
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,12 @@ $(TOOLS_BIN_DIR):

$(TOOLS_BIN_NAMES): $(TOOLS_BIN_DIR) $(TOOLS_MOD_DIR)/go.mod
cd $(TOOLS_MOD_DIR) && $(GOCMD) build -o $@ -trimpath $(filter %/$(notdir $@),$(TOOLS_PKG_NAMES))

.PHONY: test
test:
go test ./...

.PHONY: generate
generate:
go generate ./...

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ The SolarWinds OpenTelemetry collector contains following components:
- full set of [opentelemetry-collector processors](https://github.com/open-telemetry/opentelemetry-collector/tree/v0.113.0/processor)
- full set of [opentelemetry-collector-contrib processors](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.113.0/processor)
- exporters
- [`solarwindsexporter`](./exporter/solarwindsexporter)
- [`otlpexporter`](https://github.com/open-telemetry/opentelemetry-collector/tree/v0.113.0/exporter/otlpexporter)
- [`fileexporter`](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.113.0/exporter/fileexporter)
- [`solarwindsexporter`](./exporter/solarwindsexporter)
- [`debugexporter`](https://github.com/open-telemetry/opentelemetry-collector/tree/v0.113.0/exporter/debugexporter)
- [`nopexporter`](https://github.com/open-telemetry/opentelemetry-collector/tree/v0.113.0/exporter/nopexporter)
- extensions
- [`solarwindsextension`](./extension/solarwindsextension)
- full set of [opentelemetry-collector extensions](https://github.com/open-telemetry/opentelemetry-collector/tree/v0.113.0/extension)
- full set of [opentelemetry-collector-contrib extensions](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.113.0/extension)
- connectors
Expand Down
4 changes: 2 additions & 2 deletions build/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM docker.io/library/golang:1.22.7-bookworm AS base
FROM docker.io/library/golang:1.23.4-bookworm AS base

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some new features were used in the codebase, hence updated the GO version

COPY /LICENSE /LICENSE
COPY ./ /src
Expand All @@ -8,7 +8,7 @@ FROM base AS builder
RUN cd /src/cmd/solarwinds-otel-collector && CGO_ENABLED=0 GOEXPERIMENT=boringcrypto go build -trimpath -o /src/bin/solarwinds-otel-collector "-ldflags=-s -w"

FROM builder AS tests
WORKDIR src
WORKDIR /src
# run tests for go modules of all maintained components
simek-m marked this conversation as resolved.
Show resolved Hide resolved
# image build is stopped if test failure is detected
RUN find . -name go.mod -not -path "./cmd/solarwinds-otel-collector/*" -execdir go test ./... \; | ( ! grep FAIL )
Expand Down
2 changes: 2 additions & 0 deletions cmd/solarwinds-otel-collector/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package main
import (
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/fileexporter"
"github.com/solarwinds/solarwinds-otel-collector/exporter/solarwindsexporter"
"github.com/solarwinds/solarwinds-otel-collector/extension/solarwindsextension"
"go.opentelemetry.io/collector/exporter/debugexporter"
"go.opentelemetry.io/collector/exporter/nopexporter"
"go.opentelemetry.io/collector/exporter/otlpexporter"
Expand Down Expand Up @@ -219,6 +220,7 @@ func components() (otelcol.Factories, error) {
sigv4authextension.NewFactory(),
solarwindsapmsettingsextension.NewFactory(),
sumologicextension.NewFactory(),
solarwindsextension.NewFactory(),
)

if err != nil {
Expand Down
11 changes: 7 additions & 4 deletions cmd/solarwinds-otel-collector/go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module github.com/solarwinds/solarwinds-otel-collector

go 1.22.7

toolchain go1.22.9
go 1.23.4
adschr marked this conversation as resolved.
Show resolved Hide resolved

require (
github.com/open-telemetry/opentelemetry-collector-contrib/confmap/provider/aesprovider v0.113.0
Expand Down Expand Up @@ -161,8 +159,9 @@ require (
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.113.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zookeeperreceiver v0.113.0
github.com/solarwinds/solarwinds-otel-collector/exporter/solarwindsexporter v0.113.0
github.com/solarwinds/solarwinds-otel-collector/extension/solarwindsextension v0.113.0
go.opentelemetry.io/collector/component v0.113.0
go.opentelemetry.io/collector/confmap v1.19.0
go.opentelemetry.io/collector/confmap v1.21.0
go.opentelemetry.io/collector/confmap/provider/envprovider v1.19.0
go.opentelemetry.io/collector/confmap/provider/fileprovider v1.19.0
go.opentelemetry.io/collector/confmap/provider/httpprovider v1.19.0
Expand Down Expand Up @@ -712,3 +711,7 @@ require (
)

replace github.com/solarwinds/solarwinds-otel-collector/exporter/solarwindsexporter => ../../exporter/solarwindsexporter

replace github.com/solarwinds/solarwinds-otel-collector/extension/solarwindsextension => ../../extension/solarwindsextension

replace github.com/solarwinds/solarwinds-otel-collector/pkg/testutil => ../../pkg/testutil
4 changes: 2 additions & 2 deletions cmd/solarwinds-otel-collector/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2542,8 +2542,8 @@ go.opentelemetry.io/collector/config/configtls v1.19.0 h1:GQ/cF1hgNqHVBq2oSSrOFX
go.opentelemetry.io/collector/config/configtls v1.19.0/go.mod h1:1hyqnYB3JqEUlk1ME/s9HYz4oCRcxQCRxsJitFFT/cA=
go.opentelemetry.io/collector/config/internal v0.114.0 h1:uWSDWTJb8T6xRjKD9/XmEARakXnxgYVYKUeId78hErc=
go.opentelemetry.io/collector/config/internal v0.114.0/go.mod h1:yC7E4h1Uj0SubxcFImh6OvBHFTjMh99+A5PuyIgDWqc=
go.opentelemetry.io/collector/confmap v1.19.0 h1:TQ0lZpAKqgsE0EKk+u4JA+uBbPYeFRmWP3GH43w40CY=
go.opentelemetry.io/collector/confmap v1.19.0/go.mod h1:GgNu1ElPGmLn9govqIfjaopvdspw4PJ9KeDtWC4E2Q4=
go.opentelemetry.io/collector/confmap v1.21.0 h1:1tIcx2/Suwg8VhuPmQw87ba0ludPmumpFCFRZZa6RXA=
go.opentelemetry.io/collector/confmap v1.21.0/go.mod h1:Rrhs+MWoaP6AswZp+ReQ2VO9dfOfcUjdjiSHBsG+nec=
go.opentelemetry.io/collector/confmap/provider/envprovider v1.19.0 h1:f8O/I5pVRN86Gx5mHekNx92S6fGdOS4VcooRJKWe6Bs=
go.opentelemetry.io/collector/confmap/provider/envprovider v1.19.0/go.mod h1:AiaW5YW1LD0/WlZuc8eZuZPBH6PA9QqsiAYRX1iC6T0=
go.opentelemetry.io/collector/confmap/provider/fileprovider v1.19.0 h1:TYwyk4ea3U+5MYcEjrzZAaonBcLlabQu8CZeB7ekAYY=
Expand Down
3 changes: 2 additions & 1 deletion cmd/solarwinds-otel-collector/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package main

import (
"log"

"github.com/open-telemetry/opentelemetry-collector-contrib/confmap/provider/aesprovider"
"github.com/open-telemetry/opentelemetry-collector-contrib/confmap/provider/s3provider"
"github.com/open-telemetry/opentelemetry-collector-contrib/confmap/provider/secretsmanagerprovider"
Expand All @@ -27,7 +29,6 @@ import (
"go.opentelemetry.io/collector/confmap/provider/httpsprovider"
"go.opentelemetry.io/collector/confmap/provider/yamlprovider"
"go.opentelemetry.io/collector/otelcol"
"log"
)

func main() {
Expand Down
8 changes: 1 addition & 7 deletions exporter/solarwindsexporter/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
.PHONY: test
test:
go test ./...

.PHONY: generate
generate:
go generate ./...
include ../../Makefile.Common
42 changes: 35 additions & 7 deletions exporter/solarwindsexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,24 @@ SolarWinds Exporter is a convenience wrapper around [OTLP gRPC Exporter](https:/

## Getting Started

You just need to include the SolarWinds Exporter in your exporter definitions and provide the following minimal configuration:
You just need to include the SolarWinds Exporter in your exporter definitions and no additional configuration is needed. It always needs to be used together with the [Solarwinds Extension](../../extension/solarwindsextension).

```yaml
exporters:
solarwinds:
token: "YOUR-INGESTION-TOKEN"
extensions:
solarwinds:
token: "TOKEN"
data_center: "na-01"
```
- `token` (mandatory) - You can generate your token in your SolarWinds Observability SaaS account under _Settings / API Tokens / Create API Token_. The type is "Ingestion". You can find the complete documentation [here](https://documentation.solarwinds.com/en/success_center/observability/content/settings/api-tokens.htm).
- `data_center` (mandatory) - Data center is the region you picked during the sign-up process. You can easily see in URLs after logging in to SolarWinds Observability SaaS - it's either `na-01`, `na-02` or `eu-01`. Please refer to the [documentation](https://documentation.solarwinds.com/en/success_center/observability/content/system_requirements/endpoints.htm#Find) for details.

## Full configuration

### Example with Defaults
```yaml
exporters:
solarwinds:
token: "YOUR-INGESTION-TOKEN" # No default (mandatory field).
data_center: "na-01" # No default (mandatory field).
extension: "solarwinds"
timeout: "10s"
sending_queue:
enabled: true
Expand All @@ -44,14 +43,43 @@ exporters:
multiplier: 1.5
max_interval: "30s"
max_elapsed_time: "300s"
extensions:
solarwinds:
token: "TOKEN"
data_center: "na-01"
```
- `timeout` (optional) - Timeout for each attempt to send data to the SaaS service. A timeout of zero disables the timeout. The **default** is `5s`.
> [!TIP]
> You can omit `extension` from the Solarwinds Exporter configuration above if there's only a single instance of the Solarwinds Extension.

- `extension` (optional) - This name identifies an instance of the [Solarwinds Extension](../../extension/solarwindsextension) to be used by this exporter to obtain its configuration.
If there is only a single instance of the extension, the configuration value is optional. The format mimics the identifier as it occurs in the collector configuration -
`type/name`, e.g `solarwinds` or `solarwinds/1` for multiple instances of the extension. You would use multiple instances for publishing your telemetry to
multiple **SolarWinds Observability SaaS** organizations.
- `timeout` (optional) - Timeout for each attempt to send data to the SaaS service. A timeout of zero disables the timeout. The **default** is `10s`.
- `retry_on_failure` (optional) - These options configure the retry behavior. Please refer to the [Exporter Helper documentation](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md).
- `sending_queue` (optional) - These are the options to set queuing in the exporter. A full descriptions can be similarly found in [Exporter Helper documentation](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md).

> [!NOTE]
> The format of all durations above follow the [time.ParseDuration](https://pkg.go.dev/time#ParseDuration) format of "Duration" strings.

### Example with Multiple Solarwinds Extensions
```yaml
exporters:
solarwinds:
extension: "solarwinds/1"
extensions:
solarwinds/1:
token: YOUR-INGESTION-TOKEN1"
data_center: "na-01"
solarwinds/2:
token: YOUR-INGESTION-TOKEN2"
data_center: "na-02"
```
> [!WARNING]
> The `extension` configuration value cannot be omitted in the example above.
> There are multiple instances of the Solarwinds Extension and you need to
> configure which instance to use to obtain configuration for the exporter.

## Development
- **Tests** can be executed with `make test`.
- After changes to `metadata.yaml` generated files need to be re-generated with `make generate`. The [mdatagen](http://go.opentelemetry.io/collector/cmd/mdatagen) tool has to be in the `PATH`.
93 changes: 40 additions & 53 deletions exporter/solarwindsexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
package solarwindsexporter

import (
"errors"
"fmt"
"strings"
"time"

"go.opentelemetry.io/collector/component"
Expand All @@ -29,37 +27,11 @@ import (
"go.opentelemetry.io/collector/exporter/otlpexporter"
)

// dataCenterToURLMapping maps a data center ID to
// to its corresponding OTLP endpoint URL.
var dataCenterToURLMapping = map[string]string{
"na-01": "otel.collector.na-01.cloud.solarwinds.com:443",
"na-02": "otel.collector.na-02.cloud.solarwinds.com:443",
"eu-01": "otel.collector.eu-01.cloud.solarwinds.com:443",
}

// lookupDataCenterURL returns the OTLP endpoint URL
// for a `dc` data center ID. Matching is case-insensitive.
// It fails with an error if `dc` doesn't identify a data center.
func lookupDataCenterURL(dc string) (string, error) {
dcLowercase := strings.ToLower(dc)

url, ok := dataCenterToURLMapping[dcLowercase]
if !ok {
return "", fmt.Errorf("unknown data center ID: %s", dc)
}

return url, nil
}

// Config represents a Solarwinds Exporter configuration.
type Config struct {
// DataCenter ID (e.g. na-01).
DataCenter string `mapstructure:"data_center"`
// EndpointURLOverride sets OTLP endpoint directly.
// Warning: Intended for testing use only, use `DataCenter` instead.
EndpointURLOverride string `mapstructure:"endpoint_url_override"`
// IngestionToken is your secret generated SWO ingestion token.
IngestionToken configopaque.String `mapstructure:"token"`
// Extension identifies a Solarwinds Extension to
// use for obtaining connection credentials in this exporter.
Extension string `mapstructure:"extension"`
// BackoffSettings configures retry behavior of the exporter.
// See [configretry.BackOffConfig] documentation.
BackoffSettings configretry.BackOffConfig `mapstructure:"retry_on_failure"`
Expand All @@ -68,12 +40,33 @@ type Config struct {
QueueSettings exporterhelper.QueueConfig `mapstructure:"sending_queue"`
// Timeout configures timeout in the underlying OTLP exporter.
Timeout exporterhelper.TimeoutConfig `mapstructure:"timeout,squash"`
adschr marked this conversation as resolved.
Show resolved Hide resolved

// ingestionToken stores the token provided by the Solarwinds Extension.
ingestionToken configopaque.String `mapstructure:"-"`
// endpointURL stores the URL provided by the Solarwinds Extension.
endpointURL string `mapstructure:"-"`
// insecure stores the option to disable TLS provided
// by the Solarwinds Extension.
insecure bool `mapstructure:"-"`
}

// NewDefaultConfig creates a new default configuration.
// extensionAsComponent tries to parse `extension` value of the form 'type/name'
// or 'type' from the configuration to [component.ID]. If the `extension value is empty,
// it returns `nil` with a `nil` error.
//
// Warning: it doesn't define mandatory `Token` and `DataCenter`
// fields that need to be explicitly provided.
// It uses [component.ID.UnmarshalText] and behaves accordingly.
func (cfg *Config) extensionAsComponent() (*component.ID, error) {
if cfg.Extension == "" {
return nil, nil
}

parsedID := &component.ID{}
err := parsedID.UnmarshalText([]byte(cfg.Extension))

return parsedID, err
}

// NewDefaultConfig creates a new default configuration.
func NewDefaultConfig() component.Config {
// Using a higher default than OTLP Exporter does (5s)
// based on previous experience with unnecessary timeouts.
Expand All @@ -90,16 +83,14 @@ func NewDefaultConfig() component.Config {

// Validate checks the configuration for its validity.
func (cfg *Config) Validate() error {
if cfg.DataCenter == "" && cfg.EndpointURLOverride == "" {
adschr marked this conversation as resolved.
Show resolved Hide resolved
return errors.New("invalid configuration: data center must be provided")
}

if _, err := lookupDataCenterURL(cfg.DataCenter); err != nil {
return fmt.Errorf("invalid data center ID: %w", err)
}

if cfg.IngestionToken == "" {
return errors.New("invalid configuration: token must be set")
if len(cfg.Extension) != 0 {
_, err := cfg.extensionAsComponent()
if err != nil {
return fmt.Errorf(
"invalid configuration: %q is not a correct value for 'extension'",
cfg.Extension,
)
}
}

return nil
Expand All @@ -111,15 +102,8 @@ func (cfg *Config) OTLPConfig() (*otlpexporter.Config, error) {
return nil, err
}

// Use overridden URL if provided.
endpointURL := cfg.EndpointURLOverride
if endpointURL == "" {
// Error doesn't need to be checked, it's been validated above.
endpointURL, _ = lookupDataCenterURL(cfg.DataCenter)
}

// Headers - set bearer auth.
bearer := fmt.Sprintf("Bearer %s", string(cfg.IngestionToken))
bearer := fmt.Sprintf("Bearer %s", string(cfg.ingestionToken))
headers := map[string]configopaque.String{
"Authorization": configopaque.String(bearer),
}
Expand All @@ -130,7 +114,7 @@ func (cfg *Config) OTLPConfig() (*otlpexporter.Config, error) {
Keepalive: configgrpc.NewDefaultKeepaliveClientConfig(),
BalancerName: configgrpc.BalancerName(),
Headers: headers,
Endpoint: endpointURL,
Endpoint: cfg.endpointURL,
}

otlpConfig := &otlpexporter.Config{
Expand All @@ -140,6 +124,9 @@ func (cfg *Config) OTLPConfig() (*otlpexporter.Config, error) {
ClientConfig: clientCfg,
}

// Disable TLS for testing.
otlpConfig.ClientConfig.TLSSetting.Insecure = cfg.insecure

if err := otlpConfig.Validate(); err != nil {
return nil, err
}
Expand Down
Loading
Loading