confgenerator/confmerger.go (81 lines of code) (raw):

// Copyright 2021 Google LLC // // 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 confgenerator provides functions to generate subagents configuration from unified agent. package confgenerator import ( "context" "log" "github.com/GoogleCloudPlatform/ops-agent/internal/platform" ) // MergeConfFiles merges the user provided config with the built-in config struct for the platform. func MergeConfFiles(ctx context.Context, userConfPath string, builtInConfStructs map[string]*UnifiedConfig) (*UnifiedConfig, error) { builtInStruct := builtInConfStructs[platform.FromContext(ctx).Name()] // Start with the built-in config. result, err := builtInStruct.DeepCopy(ctx) if err != nil { return nil, err } overrides, err := ReadUnifiedConfigFromFile(ctx, userConfPath) if err != nil { return nil, err } // Optionally merge the user config file. if overrides != nil { mergeConfigs(result, overrides) } if err := result.Validate(ctx); err != nil { return nil, err } // Ensure the merged config struct fields are valid. v := newValidator() if err := v.StructCtx(ctx, result); err != nil { log.Fatalf("merged config failed to validate: %v", err) } return result, nil } func mergeConfigs(original, overrides *UnifiedConfig) { // built-in configs do not contain these sections. original.Combined = overrides.Combined original.Traces = overrides.Traces original.Global = overrides.Global // For "default_pipeline", we go one level deeper. // this covers 2 cases: // 1. if "<receivers / processors / exporters>: []" is specified explicitly in user config, the entity gets cleared. // 2. if "<receivers / processors / exporters>" is a non-empty list, it overrides the built-in list. // e.g. users might use the config below to turn off iis metrics on windows. // metrics: // service: // pipelines: // default_pipeline: // receivers: [hostmetrics,mssql] if overrides.Logging != nil { // Overrides logging.receivers. for k, v := range overrides.Logging.Receivers { original.Logging.Receivers[k] = v } // Overrides logging.processors. original.Logging.Processors = map[string]LoggingProcessor{} for k, v := range overrides.Logging.Processors { original.Logging.Processors[k] = v } // Skip deprecated logging.exporters. // Override logging.service.pipelines if overrides.Logging.Service != nil { if overrides.Logging.Service.LogLevel != "info" { original.Logging.Service.LogLevel = overrides.Logging.Service.LogLevel } original.Logging.Service.OTelLogging = overrides.Logging.Service.OTelLogging if overrides.Logging.Service.Compress != "" { original.Logging.Service.Compress = overrides.Logging.Service.Compress } for name, pipeline := range overrides.Logging.Service.Pipelines { // skips logging.service.pipelines.*.exporters pipeline.ExporterIDs = nil if name == "default_pipeline" { // overrides logging.service.pipelines.default_pipeline.receivers if ids := pipeline.ReceiverIDs; ids != nil { original.Logging.Service.Pipelines["default_pipeline"].ReceiverIDs = ids } // overrides logging.service.pipelines.default_pipeline.processors if ids := pipeline.ProcessorIDs; ids != nil { original.Logging.Service.Pipelines["default_pipeline"].ProcessorIDs = ids } } else { // Overrides logging.service.pipelines.<non_default_pipelines> original.Logging.Service.Pipelines[name] = pipeline } } } } if overrides.Metrics != nil { // Overrides metrics.receivers. for k, v := range overrides.Metrics.Receivers { original.Metrics.Receivers[k] = v } // Overrides metrics.processors. for k, v := range overrides.Metrics.Processors { original.Metrics.Processors[k] = v } if overrides.Metrics.Service != nil { if overrides.Metrics.Service.LogLevel != "info" { original.Metrics.Service.LogLevel = overrides.Metrics.Service.LogLevel } for name, pipeline := range overrides.Metrics.Service.Pipelines { // skips metrics.service.pipelines.*.exporters pipeline.ExporterIDs = nil // Overrides metrics.service.pipelines.* original.Metrics.Service.Pipelines[name] = pipeline } } } }