1// Copyright The OpenTelemetry Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package config 16 17import ( 18 "errors" 19 "fmt" 20 21 "go.opentelemetry.io/collector/config/configparser" 22) 23 24var ( 25 errMissingExporters = errors.New("no enabled exporters specified in config") 26 errMissingReceivers = errors.New("no enabled receivers specified in config") 27 errMissingServicePipelines = errors.New("service must have at least one pipeline") 28) 29 30// Config defines the configuration for the various elements of collector or agent. 31type Config struct { 32 Receivers 33 Exporters 34 Processors 35 Extensions 36 Service 37} 38 39var _ validatable = (*Config)(nil) 40 41// Validate returns an error if the config is invalid. 42// 43// This function performs basic validation of configuration. There may be more subtle 44// invalid cases that we currently don't check for but which we may want to add in 45// the future (e.g. disallowing receiving and exporting on the same endpoint). 46func (cfg *Config) Validate() error { 47 // Currently there is no default receiver enabled. 48 // The configuration must specify at least one receiver to be valid. 49 if len(cfg.Receivers) == 0 { 50 return errMissingReceivers 51 } 52 53 // Validate the receiver configuration. 54 for recv, recvCfg := range cfg.Receivers { 55 if err := recvCfg.Validate(); err != nil { 56 return fmt.Errorf("receiver \"%s\" has invalid configuration: %w", recv, err) 57 } 58 } 59 60 // Currently there is no default exporter enabled. 61 // The configuration must specify at least one exporter to be valid. 62 if len(cfg.Exporters) == 0 { 63 return errMissingExporters 64 } 65 66 // Validate the exporter configuration. 67 for exp, expCfg := range cfg.Exporters { 68 if err := expCfg.Validate(); err != nil { 69 return fmt.Errorf("exporter \"%s\" has invalid configuration: %w", exp, err) 70 } 71 } 72 73 // Validate the processor configuration. 74 for proc, procCfg := range cfg.Processors { 75 if err := procCfg.Validate(); err != nil { 76 return fmt.Errorf("processor \"%s\" has invalid configuration: %w", proc, err) 77 } 78 } 79 80 // Validate the extension configuration. 81 for ext, extCfg := range cfg.Extensions { 82 if err := extCfg.Validate(); err != nil { 83 return fmt.Errorf("extension \"%s\" has invalid configuration: %w", ext, err) 84 } 85 } 86 87 // Check that all enabled extensions in the service are configured. 88 if err := cfg.validateServiceExtensions(); err != nil { 89 return err 90 } 91 92 // Check that all pipelines have at least one receiver and one exporter, and they reference 93 // only configured components. 94 return cfg.validateServicePipelines() 95} 96 97func (cfg *Config) validateServiceExtensions() error { 98 // Validate extensions. 99 for _, ref := range cfg.Service.Extensions { 100 // Check that the name referenced in the Service extensions exists in the top-level extensions. 101 if cfg.Extensions[ref] == nil { 102 return fmt.Errorf("service references extension %q which does not exist", ref) 103 } 104 } 105 106 return nil 107} 108 109func (cfg *Config) validateServicePipelines() error { 110 // Must have at least one pipeline. 111 if len(cfg.Service.Pipelines) == 0 { 112 return errMissingServicePipelines 113 } 114 115 // Validate pipelines. 116 for _, pipeline := range cfg.Service.Pipelines { 117 // Validate pipeline has at least one receiver. 118 if len(pipeline.Receivers) == 0 { 119 return fmt.Errorf("pipeline %q must have at least one receiver", pipeline.Name) 120 } 121 122 // Validate pipeline receiver name references. 123 for _, ref := range pipeline.Receivers { 124 // Check that the name referenced in the pipeline's receivers exists in the top-level receivers. 125 if cfg.Receivers[ref] == nil { 126 return fmt.Errorf("pipeline %q references receiver %q which does not exist", pipeline.Name, ref) 127 } 128 } 129 130 // Validate pipeline processor name references. 131 for _, ref := range pipeline.Processors { 132 // Check that the name referenced in the pipeline's processors exists in the top-level processors. 133 if cfg.Processors[ref] == nil { 134 return fmt.Errorf("pipeline %q references processor %q which does not exist", pipeline.Name, ref) 135 } 136 } 137 138 // Validate pipeline has at least one exporter. 139 if len(pipeline.Exporters) == 0 { 140 return fmt.Errorf("pipeline %q must have at least one exporter", pipeline.Name) 141 } 142 143 // Validate pipeline exporter name references. 144 for _, ref := range pipeline.Exporters { 145 // Check that the name referenced in the pipeline's Exporters exists in the top-level Exporters. 146 if cfg.Exporters[ref] == nil { 147 return fmt.Errorf("pipeline %q references exporter %q which does not exist", pipeline.Name, ref) 148 } 149 } 150 } 151 return nil 152} 153 154// Service defines the configurable components of the service. 155type Service struct { 156 // Extensions are the ordered list of extensions configured for the service. 157 Extensions []ComponentID 158 159 // Pipelines are the set of data pipelines configured for the service. 160 Pipelines Pipelines 161} 162 163// Type is the component type as it is used in the config. 164type Type string 165 166// validatable defines the interface for the configuration validation. 167type validatable interface { 168 // Validate validates the configuration and returns an error if invalid. 169 Validate() error 170} 171 172// CustomUnmarshable defines an optional interface for custom configuration unmarshaling. 173// A configuration struct can implement this interface to override the default unmarshaling. 174type CustomUnmarshable interface { 175 // Unmarshal is a function that un-marshals a Parser into the unmarshable struct in a custom way. 176 // componentSection *Parser 177 // The config for this specific component. May be nil or empty if no config available. 178 Unmarshal(componentSection *configparser.Parser) error 179} 180 181// DataType is the data type that is supported for collection. We currently support 182// collecting metrics, traces and logs, this can expand in the future. 183type DataType string 184 185// Currently supported data types. Add new data types here when new types are supported in the future. 186const ( 187 // TracesDataType is the data type tag for traces. 188 TracesDataType DataType = "traces" 189 190 // MetricsDataType is the data type tag for metrics. 191 MetricsDataType DataType = "metrics" 192 193 // LogsDataType is the data type tag for logs. 194 LogsDataType DataType = "logs" 195) 196 197// Pipeline defines a single pipeline. 198type Pipeline struct { 199 Name string 200 InputType DataType 201 Receivers []ComponentID 202 Processors []ComponentID 203 Exporters []ComponentID 204} 205 206// Pipelines is a map of names to Pipelines. 207type Pipelines map[string]*Pipeline 208