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

[exporter/sumologicexporter]: adds support for tracing #33021

Merged
merged 6 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 27 additions & 0 deletions .chloggen/drosiek-tracing.yaml
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: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: sumologicexporter

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: add support for tracing

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [32315]

# (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]
6 changes: 4 additions & 2 deletions exporter/sumologicexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<!-- status autogenerated section -->
| Status | |
| ------------- |-----------|
| Stability | [beta]: metrics, logs |
| Stability | [beta]: metrics, logs, traces |
| Distributions | [contrib] |
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aexporter%2Fsumologic%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aexporter%2Fsumologic) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aexporter%2Fsumologic%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aexporter%2Fsumologic) |
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@aboguszewski-sumo](https://www.github.com/aboguszewski-sumo), [@kkujawa-sumo](https://www.github.com/kkujawa-sumo), [@mat-rumian](https://www.github.com/mat-rumian), [@rnishtala-sumo](https://www.github.com/rnishtala-sumo), [@sumo-drosiek](https://www.github.com/sumo-drosiek), [@swiatekm-sumo](https://www.github.com/swiatekm-sumo) |
Expand Down Expand Up @@ -86,6 +86,8 @@ exporters:
max_request_body_size: <max_request_body_size>

# format to use when sending logs to Sumo Logic, default = otlp,
# see Sumo Logic documentation for details regarding log formats:
# https://help.sumologic.com/docs/send-data/opentelemetry-collector/data-source-configurations/mapping-records-resources/
log_format: {otlp, json, text}

# format to use when sending metrics to Sumo Logic, default = otlp,
Expand All @@ -99,7 +101,7 @@ exporters:
decompose_otlp_histograms: {true, false}

# timeout is the timeout for every attempt to send data to the backend,
# maximum connection timeout is 55s, default = 5s
# maximum connection timeout is 55s, default = 30s
Copy link
Member

Choose a reason for hiding this comment

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

Is this maximum connection timeout ever enforced or tested? It's unrelated to this PR, so no need to do anything now, just something to consider if it's not currently enforced.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think we test it
Created issue so we can keep track of it: #33151

timeout: <timeout>

# defines if sticky session support is enable.
Expand Down
66 changes: 42 additions & 24 deletions exporter/sumologicexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ type Config struct {
// Format to post logs into Sumo. (default json)
// * text - Logs will appear in Sumo Logic in text format.
// * json - Logs will appear in Sumo Logic in json format.
// * otlp - Logs will be send in otlp format and will appear in Sumo Logic:
// * in json format if record level attributes exists
// * in text format in case of no level attributes
// See Sumo Logic documentation for more details:
// https://help.sumologic.com/docs/send-data/opentelemetry-collector/data-source-configurations/mapping-records-resources/
LogFormat LogFormatType `mapstructure:"log_format"`

// Metrics related configuration
Expand All @@ -46,6 +51,7 @@ type Config struct {
// Decompose OTLP Histograms into individual metrics, similar to how they're represented in Prometheus format
DecomposeOtlpHistograms bool `mapstructure:"decompose_otlp_histograms"`

// Sumo specific options
// Name of the client
Client string `mapstructure:"client"`

Expand All @@ -66,6 +72,30 @@ func createDefaultClientConfig() confighttp.ClientConfig {
}

func (cfg *Config) Validate() error {

switch cfg.CompressEncoding {
case configcompression.TypeGzip:
case configcompression.TypeDeflate:
case NoCompression:

default:
return fmt.Errorf("invalid compression encoding type: %v", cfg.CompressEncoding)
}

switch cfg.ClientConfig.Compression {
case configcompression.TypeGzip:
case configcompression.TypeDeflate:
case configcompression.TypeZstd:
case NoCompression:

default:
return fmt.Errorf("invalid compression encoding type: %v", cfg.ClientConfig.Compression)
}

if cfg.CompressEncoding != NoCompression && cfg.ClientConfig.Compression != DefaultCompressEncoding {
return fmt.Errorf("compress_encoding is deprecated and should not be used when compression is set to a non-default value")
}

switch cfg.LogFormat {
case OTLPLogFormat:
case JSONFormat:
Expand All @@ -75,26 +105,16 @@ func (cfg *Config) Validate() error {
}

switch cfg.MetricFormat {
case OTLPMetricFormat:
case PrometheusFormat:
case RemovedGraphiteFormat:
return fmt.Errorf("support for the graphite metric format was removed, please use prometheus or otlp instead")
case RemovedCarbon2Format:
return fmt.Errorf("support for the carbon2 metric format was removed, please use prometheus or otlp instead")
case PrometheusFormat:
case OTLPMetricFormat:
default:
return fmt.Errorf("unexpected metric format: %s", cfg.MetricFormat)
}

switch cfg.ClientConfig.Compression {
case configcompression.TypeGzip:
case configcompression.TypeDeflate:
case configcompression.TypeZstd:
case NoCompression:

default:
return fmt.Errorf("invalid compression encoding type: %v", cfg.ClientConfig.Compression)
}

if len(cfg.ClientConfig.Endpoint) == 0 && cfg.ClientConfig.Auth == nil {
return errors.New("no endpoint and no auth extension specified")
}
Expand All @@ -118,35 +138,39 @@ type LogFormatType string
// MetricFormatType represents metric_format
type MetricFormatType string

// TraceFormatType represents trace_format
type TraceFormatType string

// PipelineType represents type of the pipeline
type PipelineType string

// CompressEncodingType represents type of the pipeline
type CompressEncodingType string

const (
// TextFormat represents log_format: text
TextFormat LogFormatType = "text"
// JSONFormat represents log_format: json
JSONFormat LogFormatType = "json"
// RemovedGraphiteFormat represents the no longer supported graphite metric format
// OTLPLogFormat represents log_format: otlp
OTLPLogFormat LogFormatType = "otlp"
// RemovedGraphiteFormat represents the no longer supported graphite metric format
RemovedGraphiteFormat MetricFormatType = "graphite"
// RemovedCarbon2Format represents the no longer supported carbon2 metric format
RemovedCarbon2Format MetricFormatType = "carbon2"
// GraphiteFormat represents metric_format: text
// PrometheusFormat represents metric_format: prometheus
PrometheusFormat MetricFormatType = "prometheus"
// OTLPMetricFormat represents metric_format: otlp
OTLPMetricFormat MetricFormatType = "otlp"
// OTLPTraceFormat represents trace_format: otlp
OTLPTraceFormat TraceFormatType = "otlp"
// NoCompression represents disabled compression
NoCompression configcompression.Type = ""
// MetricsPipeline represents metrics pipeline
MetricsPipeline PipelineType = "metrics"
// LogsPipeline represents metrics pipeline
LogsPipeline PipelineType = "logs"
// TracesPipeline represents traces pipeline
TracesPipeline PipelineType = "traces"
// defaultTimeout
defaultTimeout time.Duration = 5 * time.Second
defaultTimeout time.Duration = 30 * time.Second
sumo-drosiek marked this conversation as resolved.
Show resolved Hide resolved
// DefaultCompress defines default Compress
DefaultCompress bool = true
// DefaultCompressEncoding defines default CompressEncoding
Expand All @@ -157,12 +181,6 @@ const (
DefaultLogFormat LogFormatType = OTLPLogFormat
// DefaultMetricFormat defines default MetricFormat
DefaultMetricFormat MetricFormatType = OTLPMetricFormat
// DefaultSourceCategory defines default SourceCategory
DefaultSourceCategory string = ""
// DefaultSourceName defines default SourceName
DefaultSourceName string = ""
// DefaultSourceHost defines default SourceHost
DefaultSourceHost string = ""
// DefaultClient defines default Client
DefaultClient string = "otelcol"
// DefaultLogKey defines default LogKey value
Expand Down
14 changes: 1 addition & 13 deletions exporter/sumologicexporter/config_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

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

import (
"errors"
Expand Down Expand Up @@ -69,18 +69,6 @@ func TestInitExporterInvalidConfiguration(t *testing.T) {
},
},
},
{
name: "no endpoint and no auth extension specified",
expectedError: errors.New("no endpoint and no auth extension specified"),
cfg: &Config{
LogFormat: "json",
MetricFormat: "otlp",
ClientConfig: confighttp.ClientConfig{
Timeout: defaultTimeout,
Compression: "gzip",
},
},
},
}

for _, tc := range testcases {
Expand Down
43 changes: 43 additions & 0 deletions exporter/sumologicexporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/plog"
"go.opentelemetry.io/collector/pdata/pmetric"
"go.opentelemetry.io/collector/pdata/ptrace"
"go.uber.org/zap"

"github.com/open-telemetry/opentelemetry-collector-contrib/extension/sumologicextension"
Expand Down Expand Up @@ -120,6 +121,28 @@ func newMetricsExporter(
)
}

func newTracesExporter(
ctx context.Context,
params exporter.CreateSettings,
cfg *Config,
) (exporter.Traces, error) {
se := initExporter(cfg, params)

return exporterhelper.NewTracesExporter(
ctx,
params,
cfg,
se.pushTracesData,
// Disable exporterhelper Timeout, since we are using a custom mechanism
// within exporter itself
exporterhelper.WithTimeout(exporterhelper.TimeoutSettings{Timeout: 0}),
exporterhelper.WithRetry(cfg.BackOffConfig),
exporterhelper.WithQueue(cfg.QueueSettings),
exporterhelper.WithStart(se.start),
exporterhelper.WithShutdown(se.shutdown),
)
}

// start starts the exporter
func (se *sumologicexporter) start(ctx context.Context, host component.Host) (err error) {
se.host = host
Expand Down Expand Up @@ -374,6 +397,26 @@ func (se *sumologicexporter) handleUnauthorizedErrors(ctx context.Context, errs
}
}

func (se *sumologicexporter) pushTracesData(ctx context.Context, td ptrace.Traces) error {
logsURL, metricsURL, tracesURL := se.getDataURLs()
sdr := newSender(
sumo-drosiek marked this conversation as resolved.
Show resolved Hide resolved
se.logger,
se.config,
se.getHTTPClient(),
se.prometheusFormatter,
metricsURL,
logsURL,
tracesURL,
se.StickySessionCookie,
se.SetStickySessionCookie,
se.id,
)

err := sdr.sendTraces(ctx, td)
se.handleUnauthorizedErrors(ctx, err)
return err
}

func (se *sumologicexporter) StickySessionCookie() string {
if se.foundSumologicExtension {
return se.sumologicExtension.StickySessionCookie()
Expand Down
Loading