diff --git a/.chloggen/fix_default-http-exporter-behaviour.yaml b/.chloggen/fix_default-http-exporter-behaviour.yaml new file mode 100755 index 000000000000..e4ad992d059f --- /dev/null +++ b/.chloggen/fix_default-http-exporter-behaviour.yaml @@ -0,0 +1,29 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: telemetrygen + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: better defaults for http exporter mode + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [26999] + +# (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: | + - the url path default is now correct for both traces and metrics + - when not provided, the endpoint is automatically set to target a local gRPC or HTTP endpoint depending on the communication mode selected + +# 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] diff --git a/cmd/telemetrygen/config_test.go b/cmd/telemetrygen/config_test.go new file mode 100644 index 000000000000..3a67a0a6ed54 --- /dev/null +++ b/cmd/telemetrygen/config_test.go @@ -0,0 +1,25 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestConfig_HTTPPath verifies that the HTTPPath configuration defaults are correctly set for each sub-command. +func TestConfig_HTTPPath(t *testing.T) { + t.Run("LogsConfigEmptyDefaultUrlPath", func(t *testing.T) { + assert.Equal(t, "", logsCfg.HTTPPath) + }) + + t.Run("MetricsConfigValidDefaultUrlPath", func(t *testing.T) { + assert.Equal(t, "/v1/metrics", metricsCfg.HTTPPath) + }) + + t.Run("TracesConfigValidDefaultUrlPath", func(t *testing.T) { + assert.Equal(t, "/v1/traces", tracesCfg.HTTPPath) + }) +} diff --git a/cmd/telemetrygen/internal/common/config.go b/cmd/telemetrygen/internal/common/config.go index e542f4b79d66..8ec9a8acfac2 100644 --- a/cmd/telemetrygen/internal/common/config.go +++ b/cmd/telemetrygen/internal/common/config.go @@ -17,6 +17,11 @@ var ( errDoubleQuotesOTLPAttributes = fmt.Errorf("value should be a string wrapped in double quotes") ) +const ( + defaultGRPCEndpoint = "localhost:4317" + defaultHTTPEndpoint = "localhost:4318" +) + type KeyValue map[string]string var _ pflag.Value = (*KeyValue)(nil) @@ -51,7 +56,7 @@ type Config struct { SkipSettingGRPCLogger bool // OTLP config - Endpoint string + CustomEndpoint string Insecure bool UseHTTP bool HTTPPath string @@ -60,6 +65,18 @@ type Config struct { TelemetryAttributes KeyValue } +// Endpoint returns the appropriate endpoint URL based on the selected communication mode (gRPC or HTTP) +// or custom endpoint provided in the configuration. +func (c *Config) Endpoint() string { + if c.CustomEndpoint != "" { + return c.CustomEndpoint + } + if c.UseHTTP { + return defaultHTTPEndpoint + } + return defaultGRPCEndpoint +} + func (c *Config) GetAttributes() []attribute.KeyValue { var attributes []attribute.KeyValue @@ -87,12 +104,11 @@ func (c *Config) CommonFlags(fs *pflag.FlagSet) { fs.IntVar(&c.WorkerCount, "workers", 1, "Number of workers (goroutines) to run") fs.Int64Var(&c.Rate, "rate", 0, "Approximately how many metrics per second each worker should generate. Zero means no throttling.") fs.DurationVar(&c.TotalDuration, "duration", 0, "For how long to run the test") - fs.DurationVar(&c.ReportingInterval, "interval", 1*time.Second, "Reporting interval (default 1 second)") + fs.DurationVar(&c.ReportingInterval, "interval", 1*time.Second, "Reporting interval") - fs.StringVar(&c.Endpoint, "otlp-endpoint", "localhost:4317", "Target to which the exporter is going to send metrics.") + fs.StringVar(&c.CustomEndpoint, "otlp-endpoint", "", "Destination endpoint for exporting logs, metrics and traces") fs.BoolVar(&c.Insecure, "otlp-insecure", false, "Whether to enable client transport security for the exporter's grpc or http connection") fs.BoolVar(&c.UseHTTP, "otlp-http", false, "Whether to use HTTP exporter rather than a gRPC one") - fs.StringVar(&c.HTTPPath, "otlp-http-url-path", "/v1/metrics", "Which URL path to write to (default /v1/metrics)") // custom headers c.Headers = make(map[string]string) diff --git a/cmd/telemetrygen/internal/common/config_test.go b/cmd/telemetrygen/internal/common/config_test.go index c2e8bd43cb02..ebdcd0af6a78 100644 --- a/cmd/telemetrygen/internal/common/config_test.go +++ b/cmd/telemetrygen/internal/common/config_test.go @@ -49,3 +49,54 @@ func TestKeyValueSet(t *testing.T) { }) } } + +func TestEndpoint(t *testing.T) { + tests := []struct { + name string + endpoint string + http bool + expected string + }{ + { + "default-no-http", + "", + false, + defaultGRPCEndpoint, + }, + { + "default-with-http", + "", + true, + defaultHTTPEndpoint, + }, + { + "custom-endpoint-no-http", + "collector:4317", + false, + "collector:4317", + }, + { + "custom-endpoint-with-http", + "collector:4317", + true, + "collector:4317", + }, + { + "wrong-custom-endpoint-with-http", + defaultGRPCEndpoint, + true, + defaultGRPCEndpoint, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + cfg := &Config{ + CustomEndpoint: tc.endpoint, + UseHTTP: tc.http, + } + + assert.Equal(t, tc.expected, cfg.Endpoint()) + }) + } +} diff --git a/cmd/telemetrygen/internal/logs/logs.go b/cmd/telemetrygen/internal/logs/logs.go index 2b82bcfa47f7..777fd26bbcf0 100644 --- a/cmd/telemetrygen/internal/logs/logs.go +++ b/cmd/telemetrygen/internal/logs/logs.go @@ -54,7 +54,7 @@ func Start(cfg *Config) error { } // only support grpc in insecure mode - clientConn, err := grpc.DialContext(context.TODO(), cfg.Endpoint, grpc.WithTransportCredentials(insecure.NewCredentials())) + clientConn, err := grpc.DialContext(context.TODO(), cfg.Endpoint(), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { return err } diff --git a/cmd/telemetrygen/internal/metrics/config.go b/cmd/telemetrygen/internal/metrics/config.go index 44bb4ef98aae..8f5e6ec78e91 100644 --- a/cmd/telemetrygen/internal/metrics/config.go +++ b/cmd/telemetrygen/internal/metrics/config.go @@ -22,6 +22,9 @@ func (c *Config) Flags(fs *pflag.FlagSet) { c.MetricType = metricTypeGauge c.CommonFlags(fs) + + fs.StringVar(&c.HTTPPath, "otlp-http-url-path", "/v1/metrics", "Which URL path to write to") + fs.Var(&c.MetricType, "metric-type", "Metric type enum. must be one of 'Gauge' or 'Sum'") fs.IntVar(&c.NumMetrics, "metrics", 1, "Number of metrics to generate in each worker (ignored if duration is provided)") } diff --git a/cmd/telemetrygen/internal/metrics/exporter.go b/cmd/telemetrygen/internal/metrics/exporter.go new file mode 100644 index 000000000000..d320e292447c --- /dev/null +++ b/cmd/telemetrygen/internal/metrics/exporter.go @@ -0,0 +1,50 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package metrics + +import ( + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" + "google.golang.org/grpc" +) + +// grpcExporterOptions creates the configuration options for a gRPC-based OTLP metric exporter. +// It configures the exporter with the provided endpoint, connection security settings, and headers. +func grpcExporterOptions(cfg *Config) []otlpmetricgrpc.Option { + grpcExpOpt := []otlpmetricgrpc.Option{ + otlpmetricgrpc.WithEndpoint(cfg.Endpoint()), + otlpmetricgrpc.WithDialOption( + grpc.WithBlock(), + ), + } + + if cfg.Insecure { + grpcExpOpt = append(grpcExpOpt, otlpmetricgrpc.WithInsecure()) + } + + if len(cfg.Headers) > 0 { + grpcExpOpt = append(grpcExpOpt, otlpmetricgrpc.WithHeaders(cfg.Headers)) + } + + return grpcExpOpt +} + +// httpExporterOptions creates the configuration options for an HTTP-based OTLP metric exporter. +// It configures the exporter with the provided endpoint, URL path, connection security settings, and headers. +func httpExporterOptions(cfg *Config) []otlpmetrichttp.Option { + httpExpOpt := []otlpmetrichttp.Option{ + otlpmetrichttp.WithEndpoint(cfg.Endpoint()), + otlpmetrichttp.WithURLPath(cfg.HTTPPath), + } + + if cfg.Insecure { + httpExpOpt = append(httpExpOpt, otlpmetrichttp.WithInsecure()) + } + + if len(cfg.Headers) > 0 { + httpExpOpt = append(httpExpOpt, otlpmetrichttp.WithHeaders(cfg.Headers)) + } + + return httpExpOpt +} diff --git a/cmd/telemetrygen/internal/metrics/metrics.go b/cmd/telemetrygen/internal/metrics/metrics.go index 3567e6d54d24..a67271715f43 100644 --- a/cmd/telemetrygen/internal/metrics/metrics.go +++ b/cmd/telemetrygen/internal/metrics/metrics.go @@ -17,7 +17,6 @@ import ( "go.opentelemetry.io/otel/sdk/resource" "go.uber.org/zap" "golang.org/x/time/rate" - "google.golang.org/grpc" "github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen/internal/common" ) @@ -30,35 +29,13 @@ func Start(cfg *Config) error { } logger.Info("starting the metrics generator with configuration", zap.Any("config", cfg)) - grpcExpOpt := []otlpmetricgrpc.Option{ - otlpmetricgrpc.WithEndpoint(cfg.Endpoint), - otlpmetricgrpc.WithDialOption( - grpc.WithBlock(), - ), - } - - httpExpOpt := []otlpmetrichttp.Option{ - otlpmetrichttp.WithEndpoint(cfg.Endpoint), - otlpmetrichttp.WithURLPath(cfg.HTTPPath), - } - - if cfg.Insecure { - grpcExpOpt = append(grpcExpOpt, otlpmetricgrpc.WithInsecure()) - httpExpOpt = append(httpExpOpt, otlpmetrichttp.WithInsecure()) - } - - if len(cfg.Headers) > 0 { - grpcExpOpt = append(grpcExpOpt, otlpmetricgrpc.WithHeaders(cfg.Headers)) - httpExpOpt = append(httpExpOpt, otlpmetrichttp.WithHeaders(cfg.Headers)) - } - var exp sdkmetric.Exporter if cfg.UseHTTP { logger.Info("starting HTTP exporter") - exp, err = otlpmetrichttp.New(context.Background(), httpExpOpt...) + exp, err = otlpmetrichttp.New(context.Background(), httpExporterOptions(cfg)...) } else { logger.Info("starting gRPC exporter") - exp, err = otlpmetricgrpc.New(context.Background(), grpcExpOpt...) + exp, err = otlpmetricgrpc.New(context.Background(), grpcExporterOptions(cfg)...) } if err != nil { diff --git a/cmd/telemetrygen/internal/traces/config.go b/cmd/telemetrygen/internal/traces/config.go index 2ffb44fcc3cb..e8d41270d5f4 100644 --- a/cmd/telemetrygen/internal/traces/config.go +++ b/cmd/telemetrygen/internal/traces/config.go @@ -23,6 +23,9 @@ type Config struct { // Flags registers config flags. func (c *Config) Flags(fs *pflag.FlagSet) { c.CommonFlags(fs) + + fs.StringVar(&c.HTTPPath, "otlp-http-url-path", "/v1/traces", "Which URL path to write to") + fs.IntVar(&c.NumTraces, "traces", 1, "Number of traces to generate in each worker (ignored if duration is provided)") fs.BoolVar(&c.PropagateContext, "marshal", false, "Whether to marshal trace context via HTTP headers") fs.StringVar(&c.ServiceName, "service", "telemetrygen", "Service name to use") diff --git a/cmd/telemetrygen/internal/traces/exporter.go b/cmd/telemetrygen/internal/traces/exporter.go new file mode 100644 index 000000000000..4161ccc3d1f1 --- /dev/null +++ b/cmd/telemetrygen/internal/traces/exporter.go @@ -0,0 +1,50 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package traces + +import ( + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "google.golang.org/grpc" +) + +// grpcExporterOptions creates the configuration options for a gRPC-based OTLP trace exporter. +// It configures the exporter with the provided endpoint, connection security settings, and headers. +func grpcExporterOptions(cfg *Config) []otlptracegrpc.Option { + grpcExpOpt := []otlptracegrpc.Option{ + otlptracegrpc.WithEndpoint(cfg.Endpoint()), + otlptracegrpc.WithDialOption( + grpc.WithBlock(), + ), + } + + if cfg.Insecure { + grpcExpOpt = append(grpcExpOpt, otlptracegrpc.WithInsecure()) + } + + if len(cfg.Headers) > 0 { + grpcExpOpt = append(grpcExpOpt, otlptracegrpc.WithHeaders(cfg.Headers)) + } + + return grpcExpOpt +} + +// httpExporterOptions creates the configuration options for an HTTP-based OTLP trace exporter. +// It configures the exporter with the provided endpoint, URL path, connection security settings, and headers. +func httpExporterOptions(cfg *Config) []otlptracehttp.Option { + httpExpOpt := []otlptracehttp.Option{ + otlptracehttp.WithEndpoint(cfg.Endpoint()), + otlptracehttp.WithURLPath(cfg.HTTPPath), + } + + if cfg.Insecure { + httpExpOpt = append(httpExpOpt, otlptracehttp.WithInsecure()) + } + + if len(cfg.Headers) > 0 { + httpExpOpt = append(httpExpOpt, otlptracehttp.WithHeaders(cfg.Headers)) + } + + return httpExpOpt +} diff --git a/cmd/telemetrygen/internal/traces/traces.go b/cmd/telemetrygen/internal/traces/traces.go index be772cb85030..a1136a25ee4c 100644 --- a/cmd/telemetrygen/internal/traces/traces.go +++ b/cmd/telemetrygen/internal/traces/traces.go @@ -22,7 +22,6 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.4.0" "go.uber.org/zap" "golang.org/x/time/rate" - "google.golang.org/grpc" "github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen/internal/common" ) @@ -33,35 +32,13 @@ func Start(cfg *Config) error { return err } - grpcExpOpt := []otlptracegrpc.Option{ - otlptracegrpc.WithEndpoint(cfg.Endpoint), - otlptracegrpc.WithDialOption( - grpc.WithBlock(), - ), - } - - httpExpOpt := []otlptracehttp.Option{ - otlptracehttp.WithEndpoint(cfg.Endpoint), - otlptracehttp.WithURLPath(cfg.HTTPPath), - } - - if cfg.Insecure { - grpcExpOpt = append(grpcExpOpt, otlptracegrpc.WithInsecure()) - httpExpOpt = append(httpExpOpt, otlptracehttp.WithInsecure()) - } - - if len(cfg.Headers) > 0 { - grpcExpOpt = append(grpcExpOpt, otlptracegrpc.WithHeaders(cfg.Headers)) - httpExpOpt = append(httpExpOpt, otlptracehttp.WithHeaders(cfg.Headers)) - } - var exp *otlptrace.Exporter if cfg.UseHTTP { logger.Info("starting HTTP exporter") - exp, err = otlptracehttp.New(context.Background(), httpExpOpt...) + exp, err = otlptracehttp.New(context.Background(), httpExporterOptions(cfg)...) } else { logger.Info("starting gRPC exporter") - exp, err = otlptracegrpc.New(context.Background(), grpcExpOpt...) + exp, err = otlptracegrpc.New(context.Background(), grpcExporterOptions(cfg)...) } if err != nil { diff --git a/cmd/telemetrygen/main_test.go b/cmd/telemetrygen/main_test.go index ee87a7e9e3a4..05008672fa43 100644 --- a/cmd/telemetrygen/main_test.go +++ b/cmd/telemetrygen/main_test.go @@ -38,7 +38,7 @@ func TestGenerateTraces(t *testing.T) { Rate: 10, TotalDuration: 10 * time.Second, ReportingInterval: 10, - Endpoint: endpoint, + CustomEndpoint: endpoint, Insecure: true, UseHTTP: false, Headers: nil,