-
Notifications
You must be signed in to change notification settings - Fork 0
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
base: main
Are you sure you want to change the base?
Changes from all commits
7be09e3
56075f9
6cad40b
8ed1a5a
af5ba97
6d2eff4
929070f
f958e8f
abf2930
bf6e81b
9d02ad7
2146176
6af2ce6
602ecbf
0290804
b4788ae
649215f
2e17dd5
e358f65
0cac0f9
89713a0
be7f986
d8e5f14
c7fb729
daecc41
683b038
a8346ed
02fec37
a85429a
9317219
1f32a87
8d81a7d
245725c
eeb42af
5d17fd7
b4505b0
98d51f4
1c87f19
fcd0f90
40581e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include ../../Makefile.Common |
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 | ||
* `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` | ||
* `app_token` App token specifies the token of Sematext Monitoring App to which the user wants to send data to. | ||
* `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 | ||
``` |
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" | ||
|
||
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 | ||
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"{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
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 | ||
} |
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) | ||
}) | ||
} | ||
} |
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" |
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), | ||
) | ||
} |
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.
@Eromosele-SM make it match STA timeout?