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

SC-20508 Add sematext exporter #2

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
7be09e3
Worked on metrics support
AkhigbeEromo Oct 3, 2024
56075f9
Fixed all otel-related issues
AkhigbeEromo Oct 4, 2024
6cad40b
Add region to sematextexporter config
AkhigbeEromo Oct 4, 2024
8ed1a5a
Rewrite test for config
AkhigbeEromo Oct 4, 2024
af5ba97
Add comments for the region
AkhigbeEromo Oct 4, 2024
6d2eff4
Fix linter issues
AkhigbeEromo Oct 4, 2024
929070f
Vaidate app_token and region
AkhigbeEromo Oct 5, 2024
f958e8f
Add sematext specifics for the metrics line
AkhigbeEromo Oct 7, 2024
abf2930
SC-20508 #comment Fix the timestamp issue but now the test is failing…
AkhigbeEromo Oct 8, 2024
bf6e81b
Fix the issue with the test to ensure metrics line are sent in semate…
AkhigbeEromo Oct 8, 2024
9d02ad7
Fix lint issues
AkhigbeEromo Oct 8, 2024
2146176
Delete logging for test
AkhigbeEromo Oct 8, 2024
6af2ce6
Merge remote-tracking branch 'origin' into add-sematext-exporter
boratanrikulu Oct 9, 2024
602ecbf
remove go.mod files
boratanrikulu Oct 9, 2024
0290804
fix new-line issue
boratanrikulu Oct 9, 2024
b4788ae
Update App_token to AppToken
AkhigbeEromo Oct 9, 2024
649215f
Clean up dirty code
AkhigbeEromo Oct 9, 2024
2e17dd5
Remove "influx" occurences
AkhigbeEromo Oct 9, 2024
e358f65
Remove unneccessary comments
AkhigbeEromo Oct 9, 2024
0cac0f9
Change writer_test function names to Pascal case
AkhigbeEromo Oct 15, 2024
89713a0
Remove unnecessary calculation
AkhigbeEromo Oct 15, 2024
be7f986
Put AppToken in a constant outside the function
AkhigbeEromo Oct 15, 2024
d8e5f14
Fix "No content" error
AkhigbeEromo Oct 16, 2024
c7fb729
Fix hostname issue
AkhigbeEromo Oct 16, 2024
daecc41
Make telegraf-prometheus-v2 default metrics schema
AkhigbeEromo Oct 22, 2024
683b038
Change schema from otel-v1 to telegraf-prometheus-v2
AkhigbeEromo Oct 23, 2024
a8346ed
Fix test because hostname changed
AkhigbeEromo Oct 23, 2024
02fec37
Reduce tags to 20 and make sure os.host and token tags are always pre…
AkhigbeEromo Oct 24, 2024
a85429a
Make os.host dynamic in test
AkhigbeEromo Oct 24, 2024
9317219
Add README file
Eromosele-SM Oct 25, 2024
1f32a87
Change endpoint to metrics receiver endpoint
Eromosele-SM Oct 25, 2024
8d81a7d
Region is now used to determine the endpoint
Eromosele-SM Oct 25, 2024
245725c
Edit README.md
Eromosele-SM Oct 28, 2024
eeb42af
Update README.md
Eromosele-SM Oct 28, 2024
5d17fd7
Refactor Exporter so that endpoints can be seperate
Eromosele-SM Oct 30, 2024
b4505b0
Refactor Exporter
Eromosele-SM Oct 30, 2024
98d51f4
Correct a comment
Eromosele-SM Oct 30, 2024
1c87f19
Update README.md
Eromosele-SM Oct 30, 2024
fcd0f90
Change defaults of payload
Eromosele-SM Oct 30, 2024
40581e7
Fix indentation issues
Eromosele-SM Nov 5, 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
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ body:
- exporter/pulsar
- exporter/rabbitmq
- exporter/sapm
- exporter/sematext
- exporter/sentry
- exporter/signalfx
- exporter/splunkhec
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ body:
- exporter/pulsar
- exporter/rabbitmq
- exporter/sapm
- exporter/sematext
- exporter/sentry
- exporter/signalfx
- exporter/splunkhec
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/other.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ body:
- exporter/pulsar
- exporter/rabbitmq
- exporter/sapm
- exporter/sematext
- exporter/sentry
- exporter/signalfx
- exporter/splunkhec
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/unmaintained.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ body:
- exporter/pulsar
- exporter/rabbitmq
- exporter/sapm
- exporter/sematext
- exporter/sentry
- exporter/signalfx
- exporter/splunkhec
Expand Down
1 change: 1 addition & 0 deletions exporter/sematextexporter/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../../Makefile.Common
47 changes: 47 additions & 0 deletions exporter/sematextexporter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Sematext Exporter
<!-- status autogenerated section -->
<!-- end autogenerated section -->

This exporter supports sending metrics to [Sematext Cloud](https://sematext.com/) in Influx line protocol format

## Configuration

The following configuration options are supported:
* `timeout` (default = 5s) Timeout for requests
Copy link
Member

Choose a reason for hiding this comment

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

@Eromosele-SM make it match STA timeout?

* `Region` Region specifies the Sematext region the user is operating in; must be one of:
Eromosele-SM marked this conversation as resolved.
Show resolved Hide resolved
* `US`
* `EU`
* `AppToken` App token specifies the token of Sematext Monitoring App to which the user wants to send data to.
Eromosele-SM marked this conversation as resolved.
Show resolved Hide resolved
* `payload_max_lines` (default = 1_000) Maximum number of lines allowed per HTTP POST request
* `payload_max_bytes` (default = 300_000) Maximum number of bytes allowed per HTTP POST request
* `metrics_schema` (default = telegraf-prometheus-v2) The chosen metrics schema to write
* `sending_queue` [details here](https://github.com/open-telemetry/opentelemetry-collector/blob/v0.25.0/exporter/exporterhelper/README.md#configuration)
* `enabled` (default = true)
* `num_consumers` (default = 10) The number of consumers from the queue
* `queue_size` (default = 1000) Maximum number of batches allowed in queue at a given time
* `retry_on_failure` [details here](https://github.com/open-telemetry/opentelemetry-collector/blob/v0.25.0/exporter/exporterhelper/README.md#configuration)
* `enabled` (default = true)
* `initial_interval` (default = 5s) Time to wait after the first failure before retrying
* `max_interval` (default = 30s) Upper bound on backoff interval
* `max_elapsed_time` (default = 120s) Maximum amount of time (including retries) spent trying to send a request/batch

The full list of settings exposed for this exporter are documented in [config.go](config.go).

Example:
```yaml
timeout: 500ms
region: US
retry_on_failure:
enabled: true
initial_interval: 1s
max_interval: 3s
max_elapsed_time: 10s
metrics:
app_token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
sending_queue:
enabled: true
num_consumers: 3
queue_size: 10
payload_max_lines: 100
payload_max_bytes: 1000
```
57 changes: 57 additions & 0 deletions exporter/sematextexporter/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package sematextexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sematextexporter"

Check failure on line 4 in exporter/sematextexporter/config.go

View workflow job for this annotation

GitHub Actions / govulncheck (exporter-3)

package requires newer Go version go1.23

import (
"fmt"
"strings"

"go.opentelemetry.io/collector/config/confighttp"
"go.opentelemetry.io/collector/config/configretry"
"go.opentelemetry.io/collector/exporter/exporterhelper"
)

type Config struct {
confighttp.ClientConfig `mapstructure:",squash"`
configretry.BackOffConfig `mapstructure:"retry_on_failure"`
// Region specifies the Sematext region the user is operating in
// Options:
// - EU
// - US
Region string `mapstructure:"region"`
Eromosele-SM marked this conversation as resolved.
Show resolved Hide resolved
MetricsConfig `mapstructure:"metrics"`
}

type MetricsConfig struct {
// App token is the token of Sematext Monitoring App to which you want to send the metrics.
AppToken string `mapstructure:"app_token"`
// MetricsEndpoint specifies the endpoint for receiving metrics in Sematext
Eromosele-SM marked this conversation as resolved.
Show resolved Hide resolved
MetricsEndpoint string `mapstructure:"metrics_endpoint"`
QueueSettings exporterhelper.QueueConfig `mapstructure:"sending_queue"`
// MetricsSchema indicates the metrics schema to emit to line protocol.
// Default: telegraf-prometheus-v2
MetricsSchema string `mapstructure:"metrics_schema"`
// PayloadMaxLines is the maximum number of line protocol lines to POST in a single request.
PayloadMaxLines int `mapstructure:"payload_max_lines"`
// PayloadMaxBytes is the maximum number of line protocol bytes to POST in a single request.
PayloadMaxBytes int `mapstructure:"payload_max_bytes"`
}

// Validate checks for invalid or missing entries in the configuration.
func (cfg *Config) Validate() error {
if strings.ToLower(cfg.Region) != "eu" && strings.ToLower(cfg.Region) != "us" && strings.ToLower(cfg.Region) != "custom"{
Copy link
Member

Choose a reason for hiding this comment

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

Still not sure what "custom" is for. Esp. since in the line below you say only US and EU are allowed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The custom is so that we can run tests on the exporter with a mockserver

return fmt.Errorf("invalid region: %s. please use either 'EU' or 'US'", cfg.Region)
}
if len(cfg.AppToken) != 36 {
return fmt.Errorf("invalid app_token: %s. app_token should be 36 characters", cfg.AppToken)
}
if strings.ToLower(cfg.Region) == "eu" {
cfg.MetricsEndpoint ="https://spm-receiver.eu.sematext.com"
}
if strings.ToLower(cfg.Region) == "us"{
cfg.MetricsEndpoint ="https://spm-receiver.sematext.com"
}

return nil
}
84 changes: 84 additions & 0 deletions exporter/sematextexporter/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package sematextexporter

import (
"path/filepath"
"testing"
"time"

"github.com/cenkalti/backoff/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"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/confmap/confmaptest"
"go.opentelemetry.io/collector/exporter/exporterhelper"

"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sematextexporter/internal/metadata"
)

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
}{
{
id: component.NewIDWithName(metadata.Type, "default-config"),
expected: createDefaultConfig(),
},
{
id: component.NewIDWithName(metadata.Type, "override-config"),
expected: &Config{
ClientConfig: confighttp.ClientConfig{
Timeout: 500 * time.Millisecond,
Headers: map[string]configopaque.String{"User-Agent": "OpenTelemetry -> Sematext"},
},
MetricsConfig: MetricsConfig{
MetricsEndpoint: "https://spm-receiver.sematext.com",
QueueSettings: exporterhelper.QueueConfig{
Enabled: true,
NumConsumers: 3,
QueueSize: 10,
},
AppToken: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
MetricsSchema: "telegraf-prometheus-v2",
PayloadMaxLines: 72,
PayloadMaxBytes: 27,
},

BackOffConfig: configretry.BackOffConfig{
Enabled: true,
InitialInterval: 1 * time.Second,
MaxInterval: 3 * time.Second,
MaxElapsedTime: 10 * time.Second,
RandomizationFactor: backoff.DefaultRandomizationFactor,
Multiplier: backoff.DefaultMultiplier,
},
Region: "US",
},
},
}

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)
})
}
}
7 changes: 7 additions & 0 deletions exporter/sematextexporter/doc.go
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 sematextexporter sends metrics to sematext cloud.
package sematextexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sematextexporter"
93 changes: 93 additions & 0 deletions exporter/sematextexporter/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

//go:generate mdatagen metadata.yaml

package sematextexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sematextexporter"

import (
"context"
"fmt"
"time"

"github.com/influxdata/influxdb-observability/otel2influx"
"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/exporter"
"go.opentelemetry.io/collector/exporter/exporterhelper"

"github.com/influxdata/influxdb-observability/common"

"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sematextexporter/internal/metadata"
)
const appToken string = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
// NewFactory creates a factory for the Sematext metrics exporter.
func NewFactory() exporter.Factory {
return exporter.NewFactory(
metadata.Type,
createDefaultConfig,
exporter.WithMetrics(createMetricsExporter, metadata.MetricsStability),
)
}

func createDefaultConfig() component.Config {
return &Config{
ClientConfig: confighttp.ClientConfig{
Timeout: 5 * time.Second,
Headers: map[string]configopaque.String{
"User-Agent": "OpenTelemetry -> Sematext",
},
},
MetricsConfig: MetricsConfig{
MetricsSchema: common.MetricsSchemaTelegrafPrometheusV2.String(),
AppToken: appToken,
QueueSettings: exporterhelper.NewDefaultQueueConfig(),
PayloadMaxLines: 1_000,
PayloadMaxBytes: 300_000,
},
BackOffConfig: configretry.NewDefaultBackOffConfig(),
Region: "custom",
}
}

func createMetricsExporter(
ctx context.Context,
set exporter.Settings,
config component.Config,
) (exporter.Metrics, error) {
cfg := config.(*Config)

// Initialize the logger for Sematext
logger := newZapSematextLogger(set.Logger)

// Create a writer for sending metrics to Sematext
writer, err := newSematextHTTPWriter(logger, cfg, set.TelemetrySettings)
if err != nil {
return nil, fmt.Errorf("failed to create Sematext HTTP writer: %w", err)
}
schema, found := common.MetricsSchemata[cfg.MetricsSchema]
if !found {
return nil, fmt.Errorf("schema '%s' not recognized", cfg.MetricsSchema)
}

expConfig := otel2influx.DefaultOtelMetricsToLineProtocolConfig()
expConfig.Logger = logger
expConfig.Writer = writer
expConfig.Schema = schema
exp, err := otel2influx.NewOtelMetricsToLineProtocol(expConfig)
if err != nil {
return nil, err
}

return exporterhelper.NewMetricsExporter(
ctx,
set,
cfg,
exp.WriteMetrics,
exporterhelper.WithQueue(cfg.QueueSettings),
exporterhelper.WithRetry(cfg.BackOffConfig),
exporterhelper.WithStart(writer.Start),
)
}
Loading
Loading