diff --git a/CHANGELOG.md b/CHANGELOG.md index a8fbbee9a00..e387a39d46a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Remove unused logstest package (#3222) - Introduce `AppSettings` instead of `Parameters` (#3163) - Rename `configtest.LoadConfigFile` to `configtest.LoadConfigAndValidate` (#3306) +- Remove unused testutil.TempSocketName (#3291) - Move BigEndian helper functions in `tracetranslator` to an internal package.(#3298) ## 💡 Enhancements 💡 diff --git a/config/config.go b/config/config.go index 1e9452b3948..99ac6fb383c 100644 --- a/config/config.go +++ b/config/config.go @@ -12,26 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package config defines the data models for entities. This file defines the -// models for configuration format. The defined entities are: -// Config (the top-level structure), Receivers, Exporters, Processors, Pipelines. -// -// Receivers, Exporters and Processors typically have common configuration settings, however -// sometimes specific implementations will have extra configuration settings. -// This requires the configuration data for these entities to be polymorphic. -// -// To satisfy these requirements we declare interfaces Receiver, Exporter, Processor, -// which define the behavior. We also provide helper structs ReceiverSettings, ExporterSettings, -// ProcessorSettings, which define the common settings and un-marshaling from config files. -// -// Specific Receivers/Exporters/Processors are expected to at the minimum implement the -// corresponding interface and if they have additional settings they must also extend -// the corresponding common settings struct (the easiest approach is to embed the common struct). package config import ( "errors" "fmt" + + "go.opentelemetry.io/collector/config/configparser" ) var ( @@ -97,7 +84,7 @@ func (cfg *Config) Validate() error { } } - // Check that all enabled extensions in the service are configured + // Check that all enabled extensions in the service are configured. if err := cfg.validateServiceExtensions(); err != nil { return err } @@ -110,7 +97,7 @@ func (cfg *Config) Validate() error { func (cfg *Config) validateServiceExtensions() error { // Validate extensions. for _, ref := range cfg.Service.Extensions { - // Check that the name referenced in the Service extensions exists in the top-level extensions + // Check that the name referenced in the Service extensions exists in the top-level extensions. if cfg.Extensions[ref] == nil { return fmt.Errorf("service references extension %q which does not exist", ref) } @@ -134,13 +121,13 @@ func (cfg *Config) validateServicePipelines() error { // Validate pipeline receiver name references. for _, ref := range pipeline.Receivers { - // Check that the name referenced in the pipeline's receivers exists in the top-level receivers + // Check that the name referenced in the pipeline's receivers exists in the top-level receivers. if cfg.Receivers[ref] == nil { return fmt.Errorf("pipeline %q references receiver %q which does not exist", pipeline.Name, ref) } } - // Validate pipeline processor name references + // Validate pipeline processor name references. for _, ref := range pipeline.Processors { // Check that the name referenced in the pipeline's processors exists in the top-level processors. if cfg.Processors[ref] == nil { @@ -148,14 +135,14 @@ func (cfg *Config) validateServicePipelines() error { } } - // Validate pipeline has at least one exporter + // Validate pipeline has at least one exporter. if len(pipeline.Exporters) == 0 { return fmt.Errorf("pipeline %q must have at least one exporter", pipeline.Name) } // Validate pipeline exporter name references. for _, ref := range pipeline.Exporters { - // Check that the name referenced in the pipeline's Exporters exists in the top-level Exporters + // Check that the name referenced in the pipeline's Exporters exists in the top-level Exporters. if cfg.Exporters[ref] == nil { return fmt.Errorf("pipeline %q references exporter %q which does not exist", pipeline.Name, ref) } @@ -166,10 +153,10 @@ func (cfg *Config) validateServicePipelines() error { // Service defines the configurable components of the service. type Service struct { - // Extensions is the ordered list of extensions configured for the service. + // Extensions are the ordered list of extensions configured for the service. Extensions []ComponentID - // Pipelines is the set of data pipelines configured for the service. + // Pipelines are the set of data pipelines configured for the service. Pipelines Pipelines } @@ -188,7 +175,7 @@ type CustomUnmarshable interface { // Unmarshal is a function that un-marshals a Parser into the unmarshable struct in a custom way. // componentSection *Parser // The config for this specific component. May be nil or empty if no config available. - Unmarshal(componentSection *Parser) error + Unmarshal(componentSection *configparser.Parser) error } // DataType is the data type that is supported for collection. We currently support diff --git a/config/configauth/configauth.go b/config/configauth/configauth.go index 799de2a8111..fe023963504 100644 --- a/config/configauth/configauth.go +++ b/config/configauth/configauth.go @@ -27,13 +27,13 @@ var ( errAuthenticatorNotProvided = errors.New("authenticator not provided") ) -// Authentication defines the auth settings for the receiver +// Authentication defines the auth settings for the receiver. type Authentication struct { // Authenticator specifies the name of the extension to use in order to authenticate the incoming data point. AuthenticatorName string `mapstructure:"authenticator"` } -// GetAuthenticator attempts to select the appropriate from the list of extensions, based on the requested extension name. +// GetAuthenticator attempts to select the appropriate Authenticator from the list of extensions, based on the requested extension name. // If an authenticator is not found, an error is returned. func GetAuthenticator(extensions map[config.ComponentID]component.Extension, requested string) (Authenticator, error) { if requested == "" { diff --git a/config/configauth/doc.go b/config/configauth/doc.go new file mode 100644 index 00000000000..169a504122e --- /dev/null +++ b/config/configauth/doc.go @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package configauth implements the configuration settings to +// ensure authentication on incoming requests, and allows +// exporters to add authentication on outgoing requests. +package configauth diff --git a/config/configcheck/configcheck.go b/config/configcheck/configcheck.go index 3a507a2062b..0b8c16b2167 100644 --- a/config/configcheck/configcheck.go +++ b/config/configcheck/configcheck.go @@ -12,10 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package configcheck has checks to be applied to configuration -// objects implemented by factories of components used in the OpenTelemetry -// collector. It is recommended for implementers of components to run the -// validations available on this package. package configcheck import ( @@ -167,7 +163,7 @@ func checkStructFieldTags(f reflect.StructField) error { switch f.Type.Kind() { case reflect.Struct: - // It is another struct, continue down-level + // It is another struct, continue down-level. return validateConfigDataType(f.Type) case reflect.Map, reflect.Slice, reflect.Array: diff --git a/config/configcheck/doc.go b/config/configcheck/doc.go new file mode 100644 index 00000000000..82ec0712afe --- /dev/null +++ b/config/configcheck/doc.go @@ -0,0 +1,19 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package configcheck has checks to be applied to configuration +// objects implemented by factories of components used in the OpenTelemetry +// collector. It is recommended for implementers of components to run the +// validations available on this package. +package configcheck diff --git a/config/configgrpc/configgrpc.go b/config/configgrpc/configgrpc.go index 6577cd7c8a2..00d6897fabc 100644 --- a/config/configgrpc/configgrpc.go +++ b/config/configgrpc/configgrpc.go @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package configgrpc defines the gRPC configuration settings. package configgrpc import ( @@ -34,7 +33,7 @@ import ( "go.opentelemetry.io/collector/config/configtls" ) -// Compression gRPC keys for supported compression types within collector +// Compression gRPC keys for supported compression types within collector. const ( CompressionUnsupported = "" CompressionGzip = "gzip" @@ -43,13 +42,13 @@ const ( ) var ( - // Map of opentelemetry compression types to grpc registered compression types + // Map of opentelemetry compression types to grpc registered compression types. grpcCompressionKeyMap = map[string]string{ CompressionGzip: gzip.Name, } ) -// Allowed balancer names to be set in grpclb_policy to discover the servers +// Allowed balancer names to be set in grpclb_policy to discover the servers. var allowedBalancerNames = []string{roundrobin.Name, grpc.PickFirstBalancerName} // KeepaliveClientConfig exposes the keepalive.ClientParameters to be used by the exporter. @@ -75,15 +74,15 @@ type GRPCClientSettings struct { // TLSSetting struct exposes TLS client configuration. TLSSetting configtls.TLSClientSetting `mapstructure:",squash"` - // The keepalive parameters for gRPC client. See grpc.WithKeepaliveParams + // The keepalive parameters for gRPC client. See grpc.WithKeepaliveParams. // (https://godoc.org/google.golang.org/grpc#WithKeepaliveParams). Keepalive *KeepaliveClientConfig `mapstructure:"keepalive"` - // ReadBufferSize for gRPC client. See grpc.WithReadBufferSize + // ReadBufferSize for gRPC client. See grpc.WithReadBufferSize. // (https://godoc.org/google.golang.org/grpc#WithReadBufferSize). ReadBufferSize int `mapstructure:"read_buffer_size"` - // WriteBufferSize for gRPC gRPC. See grpc.WithWriteBufferSize + // WriteBufferSize for gRPC gRPC. See grpc.WithWriteBufferSize. // (https://godoc.org/google.golang.org/grpc#WithWriteBufferSize). WriteBufferSize int `mapstructure:"write_buffer_size"` @@ -97,7 +96,7 @@ type GRPCClientSettings struct { // PerRPCAuth parameter configures the client to send authentication data on a per-RPC basis. PerRPCAuth *PerRPCAuthConfig `mapstructure:"per_rpc_auth"` - // Sets the balancer in grpclb_policy to discover the servers. Default is pick_first + // Sets the balancer in grpclb_policy to discover the servers. Default is pick_first. // https://github.com/grpc/grpc-go/blob/master/examples/features/load_balancing/README.md BalancerName string `mapstructure:"balancer_name"` } @@ -152,11 +151,11 @@ type GRPCServerSettings struct { // It has effect only for streaming RPCs. MaxConcurrentStreams uint32 `mapstructure:"max_concurrent_streams"` - // ReadBufferSize for gRPC server. See grpc.ReadBufferSize + // ReadBufferSize for gRPC server. See grpc.ReadBufferSize. // (https://godoc.org/google.golang.org/grpc#ReadBufferSize). ReadBufferSize int `mapstructure:"read_buffer_size"` - // WriteBufferSize for gRPC server. See grpc.WriteBufferSize + // WriteBufferSize for gRPC server. See grpc.WriteBufferSize. // (https://godoc.org/google.golang.org/grpc#WriteBufferSize). WriteBufferSize int `mapstructure:"write_buffer_size"` @@ -167,7 +166,7 @@ type GRPCServerSettings struct { Auth *configauth.Authentication `mapstructure:"auth,omitempty"` } -// ToDialOptions maps configgrpc.GRPCClientSettings to a slice of dial options for gRPC +// ToDialOptions maps configgrpc.GRPCClientSettings to a slice of dial options for gRPC. func (gcs *GRPCClientSettings) ToDialOptions() ([]grpc.DialOption, error) { var opts []grpc.DialOption if gcs.Compression != "" { @@ -240,7 +239,7 @@ func (gss *GRPCServerSettings) ToListener() (net.Listener, error) { return gss.NetAddr.Listen() } -// ToServerOption maps configgrpc.GRPCServerSettings to a slice of server options for gRPC +// ToServerOption maps configgrpc.GRPCServerSettings to a slice of server options for gRPC. func (gss *GRPCServerSettings) ToServerOption(ext map[config.ComponentID]component.Extension) ([]grpc.ServerOption, error) { var opts []grpc.ServerOption @@ -312,7 +311,7 @@ func (gss *GRPCServerSettings) ToServerOption(ext map[config.ComponentID]compone } // GetGRPCCompressionKey returns the grpc registered compression key if the -// passed in compression key is supported, and CompressionUnsupported otherwise +// passed in compression key is supported, and CompressionUnsupported otherwise. func GetGRPCCompressionKey(compressionType string) string { compressionKey := strings.ToLower(compressionType) if encodingKey, ok := grpcCompressionKeyMap[compressionKey]; ok { diff --git a/config/configgrpc/configgrpc_test.go b/config/configgrpc/configgrpc_test.go index fa54b135559..bcab6164f36 100644 --- a/config/configgrpc/configgrpc_test.go +++ b/config/configgrpc/configgrpc_test.go @@ -16,6 +16,8 @@ package configgrpc import ( "context" + "io/ioutil" + "os" "path" "runtime" "testing" @@ -31,7 +33,6 @@ import ( "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configtls" otelcol "go.opentelemetry.io/collector/internal/data/protogen/collector/trace/v1" - "go.opentelemetry.io/collector/testutil" ) func TestDefaultGrpcClientSettings(t *testing.T) { @@ -453,7 +454,7 @@ func TestReceiveOnUnixDomainSocket(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping test on windows") } - socketName := testutil.TempSocketName(t) + socketName := tempSocketName(t) gss := &GRPCServerSettings{ NetAddr: confignet.NetAddr{ Endpoint: socketName, @@ -525,3 +526,13 @@ func TestWithPerRPCAuthInvalidAuthType(t *testing.T) { assert.Error(t, err) assert.Nil(t, dialOpts) } + +// tempSocketName provides a temporary Unix socket name for testing. +func tempSocketName(t *testing.T) string { + tmpfile, err := ioutil.TempFile("", "sock") + require.NoError(t, err) + require.NoError(t, tmpfile.Close()) + socket := tmpfile.Name() + require.NoError(t, os.Remove(socket)) + return socket +} diff --git a/config/configgrpc/doc.go b/config/configgrpc/doc.go new file mode 100644 index 00000000000..04a7330b359 --- /dev/null +++ b/config/configgrpc/doc.go @@ -0,0 +1,17 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package configgrpc defines the configuration settings to create +// a gRPC client and server. +package configgrpc diff --git a/config/configgrpc/gzip.go b/config/configgrpc/gzip.go index 68f9d98617e..a6f64286ddc 100644 --- a/config/configgrpc/gzip.go +++ b/config/configgrpc/gzip.go @@ -15,6 +15,6 @@ package configgrpc import ( - // import the gzip package with auto-registers the gzip grpc compressor + // Import the gzip package which auto-registers the gzip gRPC compressor. _ "google.golang.org/grpc/encoding/gzip" ) diff --git a/config/confighttp/confighttp.go b/config/confighttp/confighttp.go index 8bdd45315fe..4ce306106ed 100644 --- a/config/confighttp/confighttp.go +++ b/config/confighttp/confighttp.go @@ -89,7 +89,7 @@ func (hcs *HTTPClientSettings) ToClient() (*http.Client, error) { }, nil } -// Custom RoundTripper that add headers +// Custom RoundTripper that add headers. type headerRoundTripper struct { transport http.RoundTripper headers map[string]string diff --git a/config/confighttp/doc.go b/config/confighttp/doc.go new file mode 100644 index 00000000000..377c2fa74b1 --- /dev/null +++ b/config/confighttp/doc.go @@ -0,0 +1,17 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package confighttp defines the configuration settings +// for creating an HTTP client and server. +package confighttp diff --git a/config/configloader/config.go b/config/configloader/config.go index 78e7a5e04e1..7e172096c3c 100644 --- a/config/configloader/config.go +++ b/config/configloader/config.go @@ -12,9 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package configloader implements configuration loading from a config.Parser. -// The implementation relies on registered factories that allow creating -// default configuration for each type of receiver/exporter/processor. package configloader import ( @@ -28,6 +25,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" ) // These are errors that can be returned by Load(). Note that error codes are not part @@ -35,7 +33,9 @@ import ( type configErrorCode int const ( - _ configErrorCode = iota // skip 0, start errors codes from 1. + // Skip 0, start errors codes from 1. + _ configErrorCode = iota + errInvalidTypeAndNameKey errUnknownType errDuplicateName @@ -43,15 +43,18 @@ const ( ) type configError struct { - msg string // human readable error message. - code configErrorCode // internal error code. + // Human readable error message. + msg string + + // Internal error code. + code configErrorCode } func (e *configError) Error() string { return e.msg } -// YAML top-level configuration keys +// YAML top-level configuration keys. const ( // extensionsKeyName is the configuration key name for extensions section. extensionsKeyName = "extensions" @@ -89,9 +92,8 @@ type pipelineSettings struct { } // Load loads a Config from Parser. -// After loading the config, need to check if it is valid by calling `ValidateConfig`. -func Load(v *config.Parser, factories component.Factories) (*config.Config, error) { - +// After loading the config, `Validate()` must be called to validate. +func Load(v *configparser.Parser, factories component.Factories) (*config.Config, error) { var cfg config.Config // Load the config. @@ -181,7 +183,7 @@ func loadExtensions(exts map[string]interface{}, factories map[config.Type]compo // Iterate over extensions and create a config for each. for key, value := range exts { - componentConfig := config.NewParserFromStringMap(cast.ToStringMap(value)) + componentConfig := configparser.NewParserFromStringMap(cast.ToStringMap(value)) expandEnvConfig(componentConfig) // Decode the key into type and fullName components. @@ -196,7 +198,7 @@ func loadExtensions(exts map[string]interface{}, factories map[config.Type]compo return nil, errorUnknownType(extensionsKeyName, id) } - // Create the default config for this extension + // Create the default config for this extension. extensionCfg := factory.CreateDefaultConfig() extensionCfg.SetIDName(id.Name()) expandEnvLoadedConfig(extensionCfg) @@ -238,7 +240,7 @@ func loadService(rawService serviceSettings) (config.Service, error) { } // LoadReceiver loads a receiver config from componentConfig using the provided factories. -func LoadReceiver(componentConfig *config.Parser, id config.ComponentID, factory component.ReceiverFactory) (config.Receiver, error) { +func LoadReceiver(componentConfig *configparser.Parser, id config.ComponentID, factory component.ReceiverFactory) (config.Receiver, error) { // Create the default config for this receiver. receiverCfg := factory.CreateDefaultConfig() receiverCfg.SetIDName(id.Name()) @@ -255,12 +257,12 @@ func LoadReceiver(componentConfig *config.Parser, id config.ComponentID, factory } func loadReceivers(recvs map[string]interface{}, factories map[config.Type]component.ReceiverFactory) (config.Receivers, error) { - // Prepare resulting map + // Prepare resulting map. receivers := make(config.Receivers) // Iterate over input map and create a config for each. for key, value := range recvs { - componentConfig := config.NewParserFromStringMap(cast.ToStringMap(value)) + componentConfig := configparser.NewParserFromStringMap(cast.ToStringMap(value)) expandEnvConfig(componentConfig) // Decode the key into type and fullName components. @@ -269,7 +271,7 @@ func loadReceivers(recvs map[string]interface{}, factories map[config.Type]compo return nil, errorInvalidTypeAndNameKey(receiversKeyName, key, err) } - // Find receiver factory based on "type" that we read from config source + // Find receiver factory based on "type" that we read from config source. factory := factories[id.Type()] if factory == nil { return nil, errorUnknownType(receiversKeyName, id) @@ -292,12 +294,12 @@ func loadReceivers(recvs map[string]interface{}, factories map[config.Type]compo } func loadExporters(exps map[string]interface{}, factories map[config.Type]component.ExporterFactory) (config.Exporters, error) { - // Prepare resulting map + // Prepare resulting map. exporters := make(config.Exporters) // Iterate over Exporters and create a config for each. for key, value := range exps { - componentConfig := config.NewParserFromStringMap(cast.ToStringMap(value)) + componentConfig := configparser.NewParserFromStringMap(cast.ToStringMap(value)) expandEnvConfig(componentConfig) // Decode the key into type and fullName components. @@ -306,13 +308,13 @@ func loadExporters(exps map[string]interface{}, factories map[config.Type]compon return nil, errorInvalidTypeAndNameKey(exportersKeyName, key, err) } - // Find exporter factory based on "type" that we read from config source + // Find exporter factory based on "type" that we read from config source. factory := factories[id.Type()] if factory == nil { return nil, errorUnknownType(exportersKeyName, id) } - // Create the default config for this exporter + // Create the default config for this exporter. exporterCfg := factory.CreateDefaultConfig() exporterCfg.SetIDName(id.Name()) expandEnvLoadedConfig(exporterCfg) @@ -340,7 +342,7 @@ func loadProcessors(procs map[string]interface{}, factories map[config.Type]comp // Iterate over processors and create a config for each. for key, value := range procs { - componentConfig := config.NewParserFromStringMap(cast.ToStringMap(value)) + componentConfig := configparser.NewParserFromStringMap(cast.ToStringMap(value)) expandEnvConfig(componentConfig) // Decode the key into type and fullName components. @@ -438,7 +440,7 @@ func parseIDNames(pipelineID config.ComponentID, componentType string, names []s // expandEnvConfig creates a new viper config with expanded values for all the values (simple, list or map value). // It does not expand the keys. -func expandEnvConfig(v *config.Parser) { +func expandEnvConfig(v *configparser.Parser) { for _, k := range v.AllKeys() { v.Set(k, expandStringValues(v.Get(k))) } @@ -477,27 +479,33 @@ func expandEnvLoadedConfigPointer(s interface{}) { if value.Kind() != reflect.Ptr { return } - // Run expandLoadedConfigValue on the value behind the pointer + // Run expandLoadedConfigValue on the value behind the pointer. expandEnvLoadedConfigValue(value.Elem()) } func expandEnvLoadedConfigValue(value reflect.Value) { - // The value given is a string, we expand it (if allowed) + // The value given is a string, we expand it (if allowed). if value.Kind() == reflect.String && value.CanSet() { value.SetString(expandEnv(value.String())) } - // The value given is a struct, we go through its fields + // The value given is a struct, we go through its fields. if value.Kind() == reflect.Struct { for i := 0; i < value.NumField(); i++ { - field := value.Field(i) // Returns the content of the field - if field.CanSet() { // Only try to modify a field if it can be modified (eg. skip unexported private fields) + // Returns the content of the field. + field := value.Field(i) + + // Only try to modify a field if it can be modified (eg. skip unexported private fields). + if field.CanSet() { switch field.Kind() { - case reflect.String: // The current field is a string, we want to expand it - field.SetString(expandEnv(field.String())) // Expand env variables in the string - case reflect.Ptr: // The current field is a pointer - expandEnvLoadedConfigPointer(field.Interface()) // Run the expansion function on the pointer - case reflect.Struct: // The current field is a nested struct - expandEnvLoadedConfigValue(field) // Go through the nested struct + case reflect.String: + // The current field is a string, expand env variables in the string. + field.SetString(expandEnv(field.String())) + case reflect.Ptr: + // The current field is a pointer, run the expansion function on the pointer. + expandEnvLoadedConfigPointer(field.Interface()) + case reflect.Struct: + // The current field is a nested struct, go through the nested struct + expandEnvLoadedConfigValue(field) } } } @@ -529,7 +537,7 @@ type deprecatedUnmarshaler interface { Unmarshal(componentViperSection *viper.Viper, intoCfg interface{}) error } -func unmarshal(componentSection *config.Parser, intoCfg interface{}) error { +func unmarshal(componentSection *configparser.Parser, intoCfg interface{}) error { if cu, ok := intoCfg.(config.CustomUnmarshable); ok { return cu.Unmarshal(componentSection) } @@ -538,9 +546,9 @@ func unmarshal(componentSection *config.Parser, intoCfg interface{}) error { } // unmarshaler returns an unmarshaling function. It should be removed when deprecatedUnmarshaler is removed. -func unmarshaler(factory component.Factory) func(componentViperSection *config.Parser, intoCfg interface{}) error { +func unmarshaler(factory component.Factory) func(componentViperSection *configparser.Parser, intoCfg interface{}) error { if _, ok := factory.(deprecatedUnmarshaler); ok { - return func(componentParser *config.Parser, intoCfg interface{}) error { + return func(componentParser *configparser.Parser, intoCfg interface{}) error { return errors.New("deprecated way to specify custom unmarshaler no longer supported") } } diff --git a/config/configloader/config_test.go b/config/configloader/config_test.go index d9f7bfcb191..d1850a66ba5 100644 --- a/config/configloader/config_test.go +++ b/config/configloader/config_test.go @@ -25,6 +25,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/confignet" + "go.opentelemetry.io/collector/config/configparser" "go.opentelemetry.io/collector/internal/testcomponents" ) @@ -455,7 +456,7 @@ func TestLoadEmptyAllSections(t *testing.T) { } func loadConfigFile(t *testing.T, fileName string, factories component.Factories) (*config.Config, error) { - v, err := config.NewParserFromFile(fileName) + v, err := configparser.NewParserFromFile(fileName) require.NoError(t, err) // Load the config from viper using the given factories. diff --git a/config/configloader/doc.go b/config/configloader/doc.go new file mode 100644 index 00000000000..1f08d22730b --- /dev/null +++ b/config/configloader/doc.go @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package configloader implements configuration loading from a config.Parser. +// The implementation relies on registered factories that allow creating +// default configuration for each type of receiver/exporter/processor. +package configloader diff --git a/config/confignet/confignet.go b/config/confignet/confignet.go index a5929b6ab72..067812f1301 100644 --- a/config/confignet/confignet.go +++ b/config/confignet/confignet.go @@ -42,7 +42,7 @@ func (na *NetAddr) Listen() (net.Listener, error) { return net.Listen(na.Transport, na.Endpoint) } -// TCPAddr represents a tcp endpoint address. +// TCPAddr represents a TCP endpoint address. type TCPAddr struct { // Endpoint configures the address for this network connection. // The address has the form "host:port". The host must be a literal IP address, or a host name that can be diff --git a/config/confignet/doc.go b/config/confignet/doc.go new file mode 100644 index 00000000000..1a37c602d6d --- /dev/null +++ b/config/confignet/doc.go @@ -0,0 +1,17 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package confignet implements the configuration settings for protocols to +// connect and transport data information. +package confignet diff --git a/config/parser.go b/config/configparser/parser.go similarity index 91% rename from config/parser.go rename to config/configparser/parser.go index d9f0c22d3d0..92a082a0cb9 100644 --- a/config/parser.go +++ b/config/configparser/parser.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package config +package configparser import ( "fmt" @@ -38,7 +38,7 @@ func NewParser() *Parser { // NewParserFromFile creates a new Parser by reading the given file. func NewParserFromFile(fileName string) (*Parser, error) { - // Read yaml config from file + // Read yaml config from file. p := NewParser() p.v.SetConfigFile(fileName) if err := p.v.ReadInConfig(); err != nil { @@ -71,13 +71,13 @@ type Parser struct { } // AllKeys returns all keys holding a value, regardless of where they are set. -// Nested keys are returned with a KeyDelimiter separator +// Nested keys are returned with a KeyDelimiter separator. func (l *Parser) AllKeys() []string { return l.v.AllKeys() } -// Unmarshal unmarshals the config into a struct. Make sure that the tags -// on the fields of the structure are properly set. +// Unmarshal unmarshals the config into a struct. +// Tags on the fields of the structure must be properly set. func (l *Parser) Unmarshal(rawVal interface{}) error { return l.v.Unmarshal(rawVal) } @@ -142,8 +142,8 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{} for _, k := range path { m2, ok := m[k] if !ok { - // intermediate key does not exist - // => create it and continue from there + // Intermediate key does not exist: + // create it and continue from there. m3 := make(map[string]interface{}) m[k] = m3 m = m3 @@ -151,8 +151,8 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{} } m3, ok := m2.(map[string]interface{}) if !ok { - // intermediate key is a value - // => replace with a new map + // Intermediate key is a value: + // replace with a new map. m3 = make(map[string]interface{}) m[k] = m3 } @@ -164,17 +164,17 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{} // ToStringMap creates a map[string]interface{} from a Parser. func (l *Parser) ToStringMap() map[string]interface{} { - // This is equivalent to l.v.AllSettings() but it maps nil values + // This is equivalent to l.v.AllSettings() but it maps nil values. // We can't use AllSettings here because of https://github.com/spf13/viper/issues/819 m := map[string]interface{}{} - // start from the list of keys, and construct the map one value at a time + // Start from the list of keys, and construct the map one value at a time. for _, k := range l.v.AllKeys() { value := l.v.Get(k) path := strings.Split(k, KeyDelimiter) lastKey := strings.ToLower(path[len(path)-1]) deepestMap := deepSearch(m, path[0:len(path)-1]) - // set innermost value + // Set innermost value. deepestMap[lastKey] = value } return m diff --git a/config/parser_test.go b/config/configparser/parser_test.go similarity index 99% rename from config/parser_test.go rename to config/configparser/parser_test.go index fe1709b8860..0b15c2936c6 100644 --- a/config/parser_test.go +++ b/config/configparser/parser_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package config +package configparser import ( "testing" diff --git a/config/testdata/basic_types.yaml b/config/configparser/testdata/basic_types.yaml similarity index 100% rename from config/testdata/basic_types.yaml rename to config/configparser/testdata/basic_types.yaml diff --git a/config/testdata/config.yaml b/config/configparser/testdata/config.yaml similarity index 100% rename from config/testdata/config.yaml rename to config/configparser/testdata/config.yaml diff --git a/config/configtelemetry/configtelemetry.go b/config/configtelemetry/configtelemetry.go index f944dd4ba83..b8bd1e60078 100644 --- a/config/configtelemetry/configtelemetry.go +++ b/config/configtelemetry/configtelemetry.go @@ -40,7 +40,7 @@ const ( var metricsLevelPtr = new(Level) -// Flags is a helper func, to add the telemetry config flags to the service that exposes +// Flags is a helper function to add telemetry config flags to the service that exposes // the application flags. func Flags(flags *flag.FlagSet) { flags.Var( diff --git a/config/configtelemetry/doc.go b/config/configtelemetry/doc.go new file mode 100644 index 00000000000..36fe369e957 --- /dev/null +++ b/config/configtelemetry/doc.go @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package configtelemetry defines various telemetry level for configuration. +// It enables every component to have access to telemetry level +// to enable metrics only when necessary. +package configtelemetry diff --git a/config/configtest/configtest.go b/config/configtest/configtest.go index 3a7edd69df4..0fbad0fd712 100644 --- a/config/configtest/configtest.go +++ b/config/configtest/configtest.go @@ -18,6 +18,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configloader" + "go.opentelemetry.io/collector/config/configparser" ) // LoadConfig loads a config from file, and does NOT validate the configuration. diff --git a/config/configtest/doc.go b/config/configtest/doc.go new file mode 100644 index 00000000000..a76c6c8e717 --- /dev/null +++ b/config/configtest/doc.go @@ -0,0 +1,17 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package configtest loads the configuration to test packages +// implementing the config package interfaces. +package configtest diff --git a/config/configtls/configtls.go b/config/configtls/configtls.go index 0ae722359b6..641971f2f7b 100644 --- a/config/configtls/configtls.go +++ b/config/configtls/configtls.go @@ -40,7 +40,8 @@ type TLSSetting struct { // connections in addition to the common configurations. This should be used by // components configuring TLS client connections. type TLSClientSetting struct { - TLSSetting `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct + // squash ensures fields are correctly decoded in embedded struct. + TLSSetting `mapstructure:",squash"` // These are config options specific to client connections. @@ -63,7 +64,8 @@ type TLSClientSetting struct { // connections in addition to the common configurations. This should be used by // components configuring TLS server connections. type TLSServerSetting struct { - TLSSetting `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct + // squash ensures fields are correctly decoded in embedded struct. + TLSSetting `mapstructure:",squash"` // These are config options specific to server connections. @@ -81,7 +83,7 @@ func (c TLSSetting) loadTLSConfig() (*tls.Config, error) { var err error var certPool *x509.CertPool if len(c.CAFile) != 0 { - // setup user specified truststore + // Set up user specified truststore. certPool, err = c.loadCert(c.CAFile) if err != nil { return nil, fmt.Errorf("failed to load CA CertPool: %w", err) @@ -120,7 +122,7 @@ func (c TLSSetting) loadCert(caPath string) (*x509.CertPool, error) { return certPool, nil } -// LoadTLSConfig loads the tls configuration. +// LoadTLSConfig loads the TLS configuration. func (c TLSClientSetting) LoadTLSConfig() (*tls.Config, error) { if c.Insecure && c.CAFile == "" { return nil, nil @@ -135,7 +137,7 @@ func (c TLSClientSetting) LoadTLSConfig() (*tls.Config, error) { return tlsCfg, nil } -// LoadTLSConfig loads the tls configuration. +// LoadTLSConfig loads the TLS configuration. func (c TLSServerSetting) LoadTLSConfig() (*tls.Config, error) { tlsCfg, err := c.loadTLSConfig() if err != nil { diff --git a/config/configtls/doc.go b/config/configtls/doc.go new file mode 100644 index 00000000000..93a167500c4 --- /dev/null +++ b/config/configtls/doc.go @@ -0,0 +1,17 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package configtls implements the TLS settings to load and +// configure TLS clients and servers. +package configtls diff --git a/config/doc.go b/config/doc.go new file mode 100644 index 00000000000..10f21a33f54 --- /dev/null +++ b/config/doc.go @@ -0,0 +1,30 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package config defines the data models for entities. This file defines the +// models for configuration format. The defined entities are: +// Config (the top-level structure), Receivers, Exporters, Processors, Pipelines. +// +// Receivers, Exporters and Processors typically have common configuration settings, however +// sometimes specific implementations will have extra configuration settings. +// This requires the configuration data for these entities to be polymorphic. +// +// To satisfy these requirements we declare interfaces Receiver, Exporter, Processor, +// which define the behavior. We also provide helper structs ReceiverSettings, ExporterSettings, +// ProcessorSettings, which define the common settings and un-marshaling from config files. +// +// Specific Receivers/Exporters/Processors are expected to at the minimum implement the +// corresponding interface and if they have additional settings they must also extend +// the corresponding common settings struct (the easiest approach is to embed the common struct). +package config diff --git a/config/experimental/configsource/component.go b/config/experimental/configsource/component.go index 8159d51e6c0..c65ea9bda5c 100644 --- a/config/experimental/configsource/component.go +++ b/config/experimental/configsource/component.go @@ -12,11 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package configsource is an experimental package that defines the interface of -// "configuration sources," e.g., Vault, ZooKeeper, etcd2, and others. Configuration -// sources retrieve values from their respective storages. A configuration parser/loader -// can inject these values in the configuration data used by the collector. -// ATTENTION: the package is still experimental and subject to changes without advanced notice. package configsource import ( diff --git a/config/experimental/configsource/doc.go b/config/experimental/configsource/doc.go new file mode 100644 index 00000000000..73b0b772145 --- /dev/null +++ b/config/experimental/configsource/doc.go @@ -0,0 +1,20 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package configsource is an experimental package that defines the interface of +// "configuration sources," e.g., Vault, ZooKeeper, etcd2, and others. Configuration +// sources retrieve values from their respective storages. A configuration parser/loader +// can inject these values in the configuration data used by the collector. +// ATTENTION: the package is still experimental and subject to changes without advanced notice. +package configsource diff --git a/config/exporter.go b/config/exporter.go index 247f4c07628..5df3161d7cb 100644 --- a/config/exporter.go +++ b/config/exporter.go @@ -26,7 +26,7 @@ type Exporters map[ComponentID]Exporter // ExporterSettings defines common settings for an exporter configuration. // Specific exporters can embed this struct and extend it with more fields if needed. -// When embedded in the exporter config it must be with `mapstructure:",squash"` tag. +// When embedded in the exporter config, it must be with `mapstructure:",squash"` tag. type ExporterSettings struct { id ComponentID `mapstructure:"-"` } diff --git a/config/extension.go b/config/extension.go index b0587cddad7..b57dc507dd0 100644 --- a/config/extension.go +++ b/config/extension.go @@ -17,7 +17,7 @@ package config // Extension is the configuration of a service extension. Specific extensions // must implement this interface and will typically embed ExtensionSettings // struct or a struct that extends it. -// Embedded validatable will force each extension to implement Validate() function +// Embedded validatable will force each extension to implement Validate() function. type Extension interface { identifiable validatable @@ -28,7 +28,7 @@ type Extensions map[ComponentID]Extension // ExtensionSettings defines common settings for an extension configuration. // Specific processors can embed this struct and extend it with more fields if needed. -// When embedded in the extension config it must be with `mapstructure:",squash"` tag. +// When embedded in the extension config, it must be with `mapstructure:",squash"` tag. type ExtensionSettings struct { id ComponentID `mapstructure:"-"` } diff --git a/config/internal/configsource/doc.go b/config/internal/configsource/doc.go new file mode 100644 index 00000000000..f7fa73f46c4 --- /dev/null +++ b/config/internal/configsource/doc.go @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package configsource is an internal package that implements methods +// for injecting, watching, and updating data from ConfigSource into +// configuration. +package configsource diff --git a/config/internal/configsource/manager.go b/config/internal/configsource/manager.go index d45c25754ea..81ab85cfd05 100644 --- a/config/internal/configsource/manager.go +++ b/config/internal/configsource/manager.go @@ -26,7 +26,7 @@ import ( "gopkg.in/yaml.v2" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" "go.opentelemetry.io/collector/config/experimental/configsource" "go.opentelemetry.io/collector/consumer/consumererror" ) @@ -36,7 +36,7 @@ const ( // either environment variables or config sources. expandPrefixChar = '$' // configSourceNameDelimChar is the char used to terminate the name of config source - // when it is used to retrieve values to inject in the configuration + // when it is used to retrieve values to inject in the configuration. configSourceNameDelimChar = ':' ) @@ -47,7 +47,7 @@ type ( // Manager is used to inject data from config sources into a configuration and also // to monitor for updates on the items injected into the configuration. All methods -// of a Manager must be called only once and have a expected sequence: +// of a Manager must be called only once and have an expected sequence: // // 1. NewManager to create a new instance; // 2. Resolve to inject the data from config sources into a configuration; @@ -176,7 +176,7 @@ type Manager struct { // NewManager creates a new instance of a Manager to be used to inject data from // ConfigSource objects into a configuration and watch for updates on the injected // data. -func NewManager(_ *config.Parser) (*Manager, error) { +func NewManager(_ *configparser.Parser) (*Manager, error) { // TODO: Config sources should be extracted for the config itself, need Factories for that. return &Manager{ @@ -190,8 +190,8 @@ func NewManager(_ *config.Parser) (*Manager, error) { // Resolve inspects the given config.Parser and resolves all config sources referenced // in the configuration, returning a config.Parser fully resolved. This must be called only // once per lifetime of a Manager object. -func (m *Manager) Resolve(ctx context.Context, parser *config.Parser) (*config.Parser, error) { - res := config.NewParser() +func (m *Manager) Resolve(ctx context.Context, parser *configparser.Parser) (*configparser.Parser, error) { + res := configparser.NewParser() allKeys := parser.AllKeys() for _, k := range allKeys { value, err := m.expandStringValues(ctx, parser.Get(k)) @@ -385,7 +385,8 @@ func (m *Manager) expandString(ctx context.Context, s string) (interface{}, erro case s[j+1] == '{': // Bracketed usage, consume everything until first '}' exactly as os.Expand. expandableContent, w = getShellName(s[j+1:]) - expandableContent = strings.Trim(expandableContent, " ") // Allow for some spaces. + // Allow for some spaces. + expandableContent = strings.Trim(expandableContent, " ") if len(expandableContent) > 1 && strings.Contains(expandableContent, string(configSourceNameDelimChar)) { // Bracket expandableContent contains ':' treating it as a config source. cfgSrcName, _ = getShellName(expandableContent) @@ -489,8 +490,8 @@ func parseCfgSrc(s string) (cfgSrcName, selector string, params interface{}, err selector = strings.Trim(parts[0], " ") if len(parts) > 1 && len(parts[1]) > 0 { - var cp *config.Parser - cp, err = config.NewParserFromBuffer(bytes.NewReader([]byte(parts[1]))) + var cp *configparser.Parser + cp, err = configparser.NewParserFromBuffer(bytes.NewReader([]byte(parts[1]))) if err != nil { return } @@ -613,12 +614,14 @@ func getShellName(s string) (string, int) { for i := 1; i < len(s); i++ { if s[i] == '}' { if i == 1 { - return "", 2 // Bad syntax; eat "${}" + // Bad syntax; eat "${}" + return "", 2 } return s[1:i], i + 1 } } - return "", 1 // Bad syntax; eat "${" + // Bad syntax; eat "${" + return "", 1 case isShellSpecialVar(s[0]): return s[0:1], 1 } diff --git a/config/internal/configsource/manager_test.go b/config/internal/configsource/manager_test.go index 66752217706..455ab270542 100644 --- a/config/internal/configsource/manager_test.go +++ b/config/internal/configsource/manager_test.go @@ -25,7 +25,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" "go.opentelemetry.io/collector/config/experimental/configsource" ) @@ -54,7 +54,7 @@ func TestConfigSourceManager_Simple(t *testing.T) { }, } - cp := config.NewParserFromStringMap(originalCfg) + cp := configparser.NewParserFromStringMap(originalCfg) actualParser, err := manager.Resolve(ctx, cp) require.NoError(t, err) @@ -130,7 +130,7 @@ func TestConfigSourceManager_ResolveErrors(t *testing.T) { require.NoError(t, err) manager.configSources = tt.configSourceMap - res, err := manager.Resolve(ctx, config.NewParserFromStringMap(tt.config)) + res, err := manager.Resolve(ctx, configparser.NewParserFromStringMap(tt.config)) require.Error(t, err) require.Nil(t, res) require.NoError(t, manager.Close(ctx)) @@ -154,11 +154,11 @@ func TestConfigSourceManager_ArraysAndMaps(t *testing.T) { } file := path.Join("testdata", "arrays_and_maps.yaml") - cp, err := config.NewParserFromFile(file) + cp, err := configparser.NewParserFromFile(file) require.NoError(t, err) expectedFile := path.Join("testdata", "arrays_and_maps_expected.yaml") - expectedParser, err := config.NewParserFromFile(expectedFile) + expectedParser, err := configparser.NewParserFromFile(expectedFile) require.NoError(t, err) actualParser, err := manager.Resolve(ctx, cp) @@ -206,11 +206,11 @@ func TestConfigSourceManager_ParamsHandling(t *testing.T) { } file := path.Join("testdata", "params_handling.yaml") - cp, err := config.NewParserFromFile(file) + cp, err := configparser.NewParserFromFile(file) require.NoError(t, err) expectedFile := path.Join("testdata", "params_handling_expected.yaml") - expectedParser, err := config.NewParserFromFile(expectedFile) + expectedParser, err := configparser.NewParserFromFile(expectedFile) require.NoError(t, err) actualParser, err := manager.Resolve(ctx, cp) @@ -244,7 +244,7 @@ func TestConfigSourceManager_WatchForUpdate(t *testing.T) { }, } - cp := config.NewParserFromStringMap(originalCfg) + cp := configparser.NewParserFromStringMap(originalCfg) _, err = manager.Resolve(ctx, cp) require.NoError(t, err) @@ -300,7 +300,7 @@ func TestConfigSourceManager_MultipleWatchForUpdate(t *testing.T) { }, } - cp := config.NewParserFromStringMap(originalCfg) + cp := configparser.NewParserFromStringMap(originalCfg) _, err = manager.Resolve(ctx, cp) require.NoError(t, err) @@ -351,11 +351,11 @@ func TestConfigSourceManager_EnvVarHandling(t *testing.T) { } file := path.Join("testdata", "envvar_cfgsrc_mix.yaml") - cp, err := config.NewParserFromFile(file) + cp, err := configparser.NewParserFromFile(file) require.NoError(t, err) expectedFile := path.Join("testdata", "envvar_cfgsrc_mix_expected.yaml") - expectedParser, err := config.NewParserFromFile(expectedFile) + expectedParser, err := configparser.NewParserFromFile(expectedFile) require.NoError(t, err) actualParser, err := manager.Resolve(ctx, cp) diff --git a/config/processor.go b/config/processor.go index f9c20fd866f..34c61bccfbe 100644 --- a/config/processor.go +++ b/config/processor.go @@ -16,7 +16,7 @@ package config // Processor is the configuration of a processor. Specific processors must implement this // interface and will typically embed ProcessorSettings struct or a struct that extends it. -// Embedded validatable will force each processor to implement Validate() function +// Embedded validatable will force each processor to implement Validate() function. type Processor interface { identifiable validatable diff --git a/config/receiver.go b/config/receiver.go index ae1de1ccaa7..a934988991f 100644 --- a/config/receiver.go +++ b/config/receiver.go @@ -16,7 +16,7 @@ package config // Receiver is the configuration of a receiver. Specific receivers must implement this // interface and will typically embed ReceiverSettings struct or a struct that extends it. -// Embedded validatable will force each receiver to implement Validate() function +// Embedded validatable will force each receiver to implement Validate() function. type Receiver interface { identifiable validatable diff --git a/examples/k8s/otel-config.yaml b/examples/k8s/otel-config.yaml index 6b1cdd31513..f8937d7e9dd 100644 --- a/examples/k8s/otel-config.yaml +++ b/examples/k8s/otel-config.yaml @@ -15,7 +15,7 @@ data: http: exporters: otlp: - endpoint: "otel-collector.default:55680" # TODO: Update me + endpoint: "otel-collector.default:4317" insecure: true sending_queue: num_consumers: 4 @@ -78,7 +78,7 @@ spec: memory: 100Mi ports: - containerPort: 55679 # ZPages endpoint. - - containerPort: 55680 # Default OpenTelemetry receiver port. + - containerPort: 4317 # Default OpenTelemetry receiver port. - containerPort: 8888 # Metrics. volumeMounts: - name: otel-agent-config-vol @@ -159,9 +159,9 @@ metadata: spec: ports: - name: otlp # Default endpoint for OpenTelemetry receiver. - port: 55680 + port: 4317 protocol: TCP - targetPort: 55680 + targetPort: 4317 - name: jaeger-grpc # Default endpoint for Jaeger gRPC receiver port: 14250 - name: jaeger-thrift-http # Default endpoint for Jaeger HTTP receiver. @@ -211,7 +211,7 @@ spec: memory: 400Mi ports: - containerPort: 55679 # Default endpoint for ZPages. - - containerPort: 55680 # Default endpoint for OpenTelemetry receiver. + - containerPort: 4317 # Default endpoint for OpenTelemetry receiver. - containerPort: 14250 # Default endpoint for Jaeger HTTP receiver. - containerPort: 14268 # Default endpoint for Jaeger HTTP receiver. - containerPort: 9411 # Default endpoint for Zipkin receiver. diff --git a/exporter/exporterhelper/logs_test.go b/exporter/exporterhelper/logs_test.go index cbbd2d4628e..7333c727b55 100644 --- a/exporter/exporterhelper/logs_test.go +++ b/exporter/exporterhelper/logs_test.go @@ -30,8 +30,8 @@ import ( "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumerhelper" "go.opentelemetry.io/collector/consumer/pdata" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" "go.opentelemetry.io/collector/internal/testdata" - "go.opentelemetry.io/collector/obsreport" "go.opentelemetry.io/collector/obsreport/obsreporttest" ) @@ -222,7 +222,7 @@ func checkWrapSpanForLogsExporter(t *testing.T, le component.LogsExporter, wantE sentLogRecords = 0 failedToSendLogRecords = numLogRecords } - require.Equalf(t, sentLogRecords, sd.Attributes[obsreport.SentLogRecordsKey], "SpanData %v", sd) - require.Equalf(t, failedToSendLogRecords, sd.Attributes[obsreport.FailedToSendLogRecordsKey], "SpanData %v", sd) + require.Equalf(t, sentLogRecords, sd.Attributes[obsmetrics.SentLogRecordsKey], "SpanData %v", sd) + require.Equalf(t, failedToSendLogRecords, sd.Attributes[obsmetrics.FailedToSendLogRecordsKey], "SpanData %v", sd) } } diff --git a/exporter/exporterhelper/metrics_test.go b/exporter/exporterhelper/metrics_test.go index 2f1ee8d3e73..61baee86517 100644 --- a/exporter/exporterhelper/metrics_test.go +++ b/exporter/exporterhelper/metrics_test.go @@ -30,8 +30,8 @@ import ( "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumerhelper" "go.opentelemetry.io/collector/consumer/pdata" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" "go.opentelemetry.io/collector/internal/testdata" - "go.opentelemetry.io/collector/obsreport" "go.opentelemetry.io/collector/obsreport/obsreporttest" ) @@ -246,7 +246,7 @@ func checkWrapSpanForMetricsExporter(t *testing.T, me component.MetricsExporter, sentMetricPoints = 0 failedToSendMetricPoints = numMetricPoints } - require.Equalf(t, sentMetricPoints, sd.Attributes[obsreport.SentMetricPointsKey], "SpanData %v", sd) - require.Equalf(t, failedToSendMetricPoints, sd.Attributes[obsreport.FailedToSendMetricPointsKey], "SpanData %v", sd) + require.Equalf(t, sentMetricPoints, sd.Attributes[obsmetrics.SentMetricPointsKey], "SpanData %v", sd) + require.Equalf(t, failedToSendMetricPoints, sd.Attributes[obsmetrics.FailedToSendMetricPointsKey], "SpanData %v", sd) } } diff --git a/exporter/exporterhelper/queued_retry.go b/exporter/exporterhelper/queued_retry.go index ae68dafc467..313a13b241e 100644 --- a/exporter/exporterhelper/queued_retry.go +++ b/exporter/exporterhelper/queued_retry.go @@ -30,16 +30,16 @@ import ( "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/consumer/consumererror" - "go.opentelemetry.io/collector/obsreport" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" ) var ( r = metric.NewRegistry() queueSizeGauge, _ = r.AddInt64DerivedGauge( - obsreport.ExporterKey+"/queue_size", + obsmetrics.ExporterKey+"/queue_size", metric.WithDescription("Current size of the retry queue (in batches)"), - metric.WithLabelKeys(obsreport.ExporterKey), + metric.WithLabelKeys(obsmetrics.ExporterKey), metric.WithUnit(metricdata.UnitDimensionless)) ) @@ -127,7 +127,7 @@ func createSampledLogger(logger *zap.Logger) *zap.Logger { func newQueuedRetrySender(fullName string, qCfg QueueSettings, rCfg RetrySettings, nextSender requestSender, logger *zap.Logger) *queuedRetrySender { retryStopCh := make(chan struct{}) sampledLogger := createSampledLogger(logger) - traceAttr := trace.StringAttribute(obsreport.ExporterKey, fullName) + traceAttr := trace.StringAttribute(obsmetrics.ExporterKey, fullName) return &queuedRetrySender{ fullName: fullName, cfg: qCfg, diff --git a/exporter/exporterhelper/traces_test.go b/exporter/exporterhelper/traces_test.go index 1ce9d5dbfe6..4fc1f0b38f7 100644 --- a/exporter/exporterhelper/traces_test.go +++ b/exporter/exporterhelper/traces_test.go @@ -31,8 +31,8 @@ import ( "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumerhelper" "go.opentelemetry.io/collector/consumer/pdata" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" "go.opentelemetry.io/collector/internal/testdata" - "go.opentelemetry.io/collector/obsreport" "go.opentelemetry.io/collector/obsreport/obsreporttest" ) @@ -239,7 +239,7 @@ func checkWrapSpanForTracesExporter(t *testing.T, te component.TracesExporter, w failedToSendSpans = numSpans } - require.Equalf(t, sentSpans, sd.Attributes[obsreport.SentSpansKey], "SpanData %v", sd) - require.Equalf(t, failedToSendSpans, sd.Attributes[obsreport.FailedToSendSpansKey], "SpanData %v", sd) + require.Equalf(t, sentSpans, sd.Attributes[obsmetrics.SentSpansKey], "SpanData %v", sd) + require.Equalf(t, failedToSendSpans, sd.Attributes[obsmetrics.FailedToSendSpansKey], "SpanData %v", sd) } } diff --git a/exporter/otlpexporter/README.md b/exporter/otlpexporter/README.md index 4e87f27d76e..53d8f291bec 100644 --- a/exporter/otlpexporter/README.md +++ b/exporter/otlpexporter/README.md @@ -34,11 +34,11 @@ Example: ```yaml exporters: otlp: - endpoint: otelcol2:55680 + endpoint: otelcol2:4317 cert_file: file.cert key_file: file.key otlp/2: - endpoint: otelcol2:55680 + endpoint: otelcol2:4317 insecure: true ``` diff --git a/exporter/prometheusexporter/accumulator.go b/exporter/prometheusexporter/accumulator.go index d2af0dd635c..3652d05f374 100644 --- a/exporter/prometheusexporter/accumulator.go +++ b/exporter/prometheusexporter/accumulator.go @@ -376,7 +376,7 @@ func timeseriesSignature(ilmName string, metric pdata.Metric, labels pdata.Strin b.WriteString(metric.DataType().String()) b.WriteString("*" + ilmName) b.WriteString("*" + metric.Name()) - labels.Range(func(k string, v string) bool { + labels.Sort().Range(func(k string, v string) bool { b.WriteString("*" + k + "*" + v) return true }) diff --git a/exporter/prometheusremotewriteexporter/exporter.go b/exporter/prometheusremotewriteexporter/exporter.go index 00b818172b7..4e50ca44eb8 100644 --- a/exporter/prometheusremotewriteexporter/exporter.go +++ b/exporter/prometheusremotewriteexporter/exporter.go @@ -33,6 +33,7 @@ import ( "github.com/prometheus/prometheus/prompb" "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/pdata" ) @@ -49,15 +50,11 @@ type PRWExporter struct { closeChan chan struct{} concurrency int userAgentHeader string + clientSettings *confighttp.HTTPClientSettings } // NewPRWExporter initializes a new PRWExporter instance and sets fields accordingly. func NewPRWExporter(cfg *Config, buildInfo component.BuildInfo) (*PRWExporter, error) { - client, err := cfg.HTTPClientSettings.ToClient() - if err != nil { - return nil, err - } - sanitizedLabels, err := validateAndSanitizeExternalLabels(cfg.ExternalLabels) if err != nil { return nil, err @@ -74,14 +71,20 @@ func NewPRWExporter(cfg *Config, buildInfo component.BuildInfo) (*PRWExporter, e namespace: cfg.Namespace, externalLabels: sanitizedLabels, endpointURL: endpointURL, - client: client, wg: new(sync.WaitGroup), closeChan: make(chan struct{}), userAgentHeader: userAgentHeader, concurrency: cfg.RemoteWriteQueue.NumConsumers, + clientSettings: &cfg.HTTPClientSettings, }, nil } +// Start creates the prometheus client +func (prwe *PRWExporter) Start(_ context.Context, _ component.Host) (err error) { + prwe.client, err = prwe.clientSettings.ToClient() + return err +} + // Shutdown stops the exporter from accepting incoming calls(and return error), and wait for current export operations // to finish before returning func (prwe *PRWExporter) Shutdown(context.Context) error { diff --git a/exporter/prometheusremotewriteexporter/exporter_test.go b/exporter/prometheusremotewriteexporter/exporter_test.go index 56295b07eef..1eda3f6e9b8 100644 --- a/exporter/prometheusremotewriteexporter/exporter_test.go +++ b/exporter/prometheusremotewriteexporter/exporter_test.go @@ -30,8 +30,10 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/consumer/pdata" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/internal/testdata" @@ -53,59 +55,52 @@ func Test_NewPRWExporter(t *testing.T) { } tests := []struct { - name string - config *Config - namespace string - endpoint string - concurrency int - externalLabels map[string]string - client *http.Client - returnError bool - buildInfo component.BuildInfo + name string + config *Config + namespace string + endpoint string + concurrency int + externalLabels map[string]string + returnErrorOnCreate bool + buildInfo component.BuildInfo }{ { - "invalid_URL", - cfg, - "test", - "invalid URL", - 5, - map[string]string{"Key1": "Val1"}, - http.DefaultClient, - true, - buildInfo, + name: "invalid_URL", + config: cfg, + namespace: "test", + endpoint: "invalid URL", + concurrency: 5, + externalLabels: map[string]string{"Key1": "Val1"}, + returnErrorOnCreate: true, + buildInfo: buildInfo, }, { - "invalid_labels_case", - cfg, - "test", - "http://some.url:9411/api/prom/push", - 5, - map[string]string{"Key1": ""}, - http.DefaultClient, - true, - buildInfo, + name: "invalid_labels_case", + config: cfg, + namespace: "test", + endpoint: "http://some.url:9411/api/prom/push", + concurrency: 5, + externalLabels: map[string]string{"Key1": ""}, + returnErrorOnCreate: true, + buildInfo: buildInfo, }, { - "success_case", - cfg, - "test", - "http://some.url:9411/api/prom/push", - 5, - map[string]string{"Key1": "Val1"}, - http.DefaultClient, - false, - buildInfo, + name: "success_case", + config: cfg, + namespace: "test", + endpoint: "http://some.url:9411/api/prom/push", + concurrency: 5, + externalLabels: map[string]string{"Key1": "Val1"}, + buildInfo: buildInfo, }, { - "success_case_no_labels", - cfg, - "test", - "http://some.url:9411/api/prom/push", - 5, - map[string]string{}, - http.DefaultClient, - false, - buildInfo, + name: "success_case_no_labels", + config: cfg, + namespace: "test", + endpoint: "http://some.url:9411/api/prom/push", + concurrency: 5, + externalLabels: map[string]string{}, + buildInfo: buildInfo, }, } @@ -117,7 +112,7 @@ func Test_NewPRWExporter(t *testing.T) { cfg.RemoteWriteQueue.NumConsumers = 1 prwe, err := NewPRWExporter(cfg, tt.buildInfo) - if tt.returnError { + if tt.returnErrorOnCreate { assert.Error(t, err) return } @@ -125,10 +120,87 @@ func Test_NewPRWExporter(t *testing.T) { assert.NotNil(t, prwe.namespace) assert.NotNil(t, prwe.endpointURL) assert.NotNil(t, prwe.externalLabels) - assert.NotNil(t, prwe.client) assert.NotNil(t, prwe.closeChan) assert.NotNil(t, prwe.wg) assert.NotNil(t, prwe.userAgentHeader) + assert.NotNil(t, prwe.clientSettings) + }) + } +} + +// Test_Start checks if the client is properly created as expected. +func Test_Start(t *testing.T) { + cfg := &Config{ + ExporterSettings: config.NewExporterSettings(config.NewID(typeStr)), + TimeoutSettings: exporterhelper.TimeoutSettings{}, + RetrySettings: exporterhelper.RetrySettings{}, + Namespace: "", + ExternalLabels: map[string]string{}, + } + buildInfo := component.BuildInfo{ + Description: "OpenTelemetry Collector", + Version: "1.0", + } + tests := []struct { + name string + config *Config + namespace string + concurrency int + externalLabels map[string]string + returnErrorOnStartUp bool + buildInfo component.BuildInfo + endpoint string + clientSettings confighttp.HTTPClientSettings + }{ + { + name: "success_case", + config: cfg, + namespace: "test", + concurrency: 5, + externalLabels: map[string]string{"Key1": "Val1"}, + buildInfo: buildInfo, + clientSettings: confighttp.HTTPClientSettings{Endpoint: "https://some.url:9411/api/prom/push"}, + }, + { + name: "invalid_tls", + config: cfg, + namespace: "test", + concurrency: 5, + externalLabels: map[string]string{"Key1": "Val1"}, + buildInfo: buildInfo, + returnErrorOnStartUp: true, + clientSettings: confighttp.HTTPClientSettings{ + Endpoint: "https://some.url:9411/api/prom/push", + TLSSetting: configtls.TLSClientSetting{ + TLSSetting: configtls.TLSSetting{ + CAFile: "non-existent file", + CertFile: "", + KeyFile: "", + }, + Insecure: false, + ServerName: "", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg.ExternalLabels = tt.externalLabels + cfg.Namespace = tt.namespace + cfg.RemoteWriteQueue.NumConsumers = 1 + cfg.HTTPClientSettings = tt.clientSettings + + prwe, err := NewPRWExporter(cfg, tt.buildInfo) + assert.NoError(t, err) + assert.NotNil(t, prwe) + + err = prwe.Start(context.Background(), componenttest.NewNopHost()) + if tt.returnErrorOnStartUp { + assert.Error(t, err) + return + } + assert.NotNil(t, prwe.client) }) } } @@ -195,11 +267,11 @@ func Test_export(t *testing.T) { // Create in test table format to check if different HTTP response codes or server errors // are properly identified tests := []struct { - name string - ts prompb.TimeSeries - serverUp bool - httpResponseCode int - returnError bool + name string + ts prompb.TimeSeries + serverUp bool + httpResponseCode int + returnErrorOnCreate bool }{ {"success_case", *ts1, @@ -236,7 +308,7 @@ func Test_export(t *testing.T) { server.Close() } errs := runExportPipeline(ts1, serverURL) - if tt.returnError { + if tt.returnErrorOnCreate { assert.Error(t, errs[0]) return } @@ -266,6 +338,12 @@ func runExportPipeline(ts *prompb.TimeSeries, endpoint *url.URL) []error { errs = append(errs, err) return errs } + + if err = prwe.Start(context.Background(), componenttest.NewNopHost()); err != nil { + errs = append(errs, err) + return errs + } + errs = append(errs, prwe.export(context.Background(), testmap)...) return errs } @@ -515,6 +593,7 @@ func Test_PushMetrics(t *testing.T) { } prwe, nErr := NewPRWExporter(cfg, buildInfo) require.NoError(t, nErr) + require.NoError(t, prwe.Start(context.Background(), componenttest.NewNopHost())) err := prwe.PushMetrics(context.Background(), *tt.md) if tt.returnErr { assert.Error(t, err) @@ -527,10 +606,10 @@ func Test_PushMetrics(t *testing.T) { func Test_validateAndSanitizeExternalLabels(t *testing.T) { tests := []struct { - name string - inputLabels map[string]string - expectedLabels map[string]string - returnError bool + name string + inputLabels map[string]string + expectedLabels map[string]string + returnErrorOnCreate bool }{ {"success_case_no_labels", map[string]string{}, @@ -562,7 +641,7 @@ func Test_validateAndSanitizeExternalLabels(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { newLabels, err := validateAndSanitizeExternalLabels(tt.inputLabels) - if tt.returnError { + if tt.returnErrorOnCreate { assert.Error(t, err) return } diff --git a/exporter/prometheusremotewriteexporter/factory.go b/exporter/prometheusremotewriteexporter/factory.go index 878790992e2..6b9b2c155a1 100644 --- a/exporter/prometheusremotewriteexporter/factory.go +++ b/exporter/prometheusremotewriteexporter/factory.go @@ -68,6 +68,7 @@ func createMetricsExporter(_ context.Context, params component.ExporterCreatePar }), exporterhelper.WithRetry(prwCfg.RetrySettings), exporterhelper.WithResourceToTelemetryConversion(prwCfg.ResourceToTelemetrySettings), + exporterhelper.WithStart(prwe.Start), exporterhelper.WithShutdown(prwe.Shutdown), ) } diff --git a/exporter/prometheusremotewriteexporter/factory_test.go b/exporter/prometheusremotewriteexporter/factory_test.go index b2d813a1478..3a9060c5d97 100644 --- a/exporter/prometheusremotewriteexporter/factory_test.go +++ b/exporter/prometheusremotewriteexporter/factory_test.go @@ -22,6 +22,7 @@ import ( "go.uber.org/zap" "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configcheck" "go.opentelemetry.io/collector/config/confighttp" @@ -51,37 +52,49 @@ func Test_createMetricsExporter(t *testing.T) { ServerName: "", } tests := []struct { - name string - cfg config.Exporter - params component.ExporterCreateParams - returnError bool + name string + cfg config.Exporter + params component.ExporterCreateParams + returnErrorOnCreate bool + returnErrorOnStart bool }{ {"success_case", createDefaultConfig(), component.ExporterCreateParams{Logger: zap.NewNop()}, false, + false, }, {"fail_case", nil, component.ExporterCreateParams{Logger: zap.NewNop()}, true, + false, }, {"invalid_config_case", invalidConfig, component.ExporterCreateParams{Logger: zap.NewNop()}, true, + false, }, {"invalid_tls_config_case", invalidTLSConfig, component.ExporterCreateParams{Logger: zap.NewNop()}, + false, true, }, } // run tests for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, err := createMetricsExporter(context.Background(), tt.params, tt.cfg) - if tt.returnError { + exp, err := createMetricsExporter(context.Background(), tt.params, tt.cfg) + if tt.returnErrorOnCreate { + assert.Error(t, err) + return + } + assert.NoError(t, err) + assert.NotNil(t, exp) + err = exp.Start(context.Background(), componenttest.NewNopHost()) + if tt.returnErrorOnStart { assert.Error(t, err) return } diff --git a/internal/obsreportconfig/obsmetrics/obs_exporter.go b/internal/obsreportconfig/obsmetrics/obs_exporter.go new file mode 100644 index 00000000000..01f88ece936 --- /dev/null +++ b/internal/obsreportconfig/obsmetrics/obs_exporter.go @@ -0,0 +1,79 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package obsmetrics + +import ( + "go.opencensus.io/stats" + "go.opencensus.io/tag" +) + +const ( + // ExporterKey used to identify exporters in metrics and traces. + ExporterKey = "exporter" + + // SentSpansKey used to track spans sent by exporters. + SentSpansKey = "sent_spans" + // FailedToSendSpansKey used to track spans that failed to be sent by exporters. + FailedToSendSpansKey = "send_failed_spans" + + // SentMetricPointsKey used to track metric points sent by exporters. + SentMetricPointsKey = "sent_metric_points" + // FailedToSendMetricPointsKey used to track metric points that failed to be sent by exporters. + FailedToSendMetricPointsKey = "send_failed_metric_points" + + // SentLogRecordsKey used to track logs sent by exporters. + SentLogRecordsKey = "sent_log_records" + // FailedToSendLogRecordsKey used to track logs that failed to be sent by exporters. + FailedToSendLogRecordsKey = "send_failed_log_records" +) + +var ( + TagKeyExporter, _ = tag.NewKey(ExporterKey) + + ExporterPrefix = ExporterKey + NameSep + ExportTraceDataOperationSuffix = NameSep + "traces" + ExportMetricsOperationSuffix = NameSep + "metrics" + ExportLogsOperationSuffix = NameSep + "logs" + + // Exporter metrics. Any count of data items below is in the final format + // that they were sent, reasoning: reconciliation is easier if measurements + // on backend and exporter are expected to be the same. Translation issues + // that result in a different number of elements should be reported in a + // separate way. + ExporterSentSpans = stats.Int64( + ExporterPrefix+SentSpansKey, + "Number of spans successfully sent to destination.", + stats.UnitDimensionless) + ExporterFailedToSendSpans = stats.Int64( + ExporterPrefix+FailedToSendSpansKey, + "Number of spans in failed attempts to send to destination.", + stats.UnitDimensionless) + ExporterSentMetricPoints = stats.Int64( + ExporterPrefix+SentMetricPointsKey, + "Number of metric points successfully sent to destination.", + stats.UnitDimensionless) + ExporterFailedToSendMetricPoints = stats.Int64( + ExporterPrefix+FailedToSendMetricPointsKey, + "Number of metric points in failed attempts to send to destination.", + stats.UnitDimensionless) + ExporterSentLogRecords = stats.Int64( + ExporterPrefix+SentLogRecordsKey, + "Number of log record successfully sent to destination.", + stats.UnitDimensionless) + ExporterFailedToSendLogRecords = stats.Int64( + ExporterPrefix+FailedToSendLogRecordsKey, + "Number of log records in failed attempts to send to destination.", + stats.UnitDimensionless) +) diff --git a/internal/obsreportconfig/obsmetrics/obs_processor.go b/internal/obsreportconfig/obsmetrics/obs_processor.go new file mode 100644 index 00000000000..ea4a9a51751 --- /dev/null +++ b/internal/obsreportconfig/obsmetrics/obs_processor.go @@ -0,0 +1,79 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package obsmetrics + +import ( + "go.opencensus.io/stats" + "go.opencensus.io/tag" +) + +const ( + // ProcessorKey is the key used to identify processors in metrics and traces. + ProcessorKey = "processor" + + // DroppedSpansKey is the key used to identify spans dropped by the Collector. + DroppedSpansKey = "dropped_spans" + + // DroppedMetricPointsKey is the key used to identify metric points dropped by the Collector. + DroppedMetricPointsKey = "dropped_metric_points" + + // DroppedLogRecordsKey is the key used to identify log records dropped by the Collector. + DroppedLogRecordsKey = "dropped_log_records" +) + +var ( + TagKeyProcessor, _ = tag.NewKey(ProcessorKey) + + ProcessorPrefix = ProcessorKey + NameSep + + // Processor metrics. Any count of data items below is in the internal format + // of the collector since processors only deal with internal format. + ProcessorAcceptedSpans = stats.Int64( + ProcessorPrefix+AcceptedSpansKey, + "Number of spans successfully pushed into the next component in the pipeline.", + stats.UnitDimensionless) + ProcessorRefusedSpans = stats.Int64( + ProcessorPrefix+RefusedSpansKey, + "Number of spans that were rejected by the next component in the pipeline.", + stats.UnitDimensionless) + ProcessorDroppedSpans = stats.Int64( + ProcessorPrefix+DroppedSpansKey, + "Number of spans that were dropped.", + stats.UnitDimensionless) + ProcessorAcceptedMetricPoints = stats.Int64( + ProcessorPrefix+AcceptedMetricPointsKey, + "Number of metric points successfully pushed into the next component in the pipeline.", + stats.UnitDimensionless) + ProcessorRefusedMetricPoints = stats.Int64( + ProcessorPrefix+RefusedMetricPointsKey, + "Number of metric points that were rejected by the next component in the pipeline.", + stats.UnitDimensionless) + ProcessorDroppedMetricPoints = stats.Int64( + ProcessorPrefix+DroppedMetricPointsKey, + "Number of metric points that were dropped.", + stats.UnitDimensionless) + ProcessorAcceptedLogRecords = stats.Int64( + ProcessorPrefix+AcceptedLogRecordsKey, + "Number of log records successfully pushed into the next component in the pipeline.", + stats.UnitDimensionless) + ProcessorRefusedLogRecords = stats.Int64( + ProcessorPrefix+RefusedLogRecordsKey, + "Number of log records that were rejected by the next component in the pipeline.", + stats.UnitDimensionless) + ProcessorDroppedLogRecords = stats.Int64( + ProcessorPrefix+DroppedLogRecordsKey, + "Number of log records that were dropped.", + stats.UnitDimensionless) +) diff --git a/internal/obsreportconfig/obsmetrics/obs_receiver.go b/internal/obsreportconfig/obsmetrics/obs_receiver.go new file mode 100644 index 00000000000..8cc7bf8b296 --- /dev/null +++ b/internal/obsreportconfig/obsmetrics/obs_receiver.go @@ -0,0 +1,86 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package obsmetrics + +import ( + "go.opencensus.io/stats" + "go.opencensus.io/tag" +) + +const ( + // ReceiverKey used to identify receivers in metrics and traces. + ReceiverKey = "receiver" + // TransportKey used to identify the transport used to received the data. + TransportKey = "transport" + // FormatKey used to identify the format of the data received. + FormatKey = "format" + + // AcceptedSpansKey used to identify spans accepted by the Collector. + AcceptedSpansKey = "accepted_spans" + // RefusedSpansKey used to identify spans refused (ie.: not ingested) by the Collector. + RefusedSpansKey = "refused_spans" + + // AcceptedMetricPointsKey used to identify metric points accepted by the Collector. + AcceptedMetricPointsKey = "accepted_metric_points" + // RefusedMetricPointsKey used to identify metric points refused (ie.: not ingested) by the + // Collector. + RefusedMetricPointsKey = "refused_metric_points" + + // AcceptedLogRecordsKey used to identify log records accepted by the Collector. + AcceptedLogRecordsKey = "accepted_log_records" + // RefusedLogRecordsKey used to identify log records refused (ie.: not ingested) by the + // Collector. + RefusedLogRecordsKey = "refused_log_records" +) + +var ( + TagKeyReceiver, _ = tag.NewKey(ReceiverKey) + TagKeyTransport, _ = tag.NewKey(TransportKey) + + ReceiverPrefix = ReceiverKey + NameSep + ReceiveTraceDataOperationSuffix = NameSep + "TraceDataReceived" + ReceiverMetricsOperationSuffix = NameSep + "MetricsReceived" + ReceiverLogsOperationSuffix = NameSep + "LogsReceived" + + // Receiver metrics. Any count of data items below is in the original format + // that they were received, reasoning: reconciliation is easier if measurement + // on clients and receiver are expected to be the same. Translation issues + // that result in a different number of elements should be reported in a + // separate way. + ReceiverAcceptedSpans = stats.Int64( + ReceiverPrefix+AcceptedSpansKey, + "Number of spans successfully pushed into the pipeline.", + stats.UnitDimensionless) + ReceiverRefusedSpans = stats.Int64( + ReceiverPrefix+RefusedSpansKey, + "Number of spans that could not be pushed into the pipeline.", + stats.UnitDimensionless) + ReceiverAcceptedMetricPoints = stats.Int64( + ReceiverPrefix+AcceptedMetricPointsKey, + "Number of metric points successfully pushed into the pipeline.", + stats.UnitDimensionless) + ReceiverRefusedMetricPoints = stats.Int64( + ReceiverPrefix+RefusedMetricPointsKey, + "Number of metric points that could not be pushed into the pipeline.", + stats.UnitDimensionless) + ReceiverAcceptedLogRecords = stats.Int64( + ReceiverPrefix+AcceptedLogRecordsKey, + "Number of log records successfully pushed into the pipeline.", + stats.UnitDimensionless) + ReceiverRefusedLogRecords = stats.Int64( + ReceiverPrefix+RefusedLogRecordsKey, + "Number of log records that could not be pushed into the pipeline.", + stats.UnitDimensionless) +) diff --git a/internal/obsreportconfig/obsmetrics/obs_scraper.go b/internal/obsreportconfig/obsmetrics/obs_scraper.go new file mode 100644 index 00000000000..dedbe4953ef --- /dev/null +++ b/internal/obsreportconfig/obsmetrics/obs_scraper.go @@ -0,0 +1,50 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package obsmetrics + +import ( + "go.opencensus.io/stats" + "go.opencensus.io/tag" +) + +const ( + // ScraperKey used to identify scrapers in metrics and traces. + ScraperKey = "scraper" + + // ScrapedMetricPointsKey used to identify metric points scraped by the + // Collector. + ScrapedMetricPointsKey = "scraped_metric_points" + // ErroredMetricPointsKey used to identify metric points errored (i.e. + // unable to be scraped) by the Collector. + ErroredMetricPointsKey = "errored_metric_points" +) + +const ( + ScraperPrefix = ScraperKey + NameSep + ScraperMetricsOperationSuffix = NameSep + "MetricsScraped" +) + +var ( + TagKeyScraper, _ = tag.NewKey(ScraperKey) + + ScraperScrapedMetricPoints = stats.Int64( + ScraperPrefix+ScrapedMetricPointsKey, + "Number of metric points successfully scraped.", + stats.UnitDimensionless) + ScraperErroredMetricPoints = stats.Int64( + ScraperPrefix+ErroredMetricPointsKey, + "Number of metric points that were unable to be scraped.", + stats.UnitDimensionless) +) diff --git a/internal/obsreportconfig/obsmetrics/obsmetrics.go b/internal/obsreportconfig/obsmetrics/obsmetrics.go new file mode 100644 index 00000000000..fe7ea208116 --- /dev/null +++ b/internal/obsreportconfig/obsmetrics/obsmetrics.go @@ -0,0 +1,22 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package obsmetrics defines the obsreport metrics for each components +// all the metrics is in OpenCensus format which will be replaced with OTEL Metrics +// in the future +package obsmetrics + +const ( + NameSep = "/" +) diff --git a/internal/obsreportconfig/obsreportconfig.go b/internal/obsreportconfig/obsreportconfig.go new file mode 100644 index 00000000000..da1ce262ff7 --- /dev/null +++ b/internal/obsreportconfig/obsreportconfig.go @@ -0,0 +1,124 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package obsreportconfig + +import ( + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" + + "go.opentelemetry.io/collector/config/configtelemetry" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" +) + +var ( + Level = configtelemetry.LevelBasic +) + +// ObsMetrics wraps OpenCensus View for Collector observability metrics +type ObsMetrics struct { + Views []*view.View +} + +// Configure is used to control the settings that will be used by the obsreport +// package. +func Configure(level configtelemetry.Level) *ObsMetrics { + Level = level + var views []*view.View + + if Level != configtelemetry.LevelNone { + obsMetricViews := allViews() + views = append(views, obsMetricViews.Views...) + } + + return &ObsMetrics{ + Views: views, + } +} + +// allViews return the list of all views that needs to be configured. +func allViews() *ObsMetrics { + var views []*view.View + // Receiver views. + measures := []*stats.Int64Measure{ + obsmetrics.ReceiverAcceptedSpans, + obsmetrics.ReceiverRefusedSpans, + obsmetrics.ReceiverAcceptedMetricPoints, + obsmetrics.ReceiverRefusedMetricPoints, + obsmetrics.ReceiverAcceptedLogRecords, + obsmetrics.ReceiverRefusedLogRecords, + } + tagKeys := []tag.Key{ + obsmetrics.TagKeyReceiver, obsmetrics.TagKeyTransport, + } + views = append(views, genViews(measures, tagKeys, view.Sum())...) + + // Scraper views. + measures = []*stats.Int64Measure{ + obsmetrics.ScraperScrapedMetricPoints, + obsmetrics.ScraperErroredMetricPoints, + } + tagKeys = []tag.Key{obsmetrics.TagKeyReceiver, obsmetrics.TagKeyScraper} + views = append(views, genViews(measures, tagKeys, view.Sum())...) + + // Exporter views. + measures = []*stats.Int64Measure{ + obsmetrics.ExporterSentSpans, + obsmetrics.ExporterFailedToSendSpans, + obsmetrics.ExporterSentMetricPoints, + obsmetrics.ExporterFailedToSendMetricPoints, + obsmetrics.ExporterSentLogRecords, + obsmetrics.ExporterFailedToSendLogRecords, + } + tagKeys = []tag.Key{obsmetrics.TagKeyExporter} + views = append(views, genViews(measures, tagKeys, view.Sum())...) + + // Processor views. + measures = []*stats.Int64Measure{ + obsmetrics.ProcessorAcceptedSpans, + obsmetrics.ProcessorRefusedSpans, + obsmetrics.ProcessorDroppedSpans, + obsmetrics.ProcessorAcceptedMetricPoints, + obsmetrics.ProcessorRefusedMetricPoints, + obsmetrics.ProcessorDroppedMetricPoints, + obsmetrics.ProcessorAcceptedLogRecords, + obsmetrics.ProcessorRefusedLogRecords, + obsmetrics.ProcessorDroppedLogRecords, + } + tagKeys = []tag.Key{obsmetrics.TagKeyProcessor} + views = append(views, genViews(measures, tagKeys, view.Sum())...) + + return &ObsMetrics{ + Views: views, + } +} + +func genViews( + measures []*stats.Int64Measure, + tagKeys []tag.Key, + aggregation *view.Aggregation, +) []*view.View { + views := make([]*view.View, 0, len(measures)) + for _, measure := range measures { + views = append(views, &view.View{ + Name: measure.Name(), + Description: measure.Description(), + TagKeys: tagKeys, + Measure: measure, + Aggregation: aggregation, + }) + } + return views +} diff --git a/internal/obsreportconfig/obsreportconfig_test.go b/internal/obsreportconfig/obsreportconfig_test.go new file mode 100644 index 00000000000..91a011b1902 --- /dev/null +++ b/internal/obsreportconfig/obsreportconfig_test.go @@ -0,0 +1,58 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package obsreportconfig + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "go.opencensus.io/stats/view" + + "go.opentelemetry.io/collector/config/configtelemetry" +) + +func TestConfigure(t *testing.T) { + tests := []struct { + name string + level configtelemetry.Level + wantViews []*view.View + }{ + { + name: "none", + level: configtelemetry.LevelNone, + }, + { + name: "basic", + level: configtelemetry.LevelBasic, + wantViews: allViews().Views, + }, + { + name: "normal", + level: configtelemetry.LevelNormal, + wantViews: allViews().Views, + }, + { + name: "detailed", + level: configtelemetry.LevelDetailed, + wantViews: allViews().Views, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotViews := Configure(tt.level) + assert.Equal(t, tt.wantViews, gotViews.Views) + }) + } +} diff --git a/internal/processor/filtermetric/config_test.go b/internal/processor/filtermetric/config_test.go index 274ae27bdc6..86cfa5f27bd 100644 --- a/internal/processor/filtermetric/config_test.go +++ b/internal/processor/filtermetric/config_test.go @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" "go.opentelemetry.io/collector/internal/processor/filterset" "go.opentelemetry.io/collector/internal/processor/filterset/regexp" ) @@ -48,7 +48,7 @@ func createConfigWithRegexpOptions(filters []string, rCfg *regexp.Config) *Match func TestConfig(t *testing.T) { testFile := path.Join(".", "testdata", "config.yaml") - v, err := config.NewParserFromFile(testFile) + v, err := configparser.NewParserFromFile(testFile) require.NoError(t, err) testYamls := map[string]MatchProperties{} require.NoErrorf(t, v.UnmarshalExact(&testYamls), "unable to unmarshal yaml from file %v", testFile) diff --git a/internal/processor/filterset/config_test.go b/internal/processor/filterset/config_test.go index 90b4647d3f5..f8a89a96bd9 100644 --- a/internal/processor/filterset/config_test.go +++ b/internal/processor/filterset/config_test.go @@ -21,13 +21,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" "go.opentelemetry.io/collector/internal/processor/filterset/regexp" ) func readTestdataConfigYamls(t *testing.T, filename string) map[string]*Config { testFile := path.Join(".", "testdata", filename) - v, err := config.NewParserFromFile(testFile) + v, err := configparser.NewParserFromFile(testFile) require.NoError(t, err) cfgs := map[string]*Config{} diff --git a/internal/processor/filterset/regexp/config_test.go b/internal/processor/filterset/regexp/config_test.go index 23fd9a9121f..313d5c1cc93 100644 --- a/internal/processor/filterset/regexp/config_test.go +++ b/internal/processor/filterset/regexp/config_test.go @@ -21,12 +21,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" ) func TestConfig(t *testing.T) { testFile := path.Join(".", "testdata", "config.yaml") - v, err := config.NewParserFromFile(testFile) + v, err := configparser.NewParserFromFile(testFile) require.NoError(t, err) actualConfigs := map[string]*Config{} diff --git a/internal/testcomponents/example_exporter.go b/internal/testcomponents/example_exporter.go index 3fcf225ded0..5543bc231cf 100644 --- a/internal/testcomponents/example_exporter.go +++ b/internal/testcomponents/example_exporter.go @@ -19,6 +19,7 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/pdata" "go.opentelemetry.io/collector/exporter/exporterhelper" @@ -37,7 +38,7 @@ type ExampleExporter struct { } // Unmarshal a viper data into the config struct -func (cfg *ExampleExporter) Unmarshal(componentParser *config.Parser) error { +func (cfg *ExampleExporter) Unmarshal(componentParser *configparser.Parser) error { return componentParser.UnmarshalExact(cfg) } diff --git a/obsreport/obsreport.go b/obsreport/obsreport.go index 8bab9ca1c55..c1e12804eb7 100644 --- a/obsreport/obsreport.go +++ b/obsreport/obsreport.go @@ -18,21 +18,12 @@ import ( "context" "strings" - "go.opencensus.io/stats" - "go.opencensus.io/stats/view" - "go.opencensus.io/tag" "go.opencensus.io/trace" - "go.opentelemetry.io/collector/config/configtelemetry" -) - -const ( - nameSep = "/" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" ) var ( - gLevel = configtelemetry.LevelBasic - okStatus = trace.Status{Code: trace.StatusCodeOK} ) @@ -60,99 +51,14 @@ func setParentLink(parentCtx context.Context, childSpan *trace.Span) bool { return true } -// Configure is used to control the settings that will be used by the obsreport -// package. -func Configure(level configtelemetry.Level) (views []*view.View) { - gLevel = level - - if gLevel != configtelemetry.LevelNone { - gProcessor.level = level - views = append(views, AllViews()...) - } - - return views -} - func buildComponentPrefix(componentPrefix, configType string) string { - if !strings.HasSuffix(componentPrefix, nameSep) { - componentPrefix += nameSep + if !strings.HasSuffix(componentPrefix, obsmetrics.NameSep) { + componentPrefix += obsmetrics.NameSep } if configType == "" { return componentPrefix } - return componentPrefix + configType + nameSep -} - -// AllViews return the list of all views that needs to be configured. -func AllViews() (views []*view.View) { - // Receiver views. - measures := []*stats.Int64Measure{ - mReceiverAcceptedSpans, - mReceiverRefusedSpans, - mReceiverAcceptedMetricPoints, - mReceiverRefusedMetricPoints, - mReceiverAcceptedLogRecords, - mReceiverRefusedLogRecords, - } - tagKeys := []tag.Key{ - tagKeyReceiver, tagKeyTransport, - } - views = append(views, genViews(measures, tagKeys, view.Sum())...) - - // Scraper views. - measures = []*stats.Int64Measure{ - mScraperScrapedMetricPoints, - mScraperErroredMetricPoints, - } - tagKeys = []tag.Key{tagKeyReceiver, tagKeyScraper} - views = append(views, genViews(measures, tagKeys, view.Sum())...) - - // Exporter views. - measures = []*stats.Int64Measure{ - mExporterSentSpans, - mExporterFailedToSendSpans, - mExporterSentMetricPoints, - mExporterFailedToSendMetricPoints, - mExporterSentLogRecords, - mExporterFailedToSendLogRecords, - } - tagKeys = []tag.Key{tagKeyExporter} - views = append(views, genViews(measures, tagKeys, view.Sum())...) - - // Processor views. - measures = []*stats.Int64Measure{ - mProcessorAcceptedSpans, - mProcessorRefusedSpans, - mProcessorDroppedSpans, - mProcessorAcceptedMetricPoints, - mProcessorRefusedMetricPoints, - mProcessorDroppedMetricPoints, - mProcessorAcceptedLogRecords, - mProcessorRefusedLogRecords, - mProcessorDroppedLogRecords, - } - tagKeys = []tag.Key{tagKeyProcessor} - views = append(views, genViews(measures, tagKeys, view.Sum())...) - - return views -} - -func genViews( - measures []*stats.Int64Measure, - tagKeys []tag.Key, - aggregation *view.Aggregation, -) []*view.View { - views := make([]*view.View, 0, len(measures)) - for _, measure := range measures { - views = append(views, &view.View{ - Name: measure.Name(), - Description: measure.Description(), - TagKeys: tagKeys, - Measure: measure, - Aggregation: aggregation, - }) - } - return views + return componentPrefix + configType + obsmetrics.NameSep } func errToStatus(err error) trace.Status { diff --git a/obsreport/obsreport_exporter.go b/obsreport/obsreport_exporter.go index 1d8f5497632..9671dce146e 100644 --- a/obsreport/obsreport_exporter.go +++ b/obsreport/obsreport_exporter.go @@ -23,65 +23,8 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configtelemetry" -) - -const ( - // ExporterKey used to identify exporters in metrics and traces. - ExporterKey = "exporter" - - // SentSpansKey used to track spans sent by exporters. - SentSpansKey = "sent_spans" - // FailedToSendSpansKey used to track spans that failed to be sent by exporters. - FailedToSendSpansKey = "send_failed_spans" - - // SentMetricPointsKey used to track metric points sent by exporters. - SentMetricPointsKey = "sent_metric_points" - // FailedToSendMetricPointsKey used to track metric points that failed to be sent by exporters. - FailedToSendMetricPointsKey = "send_failed_metric_points" - - // SentLogRecordsKey used to track logs sent by exporters. - SentLogRecordsKey = "sent_log_records" - // FailedToSendLogRecordsKey used to track logs that failed to be sent by exporters. - FailedToSendLogRecordsKey = "send_failed_log_records" -) - -var ( - tagKeyExporter, _ = tag.NewKey(ExporterKey) - - exporterPrefix = ExporterKey + nameSep - exportTraceDataOperationSuffix = nameSep + "traces" - exportMetricsOperationSuffix = nameSep + "metrics" - exportLogsOperationSuffix = nameSep + "logs" - - // Exporter metrics. Any count of data items below is in the final format - // that they were sent, reasoning: reconciliation is easier if measurements - // on backend and exporter are expected to be the same. Translation issues - // that result in a different number of elements should be reported in a - // separate way. - mExporterSentSpans = stats.Int64( - exporterPrefix+SentSpansKey, - "Number of spans successfully sent to destination.", - stats.UnitDimensionless) - mExporterFailedToSendSpans = stats.Int64( - exporterPrefix+FailedToSendSpansKey, - "Number of spans in failed attempts to send to destination.", - stats.UnitDimensionless) - mExporterSentMetricPoints = stats.Int64( - exporterPrefix+SentMetricPointsKey, - "Number of metric points successfully sent to destination.", - stats.UnitDimensionless) - mExporterFailedToSendMetricPoints = stats.Int64( - exporterPrefix+FailedToSendMetricPointsKey, - "Number of metric points in failed attempts to send to destination.", - stats.UnitDimensionless) - mExporterSentLogRecords = stats.Int64( - exporterPrefix+SentLogRecordsKey, - "Number of log record successfully sent to destination.", - stats.UnitDimensionless) - mExporterFailedToSendLogRecords = stats.Int64( - exporterPrefix+FailedToSendLogRecordsKey, - "Number of log records in failed attempts to send to destination.", - stats.UnitDimensionless) + "go.opentelemetry.io/collector/internal/obsreportconfig" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" ) // Exporter is a helper to add observability to a component.Exporter. @@ -102,7 +45,7 @@ func NewExporter(cfg ExporterSettings) *Exporter { return &Exporter{ level: cfg.Level, exporterName: cfg.ExporterID.String(), - mutators: []tag.Mutator{tag.Upsert(tagKeyExporter, cfg.ExporterID.String(), tag.WithTTL(tag.TTLNoPropagation))}, + mutators: []tag.Mutator{tag.Upsert(obsmetrics.TagKeyExporter, cfg.ExporterID.String(), tag.WithTTL(tag.TTLNoPropagation))}, } } @@ -110,55 +53,55 @@ func NewExporter(cfg ExporterSettings) *Exporter { // The returned context should be used in other calls to the Exporter functions // dealing with the same export operation. func (eor *Exporter) StartTracesExportOp(ctx context.Context) context.Context { - return eor.startSpan(ctx, exportTraceDataOperationSuffix) + return eor.startSpan(ctx, obsmetrics.ExportTraceDataOperationSuffix) } // EndTracesExportOp completes the export operation that was started with StartTracesExportOp. func (eor *Exporter) EndTracesExportOp(ctx context.Context, numSpans int, err error) { numSent, numFailedToSend := toNumItems(numSpans, err) - eor.recordMetrics(ctx, numSent, numFailedToSend, mExporterSentSpans, mExporterFailedToSendSpans) - endSpan(ctx, err, numSent, numFailedToSend, SentSpansKey, FailedToSendSpansKey) + eor.recordMetrics(ctx, numSent, numFailedToSend, obsmetrics.ExporterSentSpans, obsmetrics.ExporterFailedToSendSpans) + endSpan(ctx, err, numSent, numFailedToSend, obsmetrics.SentSpansKey, obsmetrics.FailedToSendSpansKey) } // StartMetricsExportOp is called at the start of an Export operation. // The returned context should be used in other calls to the Exporter functions // dealing with the same export operation. func (eor *Exporter) StartMetricsExportOp(ctx context.Context) context.Context { - return eor.startSpan(ctx, exportMetricsOperationSuffix) + return eor.startSpan(ctx, obsmetrics.ExportMetricsOperationSuffix) } // EndMetricsExportOp completes the export operation that was started with // StartMetricsExportOp. func (eor *Exporter) EndMetricsExportOp(ctx context.Context, numMetricPoints int, err error) { numSent, numFailedToSend := toNumItems(numMetricPoints, err) - eor.recordMetrics(ctx, numSent, numFailedToSend, mExporterSentMetricPoints, mExporterFailedToSendMetricPoints) - endSpan(ctx, err, numSent, numFailedToSend, SentMetricPointsKey, FailedToSendMetricPointsKey) + eor.recordMetrics(ctx, numSent, numFailedToSend, obsmetrics.ExporterSentMetricPoints, obsmetrics.ExporterFailedToSendMetricPoints) + endSpan(ctx, err, numSent, numFailedToSend, obsmetrics.SentMetricPointsKey, obsmetrics.FailedToSendMetricPointsKey) } // StartLogsExportOp is called at the start of an Export operation. // The returned context should be used in other calls to the Exporter functions // dealing with the same export operation. func (eor *Exporter) StartLogsExportOp(ctx context.Context) context.Context { - return eor.startSpan(ctx, exportLogsOperationSuffix) + return eor.startSpan(ctx, obsmetrics.ExportLogsOperationSuffix) } // EndLogsExportOp completes the export operation that was started with StartLogsExportOp. func (eor *Exporter) EndLogsExportOp(ctx context.Context, numLogRecords int, err error) { numSent, numFailedToSend := toNumItems(numLogRecords, err) - eor.recordMetrics(ctx, numSent, numFailedToSend, mExporterSentLogRecords, mExporterFailedToSendLogRecords) - endSpan(ctx, err, numSent, numFailedToSend, SentLogRecordsKey, FailedToSendLogRecordsKey) + eor.recordMetrics(ctx, numSent, numFailedToSend, obsmetrics.ExporterSentLogRecords, obsmetrics.ExporterFailedToSendLogRecords) + endSpan(ctx, err, numSent, numFailedToSend, obsmetrics.SentLogRecordsKey, obsmetrics.FailedToSendLogRecordsKey) } // startSpan creates the span used to trace the operation. Returning // the updated context and the created span. func (eor *Exporter) startSpan(ctx context.Context, operationSuffix string) context.Context { - spanName := exporterPrefix + eor.exporterName + operationSuffix + spanName := obsmetrics.ExporterPrefix + eor.exporterName + operationSuffix ctx, _ = trace.StartSpan(ctx, spanName) return ctx } func (eor *Exporter) recordMetrics(ctx context.Context, numSent, numFailedToSend int64, sentMeasure, failedToSendMeasure *stats.Int64Measure) { - if gLevel == configtelemetry.LevelNone { + if obsreportconfig.Level == configtelemetry.LevelNone { return } // Ignore the error for now. This should not happen. diff --git a/obsreport/obsreport_processor.go b/obsreport/obsreport_processor.go index e048f329bec..83a90f1bdca 100644 --- a/obsreport/obsreport_processor.go +++ b/obsreport/obsreport_processor.go @@ -23,79 +23,22 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configtelemetry" -) - -const ( - // ProcessorKey is the key used to identify processors in metrics and traces. - ProcessorKey = "processor" - - // DroppedSpansKey is the key used to identify spans dropped by the Collector. - DroppedSpansKey = "dropped_spans" - - // DroppedMetricPointsKey is the key used to identify metric points dropped by the Collector. - DroppedMetricPointsKey = "dropped_metric_points" - - // DroppedLogRecordsKey is the key used to identify log records dropped by the Collector. - DroppedLogRecordsKey = "dropped_log_records" -) - -var ( - tagKeyProcessor, _ = tag.NewKey(ProcessorKey) - - processorPrefix = ProcessorKey + nameSep - - // Processor metrics. Any count of data items below is in the internal format - // of the collector since processors only deal with internal format. - mProcessorAcceptedSpans = stats.Int64( - processorPrefix+AcceptedSpansKey, - "Number of spans successfully pushed into the next component in the pipeline.", - stats.UnitDimensionless) - mProcessorRefusedSpans = stats.Int64( - processorPrefix+RefusedSpansKey, - "Number of spans that were rejected by the next component in the pipeline.", - stats.UnitDimensionless) - mProcessorDroppedSpans = stats.Int64( - processorPrefix+DroppedSpansKey, - "Number of spans that were dropped.", - stats.UnitDimensionless) - mProcessorAcceptedMetricPoints = stats.Int64( - processorPrefix+AcceptedMetricPointsKey, - "Number of metric points successfully pushed into the next component in the pipeline.", - stats.UnitDimensionless) - mProcessorRefusedMetricPoints = stats.Int64( - processorPrefix+RefusedMetricPointsKey, - "Number of metric points that were rejected by the next component in the pipeline.", - stats.UnitDimensionless) - mProcessorDroppedMetricPoints = stats.Int64( - processorPrefix+DroppedMetricPointsKey, - "Number of metric points that were dropped.", - stats.UnitDimensionless) - mProcessorAcceptedLogRecords = stats.Int64( - processorPrefix+AcceptedLogRecordsKey, - "Number of log records successfully pushed into the next component in the pipeline.", - stats.UnitDimensionless) - mProcessorRefusedLogRecords = stats.Int64( - processorPrefix+RefusedLogRecordsKey, - "Number of log records that were rejected by the next component in the pipeline.", - stats.UnitDimensionless) - mProcessorDroppedLogRecords = stats.Int64( - processorPrefix+DroppedLogRecordsKey, - "Number of log records that were dropped.", - stats.UnitDimensionless) + "go.opentelemetry.io/collector/internal/obsreportconfig" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" ) // BuildProcessorCustomMetricName is used to be build a metric name following // the standards used in the Collector. The configType should be the same // value used to identify the type on the config. func BuildProcessorCustomMetricName(configType, metric string) string { - return buildComponentPrefix(processorPrefix, configType) + metric + return buildComponentPrefix(obsmetrics.ProcessorPrefix, configType) + metric } // ProcessorMetricViews builds the metric views for custom metrics of processors. -func ProcessorMetricViews(configType string, legacyViews []*view.View) []*view.View { +func ProcessorMetricViews(configType string, legacyViews *obsreportconfig.ObsMetrics) *obsreportconfig.ObsMetrics { var allViews []*view.View - if gLevel != configtelemetry.LevelNone { - for _, legacyView := range legacyViews { + if obsreportconfig.Level != configtelemetry.LevelNone { + for _, legacyView := range legacyViews.Views { // Ignore any nil entry and views without measure or aggregation. // These can't be registered but some code registering legacy views may // ignore the errors. @@ -112,11 +55,11 @@ func ProcessorMetricViews(configType string, legacyViews []*view.View) []*view.V } } - return allViews + return &obsreportconfig.ObsMetrics{ + Views: allViews, + } } -var gProcessor = &Processor{level: configtelemetry.LevelNone} - // Processor is a helper to add observability to a component.Processor. type Processor struct { level configtelemetry.Level @@ -133,7 +76,7 @@ type ProcessorSettings struct { func NewProcessor(cfg ProcessorSettings) *Processor { return &Processor{ level: cfg.Level, - mutators: []tag.Mutator{tag.Upsert(tagKeyProcessor, cfg.ProcessorID.String(), tag.WithTTL(tag.TTLNoPropagation))}, + mutators: []tag.Mutator{tag.Upsert(obsmetrics.TagKeyProcessor, cfg.ProcessorID.String(), tag.WithTTL(tag.TTLNoPropagation))}, } } @@ -143,9 +86,9 @@ func (por *Processor) TracesAccepted(ctx context.Context, numSpans int) { stats.RecordWithTags( ctx, por.mutators, - mProcessorAcceptedSpans.M(int64(numSpans)), - mProcessorRefusedSpans.M(0), - mProcessorDroppedSpans.M(0), + obsmetrics.ProcessorAcceptedSpans.M(int64(numSpans)), + obsmetrics.ProcessorRefusedSpans.M(0), + obsmetrics.ProcessorDroppedSpans.M(0), ) } } @@ -156,9 +99,9 @@ func (por *Processor) TracesRefused(ctx context.Context, numSpans int) { stats.RecordWithTags( ctx, por.mutators, - mProcessorAcceptedSpans.M(0), - mProcessorRefusedSpans.M(int64(numSpans)), - mProcessorDroppedSpans.M(0), + obsmetrics.ProcessorAcceptedSpans.M(0), + obsmetrics.ProcessorRefusedSpans.M(int64(numSpans)), + obsmetrics.ProcessorDroppedSpans.M(0), ) } } @@ -169,9 +112,9 @@ func (por *Processor) TracesDropped(ctx context.Context, numSpans int) { stats.RecordWithTags( ctx, por.mutators, - mProcessorAcceptedSpans.M(0), - mProcessorRefusedSpans.M(0), - mProcessorDroppedSpans.M(int64(numSpans)), + obsmetrics.ProcessorAcceptedSpans.M(0), + obsmetrics.ProcessorRefusedSpans.M(0), + obsmetrics.ProcessorDroppedSpans.M(int64(numSpans)), ) } } @@ -182,9 +125,9 @@ func (por *Processor) MetricsAccepted(ctx context.Context, numPoints int) { stats.RecordWithTags( ctx, por.mutators, - mProcessorAcceptedMetricPoints.M(int64(numPoints)), - mProcessorRefusedMetricPoints.M(0), - mProcessorDroppedMetricPoints.M(0), + obsmetrics.ProcessorAcceptedMetricPoints.M(int64(numPoints)), + obsmetrics.ProcessorRefusedMetricPoints.M(0), + obsmetrics.ProcessorDroppedMetricPoints.M(0), ) } } @@ -195,9 +138,9 @@ func (por *Processor) MetricsRefused(ctx context.Context, numPoints int) { stats.RecordWithTags( ctx, por.mutators, - mProcessorAcceptedMetricPoints.M(0), - mProcessorRefusedMetricPoints.M(int64(numPoints)), - mProcessorDroppedMetricPoints.M(0), + obsmetrics.ProcessorAcceptedMetricPoints.M(0), + obsmetrics.ProcessorRefusedMetricPoints.M(int64(numPoints)), + obsmetrics.ProcessorDroppedMetricPoints.M(0), ) } } @@ -208,9 +151,9 @@ func (por *Processor) MetricsDropped(ctx context.Context, numPoints int) { stats.RecordWithTags( ctx, por.mutators, - mProcessorAcceptedMetricPoints.M(0), - mProcessorRefusedMetricPoints.M(0), - mProcessorDroppedMetricPoints.M(int64(numPoints)), + obsmetrics.ProcessorAcceptedMetricPoints.M(0), + obsmetrics.ProcessorRefusedMetricPoints.M(0), + obsmetrics.ProcessorDroppedMetricPoints.M(int64(numPoints)), ) } } @@ -221,9 +164,9 @@ func (por *Processor) LogsAccepted(ctx context.Context, numRecords int) { stats.RecordWithTags( ctx, por.mutators, - mProcessorAcceptedLogRecords.M(int64(numRecords)), - mProcessorRefusedLogRecords.M(0), - mProcessorDroppedLogRecords.M(0), + obsmetrics.ProcessorAcceptedLogRecords.M(int64(numRecords)), + obsmetrics.ProcessorRefusedLogRecords.M(0), + obsmetrics.ProcessorDroppedLogRecords.M(0), ) } } @@ -234,9 +177,9 @@ func (por *Processor) LogsRefused(ctx context.Context, numRecords int) { stats.RecordWithTags( ctx, por.mutators, - mProcessorAcceptedLogRecords.M(0), - mProcessorRefusedLogRecords.M(int64(numRecords)), - mProcessorDroppedMetricPoints.M(0), + obsmetrics.ProcessorAcceptedLogRecords.M(0), + obsmetrics.ProcessorRefusedLogRecords.M(int64(numRecords)), + obsmetrics.ProcessorDroppedMetricPoints.M(0), ) } } @@ -247,9 +190,9 @@ func (por *Processor) LogsDropped(ctx context.Context, numRecords int) { stats.RecordWithTags( ctx, por.mutators, - mProcessorAcceptedLogRecords.M(0), - mProcessorRefusedLogRecords.M(0), - mProcessorDroppedLogRecords.M(int64(numRecords)), + obsmetrics.ProcessorAcceptedLogRecords.M(0), + obsmetrics.ProcessorRefusedLogRecords.M(0), + obsmetrics.ProcessorDroppedLogRecords.M(int64(numRecords)), ) } } diff --git a/obsreport/obsreport_receiver.go b/obsreport/obsreport_receiver.go index 4cf9eb3d080..7467a9cd5a8 100644 --- a/obsreport/obsreport_receiver.go +++ b/obsreport/obsreport_receiver.go @@ -23,72 +23,8 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configtelemetry" -) - -const ( - // ReceiverKey used to identify receivers in metrics and traces. - ReceiverKey = "receiver" - // TransportKey used to identify the transport used to received the data. - TransportKey = "transport" - // FormatKey used to identify the format of the data received. - FormatKey = "format" - - // AcceptedSpansKey used to identify spans accepted by the Collector. - AcceptedSpansKey = "accepted_spans" - // RefusedSpansKey used to identify spans refused (ie.: not ingested) by the Collector. - RefusedSpansKey = "refused_spans" - - // AcceptedMetricPointsKey used to identify metric points accepted by the Collector. - AcceptedMetricPointsKey = "accepted_metric_points" - // RefusedMetricPointsKey used to identify metric points refused (ie.: not ingested) by the - // Collector. - RefusedMetricPointsKey = "refused_metric_points" - - // AcceptedLogRecordsKey used to identify log records accepted by the Collector. - AcceptedLogRecordsKey = "accepted_log_records" - // RefusedLogRecordsKey used to identify log records refused (ie.: not ingested) by the - // Collector. - RefusedLogRecordsKey = "refused_log_records" -) - -var ( - tagKeyReceiver, _ = tag.NewKey(ReceiverKey) - tagKeyTransport, _ = tag.NewKey(TransportKey) - - receiverPrefix = ReceiverKey + nameSep - receiveTraceDataOperationSuffix = nameSep + "TraceDataReceived" - receiverMetricsOperationSuffix = nameSep + "MetricsReceived" - receiverLogsOperationSuffix = nameSep + "LogsReceived" - - // Receiver metrics. Any count of data items below is in the original format - // that they were received, reasoning: reconciliation is easier if measurements - // on clients and receiver are expected to be the same. Translation issues - // that result in a different number of elements should be reported in a - // separate way. - mReceiverAcceptedSpans = stats.Int64( - receiverPrefix+AcceptedSpansKey, - "Number of spans successfully pushed into the pipeline.", - stats.UnitDimensionless) - mReceiverRefusedSpans = stats.Int64( - receiverPrefix+RefusedSpansKey, - "Number of spans that could not be pushed into the pipeline.", - stats.UnitDimensionless) - mReceiverAcceptedMetricPoints = stats.Int64( - receiverPrefix+AcceptedMetricPointsKey, - "Number of metric points successfully pushed into the pipeline.", - stats.UnitDimensionless) - mReceiverRefusedMetricPoints = stats.Int64( - receiverPrefix+RefusedMetricPointsKey, - "Number of metric points that could not be pushed into the pipeline.", - stats.UnitDimensionless) - mReceiverAcceptedLogRecords = stats.Int64( - receiverPrefix+AcceptedLogRecordsKey, - "Number of log records successfully pushed into the pipeline.", - stats.UnitDimensionless) - mReceiverRefusedLogRecords = stats.Int64( - receiverPrefix+RefusedLogRecordsKey, - "Number of log records that could not be pushed into the pipeline.", - stats.UnitDimensionless) + "go.opentelemetry.io/collector/internal/obsreportconfig" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" ) // StartReceiveOptions has the options related to starting a receive operation. @@ -172,7 +108,7 @@ func (rec *Receiver) StartTraceDataReceiveOp( ) context.Context { return rec.traceReceiveOp( operationCtx, - receiveTraceDataOperationSuffix, + obsmetrics.ReceiveTraceDataOperationSuffix, opt...) } @@ -188,7 +124,7 @@ func StartTraceDataReceiveOp( rec := NewReceiver(ReceiverSettings{ReceiverID: receiverID, Transport: transport}) return rec.traceReceiveOp( operationCtx, - receiveTraceDataOperationSuffix, + obsmetrics.ReceiveTraceDataOperationSuffix, opt...) } @@ -236,7 +172,7 @@ func (rec *Receiver) StartLogsReceiveOp( ) context.Context { return rec.traceReceiveOp( operationCtx, - receiverLogsOperationSuffix, + obsmetrics.ReceiverLogsOperationSuffix, opt...) } @@ -252,7 +188,7 @@ func StartLogsReceiveOp( rec := NewReceiver(ReceiverSettings{ReceiverID: receiverID, Transport: transport}) return rec.traceReceiveOp( operationCtx, - receiverLogsOperationSuffix, + obsmetrics.ReceiverLogsOperationSuffix, opt...) } @@ -300,7 +236,7 @@ func (rec *Receiver) StartMetricsReceiveOp( ) context.Context { return rec.traceReceiveOp( operationCtx, - receiverMetricsOperationSuffix, + obsmetrics.ReceiverMetricsOperationSuffix, opt...) } @@ -316,7 +252,7 @@ func StartMetricsReceiveOp( rec := NewReceiver(ReceiverSettings{ReceiverID: receiverID, Transport: transport}) return rec.traceReceiveOp( operationCtx, - receiverMetricsOperationSuffix, + obsmetrics.ReceiverMetricsOperationSuffix, opt...) } @@ -365,8 +301,8 @@ func ReceiverContext( transport string, ) context.Context { ctx, _ = tag.New(ctx, - tag.Upsert(tagKeyReceiver, receiverID.String(), tag.WithTTL(tag.TTLNoPropagation)), - tag.Upsert(tagKeyTransport, transport, tag.WithTTL(tag.TTLNoPropagation))) + tag.Upsert(obsmetrics.TagKeyReceiver, receiverID.String(), tag.WithTTL(tag.TTLNoPropagation)), + tag.Upsert(obsmetrics.TagKeyTransport, transport, tag.WithTTL(tag.TTLNoPropagation))) return ctx } @@ -385,7 +321,7 @@ func (rec *Receiver) traceReceiveOp( var ctx context.Context var span *trace.Span - spanName := receiverPrefix + rec.receiverID.String() + operationSuffix + spanName := obsmetrics.ReceiverPrefix + rec.receiverID.String() + operationSuffix if !opts.LongLivedCtx { ctx, span = trace.StartSpan(receiverCtx, spanName) } else { @@ -401,7 +337,7 @@ func (rec *Receiver) traceReceiveOp( } if rec.transport != "" { - span.AddAttributes(trace.StringAttribute(TransportKey, rec.transport)) + span.AddAttributes(trace.StringAttribute(obsmetrics.TransportKey, rec.transport)) } return ctx } @@ -423,18 +359,18 @@ func (rec *Receiver) endReceiveOp( span := trace.FromContext(receiverCtx) - if gLevel != configtelemetry.LevelNone { + if obsreportconfig.Level != configtelemetry.LevelNone { var acceptedMeasure, refusedMeasure *stats.Int64Measure switch dataType { case config.TracesDataType: - acceptedMeasure = mReceiverAcceptedSpans - refusedMeasure = mReceiverRefusedSpans + acceptedMeasure = obsmetrics.ReceiverAcceptedSpans + refusedMeasure = obsmetrics.ReceiverRefusedSpans case config.MetricsDataType: - acceptedMeasure = mReceiverAcceptedMetricPoints - refusedMeasure = mReceiverRefusedMetricPoints + acceptedMeasure = obsmetrics.ReceiverAcceptedMetricPoints + refusedMeasure = obsmetrics.ReceiverRefusedMetricPoints case config.LogsDataType: - acceptedMeasure = mReceiverAcceptedLogRecords - refusedMeasure = mReceiverRefusedLogRecords + acceptedMeasure = obsmetrics.ReceiverAcceptedLogRecords + refusedMeasure = obsmetrics.ReceiverRefusedLogRecords } stats.Record( @@ -448,19 +384,19 @@ func (rec *Receiver) endReceiveOp( var acceptedItemsKey, refusedItemsKey string switch dataType { case config.TracesDataType: - acceptedItemsKey = AcceptedSpansKey - refusedItemsKey = RefusedSpansKey + acceptedItemsKey = obsmetrics.AcceptedSpansKey + refusedItemsKey = obsmetrics.RefusedSpansKey case config.MetricsDataType: - acceptedItemsKey = AcceptedMetricPointsKey - refusedItemsKey = RefusedMetricPointsKey + acceptedItemsKey = obsmetrics.AcceptedMetricPointsKey + refusedItemsKey = obsmetrics.RefusedMetricPointsKey case config.LogsDataType: - acceptedItemsKey = AcceptedLogRecordsKey - refusedItemsKey = RefusedLogRecordsKey + acceptedItemsKey = obsmetrics.AcceptedLogRecordsKey + refusedItemsKey = obsmetrics.RefusedLogRecordsKey } span.AddAttributes( trace.StringAttribute( - FormatKey, format), + obsmetrics.FormatKey, format), trace.Int64Attribute( acceptedItemsKey, int64(numAccepted)), trace.Int64Attribute( diff --git a/obsreport/obsreport_scraper.go b/obsreport/obsreport_scraper.go index d9d334eda23..362b5ea312e 100644 --- a/obsreport/obsreport_scraper.go +++ b/obsreport/obsreport_scraper.go @@ -23,39 +23,11 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configtelemetry" + "go.opentelemetry.io/collector/internal/obsreportconfig" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" "go.opentelemetry.io/collector/receiver/scrapererror" ) -const ( - // ScraperKey used to identify scrapers in metrics and traces. - ScraperKey = "scraper" - - // ScrapedMetricPointsKey used to identify metric points scraped by the - // Collector. - ScrapedMetricPointsKey = "scraped_metric_points" - // ErroredMetricPointsKey used to identify metric points errored (i.e. - // unable to be scraped) by the Collector. - ErroredMetricPointsKey = "errored_metric_points" -) - -const ( - scraperPrefix = ScraperKey + nameSep - scraperMetricsOperationSuffix = nameSep + "MetricsScraped" -) - -var ( - tagKeyScraper, _ = tag.NewKey(ScraperKey) - - mScraperScrapedMetricPoints = stats.Int64( - scraperPrefix+ScrapedMetricPointsKey, - "Number of metric points successfully scraped.", - stats.UnitDimensionless) - mScraperErroredMetricPoints = stats.Int64( - scraperPrefix+ErroredMetricPointsKey, - "Number of metric points that were unable to be scraped.", - stats.UnitDimensionless) -) - // ScraperContext adds the keys used when recording observability metrics to // the given context returning the newly created context. This context should // be used in related calls to the obsreport functions so metrics are properly @@ -67,8 +39,8 @@ func ScraperContext( ) context.Context { ctx, _ = tag.New( ctx, - tag.Upsert(tagKeyReceiver, receiverID.String(), tag.WithTTL(tag.TTLNoPropagation)), - tag.Upsert(tagKeyScraper, scraper.String(), tag.WithTTL(tag.TTLNoPropagation))) + tag.Upsert(obsmetrics.TagKeyReceiver, receiverID.String(), tag.WithTTL(tag.TTLNoPropagation)), + tag.Upsert(obsmetrics.TagKeyScraper, scraper.String(), tag.WithTTL(tag.TTLNoPropagation))) return ctx } @@ -81,7 +53,7 @@ func StartMetricsScrapeOp( receiverID config.ComponentID, scraper config.ComponentID, ) context.Context { - spanName := scraperPrefix + receiverID.String() + nameSep + scraper.String() + scraperMetricsOperationSuffix + spanName := obsmetrics.ScraperPrefix + receiverID.String() + obsmetrics.NameSep + scraper.String() + obsmetrics.ScraperMetricsOperationSuffix ctx, _ := trace.StartSpan(scraperCtx, spanName) return ctx } @@ -105,19 +77,19 @@ func EndMetricsScrapeOp( span := trace.FromContext(scraperCtx) - if gLevel != configtelemetry.LevelNone { + if obsreportconfig.Level != configtelemetry.LevelNone { stats.Record( scraperCtx, - mScraperScrapedMetricPoints.M(int64(numScrapedMetrics)), - mScraperErroredMetricPoints.M(int64(numErroredMetrics))) + obsmetrics.ScraperScrapedMetricPoints.M(int64(numScrapedMetrics)), + obsmetrics.ScraperErroredMetricPoints.M(int64(numErroredMetrics))) } // end span according to errors if span.IsRecordingEvents() { span.AddAttributes( - trace.StringAttribute(FormatKey, string(config.MetricsDataType)), - trace.Int64Attribute(ScrapedMetricPointsKey, int64(numScrapedMetrics)), - trace.Int64Attribute(ErroredMetricPointsKey, int64(numErroredMetrics)), + trace.StringAttribute(obsmetrics.FormatKey, string(config.MetricsDataType)), + trace.Int64Attribute(obsmetrics.ScrapedMetricPointsKey, int64(numScrapedMetrics)), + trace.Int64Attribute(obsmetrics.ErroredMetricPointsKey, int64(numErroredMetrics)), ) span.SetStatus(errToStatus(err)) diff --git a/obsreport/obsreport_test.go b/obsreport/obsreport_test.go index 6a28f7599f0..4acbce8ff18 100644 --- a/obsreport/obsreport_test.go +++ b/obsreport/obsreport_test.go @@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// obsreport_test instead of just obsreport to avoid dependency cycle between -// obsreport_test and obsreporttest -package obsreport_test +package obsreport import ( "context" @@ -30,7 +28,8 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configtelemetry" - "go.opentelemetry.io/collector/obsreport" + "go.opentelemetry.io/collector/internal/obsreportconfig" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" "go.opentelemetry.io/collector/obsreport/obsreporttest" "go.opentelemetry.io/collector/receiver/scrapererror" ) @@ -55,40 +54,6 @@ type receiveTestParams struct { err error } -func TestConfigure(t *testing.T) { - tests := []struct { - name string - level configtelemetry.Level - wantViews []*view.View - }{ - { - name: "none", - level: configtelemetry.LevelNone, - }, - { - name: "basic", - level: configtelemetry.LevelBasic, - wantViews: obsreport.AllViews(), - }, - { - name: "normal", - level: configtelemetry.LevelNormal, - wantViews: obsreport.AllViews(), - }, - { - name: "detailed", - level: configtelemetry.LevelDetailed, - wantViews: obsreport.AllViews(), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotViews := obsreport.Configure(tt.level) - assert.Equal(t, tt.wantViews, gotViews) - }) - } -} - func TestReceiveTraceDataOp(t *testing.T) { doneFn, err := obsreporttest.SetupRecordedMetricsTest() require.NoError(t, err) @@ -102,14 +67,14 @@ func TestReceiveTraceDataOp(t *testing.T) { t.Name(), trace.WithSampler(trace.AlwaysSample())) defer parentSpan.End() - receiverCtx := obsreport.ReceiverContext(parentCtx, receiver, transport) + receiverCtx := ReceiverContext(parentCtx, receiver, transport) params := []receiveTestParams{ {transport, errFake}, {"", nil}, } rcvdSpans := []int{13, 42} for i, param := range params { - rec := obsreport.NewReceiver(obsreport.ReceiverSettings{ReceiverID: receiver, Transport: param.transport}) + rec := NewReceiver(ReceiverSettings{ReceiverID: receiver, Transport: param.transport}) ctx := rec.StartTraceDataReceiveOp(receiverCtx) assert.NotNil(t, ctx) @@ -129,22 +94,22 @@ func TestReceiveTraceDataOp(t *testing.T) { switch params[i].err { case nil: acceptedSpans += rcvdSpans[i] - assert.Equal(t, int64(rcvdSpans[i]), span.Attributes[obsreport.AcceptedSpansKey]) - assert.Equal(t, int64(0), span.Attributes[obsreport.RefusedSpansKey]) + assert.Equal(t, int64(rcvdSpans[i]), span.Attributes[obsmetrics.AcceptedSpansKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.RefusedSpansKey]) assert.Equal(t, trace.Status{Code: trace.StatusCodeOK}, span.Status) case errFake: refusedSpans += rcvdSpans[i] - assert.Equal(t, int64(0), span.Attributes[obsreport.AcceptedSpansKey]) - assert.Equal(t, int64(rcvdSpans[i]), span.Attributes[obsreport.RefusedSpansKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.AcceptedSpansKey]) + assert.Equal(t, int64(rcvdSpans[i]), span.Attributes[obsmetrics.RefusedSpansKey]) assert.Equal(t, params[i].err.Error(), span.Status.Message) default: t.Fatalf("unexpected param: %v", params[i]) } switch params[i].transport { case "": - assert.NotContains(t, span.Attributes, obsreport.TransportKey) + assert.NotContains(t, span.Attributes, obsmetrics.TransportKey) default: - assert.Equal(t, params[i].transport, span.Attributes[obsreport.TransportKey]) + assert.Equal(t, params[i].transport, span.Attributes[obsmetrics.TransportKey]) } } obsreporttest.CheckReceiverTraces(t, receiver, transport, int64(acceptedSpans), int64(refusedSpans)) @@ -163,14 +128,14 @@ func TestReceiveLogsOp(t *testing.T) { t.Name(), trace.WithSampler(trace.AlwaysSample())) defer parentSpan.End() - receiverCtx := obsreport.ReceiverContext(parentCtx, receiver, transport) + receiverCtx := ReceiverContext(parentCtx, receiver, transport) params := []receiveTestParams{ {transport, errFake}, {"", nil}, } rcvdLogRecords := []int{13, 42} for i, param := range params { - rec := obsreport.NewReceiver(obsreport.ReceiverSettings{ReceiverID: receiver, Transport: param.transport}) + rec := NewReceiver(ReceiverSettings{ReceiverID: receiver, Transport: param.transport}) ctx := rec.StartLogsReceiveOp(receiverCtx) assert.NotNil(t, ctx) @@ -190,22 +155,22 @@ func TestReceiveLogsOp(t *testing.T) { switch params[i].err { case nil: acceptedLogRecords += rcvdLogRecords[i] - assert.Equal(t, int64(rcvdLogRecords[i]), span.Attributes[obsreport.AcceptedLogRecordsKey]) - assert.Equal(t, int64(0), span.Attributes[obsreport.RefusedLogRecordsKey]) + assert.Equal(t, int64(rcvdLogRecords[i]), span.Attributes[obsmetrics.AcceptedLogRecordsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.RefusedLogRecordsKey]) assert.Equal(t, trace.Status{Code: trace.StatusCodeOK}, span.Status) case errFake: refusedLogRecords += rcvdLogRecords[i] - assert.Equal(t, int64(0), span.Attributes[obsreport.AcceptedLogRecordsKey]) - assert.Equal(t, int64(rcvdLogRecords[i]), span.Attributes[obsreport.RefusedLogRecordsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.AcceptedLogRecordsKey]) + assert.Equal(t, int64(rcvdLogRecords[i]), span.Attributes[obsmetrics.RefusedLogRecordsKey]) assert.Equal(t, params[i].err.Error(), span.Status.Message) default: t.Fatalf("unexpected param: %v", params[i]) } switch params[i].transport { case "": - assert.NotContains(t, span.Attributes, obsreport.TransportKey) + assert.NotContains(t, span.Attributes, obsmetrics.TransportKey) default: - assert.Equal(t, params[i].transport, span.Attributes[obsreport.TransportKey]) + assert.Equal(t, params[i].transport, span.Attributes[obsmetrics.TransportKey]) } } obsreporttest.CheckReceiverLogs(t, receiver, transport, int64(acceptedLogRecords), int64(refusedLogRecords)) @@ -224,14 +189,14 @@ func TestReceiveMetricsOp(t *testing.T) { t.Name(), trace.WithSampler(trace.AlwaysSample())) defer parentSpan.End() - receiverCtx := obsreport.ReceiverContext(parentCtx, receiver, transport) + receiverCtx := ReceiverContext(parentCtx, receiver, transport) params := []receiveTestParams{ {transport, errFake}, {"", nil}, } rcvdMetricPts := []int{23, 29} for i, param := range params { - rec := obsreport.NewReceiver(obsreport.ReceiverSettings{ReceiverID: receiver, Transport: param.transport}) + rec := NewReceiver(ReceiverSettings{ReceiverID: receiver, Transport: param.transport}) ctx := rec.StartMetricsReceiveOp(receiverCtx) assert.NotNil(t, ctx) @@ -251,22 +216,22 @@ func TestReceiveMetricsOp(t *testing.T) { switch params[i].err { case nil: acceptedMetricPoints += rcvdMetricPts[i] - assert.Equal(t, int64(rcvdMetricPts[i]), span.Attributes[obsreport.AcceptedMetricPointsKey]) - assert.Equal(t, int64(0), span.Attributes[obsreport.RefusedMetricPointsKey]) + assert.Equal(t, int64(rcvdMetricPts[i]), span.Attributes[obsmetrics.AcceptedMetricPointsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.RefusedMetricPointsKey]) assert.Equal(t, trace.Status{Code: trace.StatusCodeOK}, span.Status) case errFake: refusedMetricPoints += rcvdMetricPts[i] - assert.Equal(t, int64(0), span.Attributes[obsreport.AcceptedMetricPointsKey]) - assert.Equal(t, int64(rcvdMetricPts[i]), span.Attributes[obsreport.RefusedMetricPointsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.AcceptedMetricPointsKey]) + assert.Equal(t, int64(rcvdMetricPts[i]), span.Attributes[obsmetrics.RefusedMetricPointsKey]) assert.Equal(t, params[i].err.Error(), span.Status.Message) default: t.Fatalf("unexpected param: %v", params[i]) } switch params[i].transport { case "": - assert.NotContains(t, span.Attributes, obsreport.TransportKey) + assert.NotContains(t, span.Attributes, obsmetrics.TransportKey) default: - assert.Equal(t, params[i].transport, span.Attributes[obsreport.TransportKey]) + assert.Equal(t, params[i].transport, span.Attributes[obsmetrics.TransportKey]) } } @@ -286,14 +251,14 @@ func TestScrapeMetricsDataOp(t *testing.T) { t.Name(), trace.WithSampler(trace.AlwaysSample())) defer parentSpan.End() - receiverCtx := obsreport.ScraperContext(parentCtx, receiver, scraper) + receiverCtx := ScraperContext(parentCtx, receiver, scraper) errParams := []error{partialErrFake, errFake, nil} scrapedMetricPts := []int{23, 29, 15} for i, err := range errParams { - ctx := obsreport.StartMetricsScrapeOp(receiverCtx, receiver, scraper) + ctx := StartMetricsScrapeOp(receiverCtx, receiver, scraper) assert.NotNil(t, ctx) - obsreport.EndMetricsScrapeOp( + EndMetricsScrapeOp( ctx, scrapedMetricPts[i], err) @@ -308,19 +273,19 @@ func TestScrapeMetricsDataOp(t *testing.T) { switch errParams[i] { case nil: scrapedMetricPoints += scrapedMetricPts[i] - assert.Equal(t, int64(scrapedMetricPts[i]), span.Attributes[obsreport.ScrapedMetricPointsKey]) - assert.Equal(t, int64(0), span.Attributes[obsreport.ErroredMetricPointsKey]) + assert.Equal(t, int64(scrapedMetricPts[i]), span.Attributes[obsmetrics.ScrapedMetricPointsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.ErroredMetricPointsKey]) assert.Equal(t, trace.Status{Code: trace.StatusCodeOK}, span.Status) case errFake: erroredMetricPoints += scrapedMetricPts[i] - assert.Equal(t, int64(0), span.Attributes[obsreport.ScrapedMetricPointsKey]) - assert.Equal(t, int64(scrapedMetricPts[i]), span.Attributes[obsreport.ErroredMetricPointsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.ScrapedMetricPointsKey]) + assert.Equal(t, int64(scrapedMetricPts[i]), span.Attributes[obsmetrics.ErroredMetricPointsKey]) assert.Equal(t, errParams[i].Error(), span.Status.Message) case partialErrFake: scrapedMetricPoints += scrapedMetricPts[i] erroredMetricPoints++ - assert.Equal(t, int64(scrapedMetricPts[i]), span.Attributes[obsreport.ScrapedMetricPointsKey]) - assert.Equal(t, int64(1), span.Attributes[obsreport.ErroredMetricPointsKey]) + assert.Equal(t, int64(scrapedMetricPts[i]), span.Attributes[obsmetrics.ScrapedMetricPointsKey]) + assert.Equal(t, int64(1), span.Attributes[obsmetrics.ErroredMetricPointsKey]) assert.Equal(t, errParams[i].Error(), span.Status.Message) default: t.Fatalf("unexpected err param: %v", errParams[i]) @@ -343,7 +308,7 @@ func TestExportTraceDataOp(t *testing.T) { t.Name(), trace.WithSampler(trace.AlwaysSample())) defer parentSpan.End() - obsrep := obsreport.NewExporter(obsreport.ExporterSettings{Level: configtelemetry.LevelNormal, ExporterID: exporter}) + obsrep := NewExporter(ExporterSettings{Level: configtelemetry.LevelNormal, ExporterID: exporter}) errs := []error{nil, errFake} numExportedSpans := []int{22, 14} for i, err := range errs { @@ -361,13 +326,13 @@ func TestExportTraceDataOp(t *testing.T) { switch errs[i] { case nil: sentSpans += numExportedSpans[i] - assert.Equal(t, int64(numExportedSpans[i]), span.Attributes[obsreport.SentSpansKey]) - assert.Equal(t, int64(0), span.Attributes[obsreport.FailedToSendSpansKey]) + assert.Equal(t, int64(numExportedSpans[i]), span.Attributes[obsmetrics.SentSpansKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.FailedToSendSpansKey]) assert.Equal(t, trace.Status{Code: trace.StatusCodeOK}, span.Status) case errFake: failedToSendSpans += numExportedSpans[i] - assert.Equal(t, int64(0), span.Attributes[obsreport.SentSpansKey]) - assert.Equal(t, int64(numExportedSpans[i]), span.Attributes[obsreport.FailedToSendSpansKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.SentSpansKey]) + assert.Equal(t, int64(numExportedSpans[i]), span.Attributes[obsmetrics.FailedToSendSpansKey]) assert.Equal(t, errs[i].Error(), span.Status.Message) default: t.Fatalf("unexpected error: %v", errs[i]) @@ -390,7 +355,7 @@ func TestExportMetricsOp(t *testing.T) { t.Name(), trace.WithSampler(trace.AlwaysSample())) defer parentSpan.End() - obsrep := obsreport.NewExporter(obsreport.ExporterSettings{Level: configtelemetry.LevelNormal, ExporterID: exporter}) + obsrep := NewExporter(ExporterSettings{Level: configtelemetry.LevelNormal, ExporterID: exporter}) errs := []error{nil, errFake} toSendMetricPoints := []int{17, 23} @@ -410,13 +375,13 @@ func TestExportMetricsOp(t *testing.T) { switch errs[i] { case nil: sentMetricPoints += toSendMetricPoints[i] - assert.Equal(t, int64(toSendMetricPoints[i]), span.Attributes[obsreport.SentMetricPointsKey]) - assert.Equal(t, int64(0), span.Attributes[obsreport.FailedToSendMetricPointsKey]) + assert.Equal(t, int64(toSendMetricPoints[i]), span.Attributes[obsmetrics.SentMetricPointsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.FailedToSendMetricPointsKey]) assert.Equal(t, trace.Status{Code: trace.StatusCodeOK}, span.Status) case errFake: failedToSendMetricPoints += toSendMetricPoints[i] - assert.Equal(t, int64(0), span.Attributes[obsreport.SentMetricPointsKey]) - assert.Equal(t, int64(toSendMetricPoints[i]), span.Attributes[obsreport.FailedToSendMetricPointsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.SentMetricPointsKey]) + assert.Equal(t, int64(toSendMetricPoints[i]), span.Attributes[obsmetrics.FailedToSendMetricPointsKey]) assert.Equal(t, errs[i].Error(), span.Status.Message) default: t.Fatalf("unexpected error: %v", errs[i]) @@ -439,7 +404,7 @@ func TestExportLogsOp(t *testing.T) { t.Name(), trace.WithSampler(trace.AlwaysSample())) defer parentSpan.End() - obsrep := obsreport.NewExporter(obsreport.ExporterSettings{Level: configtelemetry.LevelNormal, ExporterID: exporter}) + obsrep := NewExporter(ExporterSettings{Level: configtelemetry.LevelNormal, ExporterID: exporter}) errs := []error{nil, errFake} toSendLogRecords := []int{17, 23} for i, err := range errs { @@ -458,13 +423,13 @@ func TestExportLogsOp(t *testing.T) { switch errs[i] { case nil: sentLogRecords += toSendLogRecords[i] - assert.Equal(t, int64(toSendLogRecords[i]), span.Attributes[obsreport.SentLogRecordsKey]) - assert.Equal(t, int64(0), span.Attributes[obsreport.FailedToSendLogRecordsKey]) + assert.Equal(t, int64(toSendLogRecords[i]), span.Attributes[obsmetrics.SentLogRecordsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.FailedToSendLogRecordsKey]) assert.Equal(t, trace.Status{Code: trace.StatusCodeOK}, span.Status) case errFake: failedToSendLogRecords += toSendLogRecords[i] - assert.Equal(t, int64(0), span.Attributes[obsreport.SentLogRecordsKey]) - assert.Equal(t, int64(toSendLogRecords[i]), span.Attributes[obsreport.FailedToSendLogRecordsKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.SentLogRecordsKey]) + assert.Equal(t, int64(toSendLogRecords[i]), span.Attributes[obsmetrics.FailedToSendLogRecordsKey]) assert.Equal(t, errs[i].Error(), span.Status.Message) default: t.Fatalf("unexpected error: %v", errs[i]) @@ -491,7 +456,7 @@ func TestReceiveWithLongLivedCtx(t *testing.T) { parentCtx, parentSpan := trace.StartSpan(context.Background(), t.Name()) defer parentSpan.End() - longLivedCtx := obsreport.ReceiverContext(parentCtx, receiver, transport) + longLivedCtx := ReceiverContext(parentCtx, receiver, transport) ops := []struct { numSpans int err error @@ -502,10 +467,10 @@ func TestReceiveWithLongLivedCtx(t *testing.T) { for _, op := range ops { // Use a new context on each operation to simulate distinct operations // under the same long lived context. - rec := obsreport.NewReceiver(obsreport.ReceiverSettings{ReceiverID: receiver, Transport: transport}) + rec := NewReceiver(ReceiverSettings{ReceiverID: receiver, Transport: transport}) ctx := rec.StartTraceDataReceiveOp( longLivedCtx, - obsreport.WithLongLivedCtx()) + WithLongLivedCtx()) assert.NotNil(t, ctx) rec.EndTraceDataReceiveOp( @@ -526,15 +491,15 @@ func TestReceiveWithLongLivedCtx(t *testing.T) { assert.Equal(t, parentSpan.SpanContext().TraceID, link.TraceID) assert.Equal(t, parentSpan.SpanContext().SpanID, link.SpanID) assert.Equal(t, "receiver/"+receiver.String()+"/TraceDataReceived", span.Name) - assert.Equal(t, transport, span.Attributes[obsreport.TransportKey]) + assert.Equal(t, transport, span.Attributes[obsmetrics.TransportKey]) switch ops[i].err { case nil: - assert.Equal(t, int64(ops[i].numSpans), span.Attributes[obsreport.AcceptedSpansKey]) - assert.Equal(t, int64(0), span.Attributes[obsreport.RefusedSpansKey]) + assert.Equal(t, int64(ops[i].numSpans), span.Attributes[obsmetrics.AcceptedSpansKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.RefusedSpansKey]) assert.Equal(t, trace.Status{Code: trace.StatusCodeOK}, span.Status) case errFake: - assert.Equal(t, int64(0), span.Attributes[obsreport.AcceptedSpansKey]) - assert.Equal(t, int64(ops[i].numSpans), span.Attributes[obsreport.RefusedSpansKey]) + assert.Equal(t, int64(0), span.Attributes[obsmetrics.AcceptedSpansKey]) + assert.Equal(t, int64(ops[i].numSpans), span.Attributes[obsmetrics.RefusedSpansKey]) assert.Equal(t, ops[i].err.Error(), span.Status.Message) default: t.Fatalf("unexpected error: %v", ops[i].err) @@ -551,7 +516,7 @@ func TestProcessorTraceData(t *testing.T) { const refusedSpans = 19 const droppedSpans = 13 - obsrep := obsreport.NewProcessor(obsreport.ProcessorSettings{Level: configtelemetry.LevelNormal, ProcessorID: processor}) + obsrep := NewProcessor(ProcessorSettings{Level: configtelemetry.LevelNormal, ProcessorID: processor}) obsrep.TracesAccepted(context.Background(), acceptedSpans) obsrep.TracesRefused(context.Background(), refusedSpans) obsrep.TracesDropped(context.Background(), droppedSpans) @@ -568,7 +533,7 @@ func TestProcessorMetricsData(t *testing.T) { const refusedPoints = 11 const droppedPoints = 17 - obsrep := obsreport.NewProcessor(obsreport.ProcessorSettings{Level: configtelemetry.LevelNormal, ProcessorID: processor}) + obsrep := NewProcessor(ProcessorSettings{Level: configtelemetry.LevelNormal, ProcessorID: processor}) obsrep.MetricsAccepted(context.Background(), acceptedPoints) obsrep.MetricsRefused(context.Background(), refusedPoints) obsrep.MetricsDropped(context.Background(), droppedPoints) @@ -623,9 +588,9 @@ func TestProcessorMetricViews(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - obsreport.Configure(tt.level) - got := obsreport.ProcessorMetricViews("test_type", legacyViews) - assert.Equal(t, tt.want, got) + obsreportconfig.Configure(tt.level) + got := ProcessorMetricViews("test_type", &obsreportconfig.ObsMetrics{Views: legacyViews}) + assert.Equal(t, tt.want, got.Views) }) } } @@ -639,7 +604,7 @@ func TestProcessorLogRecords(t *testing.T) { const refusedRecords = 11 const droppedRecords = 17 - obsrep := obsreport.NewProcessor(obsreport.ProcessorSettings{Level: configtelemetry.LevelNormal, ProcessorID: processor}) + obsrep := NewProcessor(ProcessorSettings{Level: configtelemetry.LevelNormal, ProcessorID: processor}) obsrep.LogsAccepted(context.Background(), acceptedRecords) obsrep.LogsRefused(context.Background(), refusedRecords) obsrep.LogsDropped(context.Background(), droppedRecords) diff --git a/obsreport/obsreporttest/obsreporttest.go b/obsreport/obsreporttest/obsreporttest.go index d7b5d701077..e0ca299cd0d 100644 --- a/obsreport/obsreporttest/obsreporttest.go +++ b/obsreport/obsreporttest/obsreporttest.go @@ -25,7 +25,7 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configtelemetry" - "go.opentelemetry.io/collector/obsreport" + "go.opentelemetry.io/collector/internal/obsreportconfig" ) var ( @@ -45,7 +45,8 @@ var ( // SetupRecordedMetricsTest does setup the testing environment to check the metrics recorded by receivers, producers or exporters. // The returned function should be deferred. func SetupRecordedMetricsTest() (func(), error) { - views := obsreport.Configure(configtelemetry.LevelNormal) + obsMetrics := obsreportconfig.Configure(configtelemetry.LevelNormal) + views := obsMetrics.Views err := view.Register(views...) if err != nil { return nil, err diff --git a/processor/batchprocessor/metrics.go b/processor/batchprocessor/metrics.go index 6dbeee02569..96ae457ec5d 100644 --- a/processor/batchprocessor/metrics.go +++ b/processor/batchprocessor/metrics.go @@ -19,11 +19,13 @@ import ( "go.opencensus.io/stats/view" "go.opencensus.io/tag" + "go.opentelemetry.io/collector/internal/obsreportconfig" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" "go.opentelemetry.io/collector/obsreport" ) var ( - processorTagKey = tag.MustNewKey(obsreport.ProcessorKey) + processorTagKey = tag.MustNewKey(obsmetrics.ProcessorKey) statBatchSizeTriggerSend = stats.Int64("batch_size_trigger_send", "Number of times the batch was sent due to a size trigger", stats.UnitDimensionless) statTimeoutTriggerSend = stats.Int64("timeout_trigger_send", "Number of times the batch was sent due to a timeout trigger", stats.UnitDimensionless) statBatchSendSize = stats.Int64("batch_send_size", "Number of units in the batch", stats.UnitDimensionless) @@ -68,12 +70,14 @@ func MetricViews() []*view.View { 1000_000, 2000_000, 3000_000, 4000_000, 5000_000, 6000_000, 7000_000, 8000_000, 9000_000), } - legacyViews := []*view.View{ - countBatchSizeTriggerSendView, - countTimeoutTriggerSendView, - distributionBatchSendSizeView, - distributionBatchSendSizeBytesView, + legacyViews := &obsreportconfig.ObsMetrics{ + Views: []*view.View{ + countBatchSizeTriggerSendView, + countTimeoutTriggerSendView, + distributionBatchSendSizeView, + distributionBatchSendSizeBytesView, + }, } - return obsreport.ProcessorMetricViews(typeStr, legacyViews) + return obsreport.ProcessorMetricViews(typeStr, legacyViews).Views } diff --git a/processor/processorhelper/processor.go b/processor/processorhelper/processor.go index b8151b100d9..449e0645612 100644 --- a/processor/processorhelper/processor.go +++ b/processor/processorhelper/processor.go @@ -23,7 +23,7 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumerhelper" - "go.opentelemetry.io/collector/obsreport" + "go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics" ) // ErrSkipProcessingData is a sentinel value to indicate when traces or metrics should intentionally be dropped @@ -79,6 +79,6 @@ func fromOptions(options []Option) *baseSettings { func spanAttributes(id config.ComponentID) []trace.Attribute { return []trace.Attribute{ - trace.StringAttribute(obsreport.ProcessorKey, id.String()), + trace.StringAttribute(obsmetrics.ProcessorKey, id.String()), } } diff --git a/receiver/hostmetricsreceiver/config.go b/receiver/hostmetricsreceiver/config.go index 9c292e26797..7cf61ff84f0 100644 --- a/receiver/hostmetricsreceiver/config.go +++ b/receiver/hostmetricsreceiver/config.go @@ -21,6 +21,7 @@ import ( "github.com/spf13/cast" "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" "go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal" "go.opentelemetry.io/collector/receiver/scraperhelper" ) @@ -48,7 +49,7 @@ func (cfg *Config) Validate() error { } // Unmarshal a config.Parser into the config struct. -func (cfg *Config) Unmarshal(componentParser *config.Parser) error { +func (cfg *Config) Unmarshal(componentParser *configparser.Parser) error { if componentParser == nil { return nil } diff --git a/receiver/jaegerreceiver/config.go b/receiver/jaegerreceiver/config.go index 51ab6352d63..f08387dd262 100644 --- a/receiver/jaegerreceiver/config.go +++ b/receiver/jaegerreceiver/config.go @@ -22,6 +22,7 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/configparser" ) const ( @@ -96,7 +97,7 @@ func (cfg *Config) Validate() error { } // Unmarshal a config.Parser into the config struct. -func (cfg *Config) Unmarshal(componentParser *config.Parser) error { +func (cfg *Config) Unmarshal(componentParser *configparser.Parser) error { if componentParser == nil || len(componentParser.AllKeys()) == 0 { return fmt.Errorf("empty config for Jaeger receiver") } diff --git a/receiver/otlpreceiver/config.go b/receiver/otlpreceiver/config.go index 19f9faabe99..e22a0169327 100644 --- a/receiver/otlpreceiver/config.go +++ b/receiver/otlpreceiver/config.go @@ -22,6 +22,7 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/configparser" ) const ( @@ -57,7 +58,7 @@ func (cfg *Config) Validate() error { } // Unmarshal a config.Parser into the config struct. -func (cfg *Config) Unmarshal(componentParser *config.Parser) error { +func (cfg *Config) Unmarshal(componentParser *configparser.Parser) error { if componentParser == nil || len(componentParser.AllKeys()) == 0 { return fmt.Errorf("empty config for OTLP receiver") } diff --git a/receiver/prometheusreceiver/config.go b/receiver/prometheusreceiver/config.go index c8dfd35f287..d7080de38f4 100644 --- a/receiver/prometheusreceiver/config.go +++ b/receiver/prometheusreceiver/config.go @@ -23,6 +23,7 @@ import ( "gopkg.in/yaml.v2" "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" ) const ( @@ -57,7 +58,7 @@ func (cfg *Config) Validate() error { } // Unmarshal a config.Parser into the config struct. -func (cfg *Config) Unmarshal(componentParser *config.Parser) error { +func (cfg *Config) Unmarshal(componentParser *configparser.Parser) error { if componentParser == nil { return nil } diff --git a/service/application_test.go b/service/application_test.go index 61afc86ca58..44dc273a7cf 100644 --- a/service/application_test.go +++ b/service/application_test.go @@ -34,7 +34,7 @@ import ( "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" "go.opentelemetry.io/collector/service/defaultcomponents" "go.opentelemetry.io/collector/service/internal/builder" "go.opentelemetry.io/collector/service/parserprovider" @@ -247,7 +247,7 @@ func assertZPages(t *testing.T) { type minimalParserLoader struct{} -func (*minimalParserLoader) Get() (*config.Parser, error) { +func (*minimalParserLoader) Get() (*configparser.Parser, error) { configStr := ` receivers: otlp: @@ -268,14 +268,14 @@ service: processors: [batch] exporters: [logging] ` - return config.NewParserFromBuffer(strings.NewReader(configStr)) + return configparser.NewParserFromBuffer(strings.NewReader(configStr)) } type errParserLoader struct { err error } -func (epl *errParserLoader) Get() (*config.Parser, error) { +func (epl *errParserLoader) Get() (*configparser.Parser, error) { return nil, epl.err } diff --git a/service/parserprovider/default_test.go b/service/parserprovider/default_test.go index 9a90fa4cf3f..d177861d53c 100644 --- a/service/parserprovider/default_test.go +++ b/service/parserprovider/default_test.go @@ -25,6 +25,7 @@ import ( "go.opentelemetry.io/collector/config" "go.opentelemetry.io/collector/config/configloader" + "go.opentelemetry.io/collector/config/configparser" "go.opentelemetry.io/collector/processor/attributesprocessor" "go.opentelemetry.io/collector/processor/batchprocessor" "go.opentelemetry.io/collector/receiver/jaegerreceiver" @@ -44,7 +45,7 @@ func TestDefault(t *testing.T) { require.NoError(t, err) pl := Default() require.NotNil(t, pl) - var cp *config.Parser + var cp *configparser.Parser cp, err = pl.Get() require.NoError(t, err) require.NotNil(t, cp) @@ -64,7 +65,7 @@ func TestDefault(t *testing.T) { require.NoError(t, err) pl := Default() require.NotNil(t, pl) - var cp *config.Parser + var cp *configparser.Parser cp, err = pl.Get() require.NoError(t, err) require.NotNil(t, cp) @@ -100,7 +101,7 @@ func TestDefault(t *testing.T) { require.NoError(t, err) pl := Default() require.NotNil(t, pl) - var cp *config.Parser + var cp *configparser.Parser cp, err = pl.Get() require.NoError(t, err) require.NotNil(t, cp) diff --git a/service/parserprovider/file.go b/service/parserprovider/file.go index 63c88ca54fa..9c0ea40bd30 100644 --- a/service/parserprovider/file.go +++ b/service/parserprovider/file.go @@ -18,7 +18,7 @@ import ( "errors" "fmt" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" ) type fileProvider struct{} @@ -29,13 +29,13 @@ func NewFile() ParserProvider { return &fileProvider{} } -func (fl *fileProvider) Get() (*config.Parser, error) { +func (fl *fileProvider) Get() (*configparser.Parser, error) { fileName := getConfigFlag() if fileName == "" { return nil, errors.New("config file not specified") } - cp, err := config.NewParserFromFile(fileName) + cp, err := configparser.NewParserFromFile(fileName) if err != nil { return nil, fmt.Errorf("error loading config file %q: %v", fileName, err) } diff --git a/service/parserprovider/inmemory.go b/service/parserprovider/inmemory.go index b5b8ad14831..80dd4120b66 100644 --- a/service/parserprovider/inmemory.go +++ b/service/parserprovider/inmemory.go @@ -17,7 +17,7 @@ package parserprovider import ( "io" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" ) type inMemoryProvider struct { @@ -29,6 +29,6 @@ func NewInMemory(buf io.Reader) ParserProvider { return &inMemoryProvider{buf: buf} } -func (inp *inMemoryProvider) Get() (*config.Parser, error) { - return config.NewParserFromBuffer(inp.buf) +func (inp *inMemoryProvider) Get() (*configparser.Parser, error) { + return configparser.NewParserFromBuffer(inp.buf) } diff --git a/service/parserprovider/provider.go b/service/parserprovider/provider.go index b296e2a2258..7b404c391d1 100644 --- a/service/parserprovider/provider.go +++ b/service/parserprovider/provider.go @@ -17,14 +17,14 @@ package parserprovider import ( "context" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" ) // ParserProvider is an interface that helps providing configuration's parser. // Implementations may load the parser from a file, a database or any other source. type ParserProvider interface { // Get returns the config.Parser if succeed or error otherwise. - Get() (*config.Parser, error) + Get() (*configparser.Parser, error) } // Watchable is an extension for ParserProvider that is implemented if the given provider diff --git a/service/parserprovider/setflag.go b/service/parserprovider/setflag.go index 8434fea27bf..f7056658ff8 100644 --- a/service/parserprovider/setflag.go +++ b/service/parserprovider/setflag.go @@ -21,7 +21,7 @@ import ( "github.com/spf13/viper" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" ) const setFlagFileType = "properties" @@ -41,7 +41,7 @@ func NewSetFlag(base ParserProvider) ParserProvider { } } -func (sfl *setFlagProvider) Get() (*config.Parser, error) { +func (sfl *setFlagProvider) Get() (*configparser.Parser, error) { flagProperties := getSetFlag() if len(flagProperties) == 0 { return sfl.base.Get() @@ -54,7 +54,7 @@ func (sfl *setFlagProvider) Get() (*config.Parser, error) { return nil, err } } - viperFlags := viper.NewWithOptions(viper.KeyDelimiter(config.KeyDelimiter)) + viperFlags := viper.NewWithOptions(viper.KeyDelimiter(configparser.KeyDelimiter)) viperFlags.SetConfigType(setFlagFileType) if err := viperFlags.ReadConfig(b); err != nil { return nil, fmt.Errorf("failed to read set flag config: %v", err) @@ -84,7 +84,7 @@ func (sfl *setFlagProvider) Get() (*config.Parser, error) { rootKeys := map[string]struct{}{} for _, k := range viperFlags.AllKeys() { - keys := strings.Split(k, config.KeyDelimiter) + keys := strings.Split(k, configparser.KeyDelimiter) if len(keys) > 0 { rootKeys[keys[0]] = struct{}{} } diff --git a/service/parserprovider/setflag_test.go b/service/parserprovider/setflag_test.go index 6ac6a88cf34..be9e07490d3 100644 --- a/service/parserprovider/setflag_test.go +++ b/service/parserprovider/setflag_test.go @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/config" + "go.opentelemetry.io/collector/config/configparser" ) func TestSetFlags(t *testing.T) { @@ -59,6 +59,6 @@ func TestSetFlags_empty(t *testing.T) { type emptyProvider struct{} -func (el *emptyProvider) Get() (*config.Parser, error) { - return config.NewParser(), nil +func (el *emptyProvider) Get() (*configparser.Parser, error) { + return configparser.NewParser(), nil } diff --git a/service/telemetry.go b/service/telemetry.go index 8ac6c91913b..cd785f6d15e 100644 --- a/service/telemetry.go +++ b/service/telemetry.go @@ -27,7 +27,7 @@ import ( "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/exporter/jaegerexporter" "go.opentelemetry.io/collector/internal/collector/telemetry" - "go.opentelemetry.io/collector/obsreport" + "go.opentelemetry.io/collector/internal/obsreportconfig" "go.opentelemetry.io/collector/processor/batchprocessor" "go.opentelemetry.io/collector/receiver/kafkareceiver" telemetry2 "go.opentelemetry.io/collector/service/internal/telemetry" @@ -61,10 +61,11 @@ func (tel *appTelemetry) init(asyncErrorChannel chan<- error, ballastSizeBytes u } var views []*view.View + obsMetrics := obsreportconfig.Configure(level) views = append(views, batchprocessor.MetricViews()...) views = append(views, jaegerexporter.MetricViews()...) views = append(views, kafkareceiver.MetricViews()...) - views = append(views, obsreport.Configure(level)...) + views = append(views, obsMetrics.Views...) views = append(views, processMetricsViews.Views()...) tel.views = views diff --git a/testbed/testbed/receivers.go b/testbed/testbed/receivers.go index 81e021b330d..533d1ab17d3 100644 --- a/testbed/testbed/receivers.go +++ b/testbed/testbed/receivers.go @@ -259,7 +259,7 @@ func (bor *BaseOTLPDataReceiver) GenConfigYAMLStr() string { return str } -const DefaultOTLPPort = 55680 +const DefaultOTLPPort = 4317 // NewOTLPDataReceiver creates a new OTLP DataReceiver that will listen on the specified port after Start // is called. diff --git a/testbed/tests/e2e_test.go b/testbed/tests/e2e_test.go index b7ef4d4cf75..3c121983ac5 100644 --- a/testbed/tests/e2e_test.go +++ b/testbed/tests/e2e_test.go @@ -88,7 +88,7 @@ func TestBallastMemory(t *testing.T) { // given that the maxRSS isn't an absolute maximum and that the actual maximum might be a bit off, // we give some room here instead of failing when the memory usage isn't that much higher than the max lenientMax := 1.1 * float32(test.maxRSS) - assert.LessOrEqual(t, rss, lenientMax) + assert.LessOrEqual(t, float32(rss), lenientMax) tc.Stop() } } diff --git a/testutil/testutil.go b/testutil/testutil.go index 43017cbe643..20462754077 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -15,9 +15,7 @@ package testutil import ( - "io/ioutil" "net" - "os" "os/exec" "runtime" "strconv" @@ -32,16 +30,6 @@ type portpair struct { last string } -// TempSocketName provides a temporary Unix socket name for testing. -func TempSocketName(t *testing.T) string { - tmpfile, err := ioutil.TempFile("", "sock") - require.NoError(t, err) - require.NoError(t, tmpfile.Close()) - socket := tmpfile.Name() - require.NoError(t, os.Remove(socket)) - return socket -} - // GetAvailableLocalAddress finds an available local port and returns an endpoint // describing it. The port is available for opening when this function returns // provided that there is no race by some other code to grab the same port