translator/translate/metrics/util/commonconfigutil.go (162 lines of code) (raw):

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: MIT package util import ( "fmt" "github.com/aws/amazon-cloudwatch-agent/internal/util/hash" "github.com/aws/amazon-cloudwatch-agent/translator" "github.com/aws/amazon-cloudwatch-agent/translator/config" "github.com/aws/amazon-cloudwatch-agent/translator/translate/agent" "github.com/aws/amazon-cloudwatch-agent/translator/translate/util" ) const ( Alias_Key = "alias" Measurement_Key = "measurement" Collect_Interval_Key = "metrics_collection_interval" Collect_Interval_Mapped_Key = "interval" Aggregation_Interval_Key = "metrics_aggregation_interval" Append_Dimensions_Key = "append_dimensions" Append_Dimensions_Mapped_Key = "tags" Windows_Object_Name_Key = "ObjectName" Windows_Measurement_Key = "Measurement" Windows_WarnOnMissing_Key = "WarnOnMissing" Windows_Disable_Replacer_Key = "DisableReplacer" ) // ProcessLinuxCommonConfig is used by both Linux and Darwin. func ProcessLinuxCommonConfig(input interface{}, pluginName string, path string, result map[string]interface{}) bool { inputMap := input.(map[string]interface{}) // Generate allowlisted metric list, process only if Measurement_Key exist if translator.IsValid(inputMap, Measurement_Key, path) { // NOTE: the logic here is a bit tricky, even windows uses linux config for metric like procstat, NvidiaGPU. os := config.OS_TYPE_LINUX if translator.GetTargetPlatform() == config.OS_TYPE_DARWIN { os = config.OS_TYPE_DARWIN } returnKey, returnVal := ApplyMeasurementRule(inputMap[Measurement_Key], pluginName, os, path) if returnKey != "" { result[returnKey] = returnVal } else { // No valid metric get generated, stop processing return false } } else { return false } ProcessAppendDimensions(inputMap, pluginName, result) isHighResolution := IsHighResolution(agent.Global_Config.Interval) isHighResolution = setTimeInterval(inputMap, result, isHighResolution, pluginName) // Add HighResolution tags if isHighResolution { if result[Append_Dimensions_Mapped_Key] != nil { util.AddHighResolutionTag(result[Append_Dimensions_Mapped_Key]) } else { result[Append_Dimensions_Mapped_Key] = map[string]interface{}{util.High_Resolution_Tag_Key: "true"} } } return true } func ProcessAppendDimensions(inputMap map[string]interface{}, pluginName string, result map[string]interface{}) { // Set append_dimensions as tags if val, ok := inputMap[Append_Dimensions_Key]; ok { result[Append_Dimensions_Mapped_Key] = util.FilterReservedKeys(val) } // Apply any specific rules for the plugin if m, ok := ApplyPluginSpecificRules(pluginName); ok { for key, val := range m { result[key] = val } } } // Windows common config returnVal would be three parts: // 1. interval: Collect_Interval_Mapped_Key // 2. tags: Append_Dimensions_Mapped_Key // 3. object config func ProcessWindowsCommonConfig(input interface{}, pluginName string, path string) (returnVal map[string]interface{}) { inputMap := input.(map[string]interface{}) objectConfig := map[string]interface{}{} isHighRsolution := IsHighResolution(agent.Global_Config.Interval) returnVal = map[string]interface{}{} returnVal[Windows_Disable_Replacer_Key] = true // 1. Set input plugin specific interval isHighRsolution = setTimeInterval(inputMap, returnVal, isHighRsolution, pluginName) // 2. Set append_dimensions as tags if val, ok := inputMap[Append_Dimensions_Key]; ok { returnVal[Append_Dimensions_Mapped_Key] = val } // 3. object config // Generate allowlisted metric list, process only if Measurement_Key exist if translator.IsValid(inputMap, Measurement_Key, path) { returnKey, returnVal := ApplyMeasurementRule(inputMap[Measurement_Key], pluginName, config.OS_TYPE_WINDOWS, path) if returnKey != "" && len(returnVal) > 0 { objectConfig[returnKey] = returnVal } } // 4. Generate a alias name for each windows plugin since every win performance counter plugin will generate // a duplicate plugin but with different configuration https://github.com/aws/amazon-cloudwatch-agent/blob/a791b1484fbc0611e515ccbb9bd24bea469cb9fb/translator/translate/metrics/metrics_collect/customizedmetrics/customizedmetric.go#L39-L40 // and being merged later on if have the same interval,tags, objects https://github.com/aws/amazon-cloudwatch-agent/blob/a791b1484fbc0611e515ccbb9bd24bea469cb9fb/translator/translate/metrics/metrics_collect/customizedmetrics/customizedmetric.go#L58-L86 returnVal[Alias_Key] = hash.HashName(pluginName) // Add common field ObjectName objectConfig[Windows_Object_Name_Key] = pluginName // Output the message about the missing perf counter metrics objectConfig[Windows_WarnOnMissing_Key] = true //Measurement behaves like prefix in cloudwatch objectConfig[Windows_Measurement_Key] = pluginName //instances field is required in windows perf counter config if InstanceDisabled(pluginName) { objectConfig[Mapped_Instance_Key_Windows] = []string{Disabled_Instance_Val_Windows} } else if val, ok := inputMap[Resource_Key]; ok { if ContainAsterisk(input, Resource_Key) { objectConfig[Mapped_Instance_Key_Windows] = []string{Asterisk_Key} } else { objectConfig[Mapped_Instance_Key_Windows] = val } } else { // if no instance field specified, we assume the Objects have no instances to collect, use "------" to comply with win_perf_counters.go objectConfig[Mapped_Instance_Key_Windows] = []string{Disabled_Instance_Val_Windows} } // Add HighResolution tags if isHighRsolution { if returnVal[Append_Dimensions_Mapped_Key] != nil { util.AddHighResolutionTag(returnVal[Append_Dimensions_Mapped_Key]) } else { returnVal[Append_Dimensions_Mapped_Key] = map[string]interface{}{util.High_Resolution_Tag_Key: "true"} } } returnVal["object"] = []interface{}{objectConfig} return } func setTimeInterval(inputMap map[string]interface{}, returnVal map[string]interface{}, isHighRsolution bool, pluginName string) bool { if val, ok := inputMap[Collect_Interval_Key]; ok { if floatVal, ok := val.(float64); ok { val = fmt.Sprintf("%ds", int(floatVal)) returnVal[Collect_Interval_Mapped_Key] = val //Check if this metric is high resolution isHighRsolution = IsHighResolution(val.(string)) } else { translator.AddErrorMessages( fmt.Sprintf("metrics plugin %s", pluginName), fmt.Sprintf("metrics_collection_interval value (%v) in json is not valid for time interval.", val)) } } return isHighRsolution } func ProcessMetricsCollectionInterval(input interface{}, defaultValue, pluginName string) (returnKey string, returnVal interface{}) { if inputMap, ok := input.(map[string]interface{}); ok { if val, ok := inputMap[Collect_Interval_Key]; ok { if floatVal, ok := val.(float64); ok { val = fmt.Sprintf("%ds", int(floatVal)) return Collect_Interval_Mapped_Key, val } else { translator.AddErrorMessages( fmt.Sprintf("metrics plugin %s", pluginName), fmt.Sprintf("metrics_collection_interval value (%v) in json is not valid for time interval.", val)) } } if defaultValue != "" { return Collect_Interval_Mapped_Key, defaultValue } } return } func ProcessMetricsAggregationInterval(input interface{}, defaultValue, pluginName string) (returnKey string, returnVal interface{}) { if inputMap, ok := input.(map[string]interface{}); ok { if val, ok := inputMap[Aggregation_Interval_Key]; ok { if floatVal, ok := val.(float64); ok { val = fmt.Sprintf("%ds", int(floatVal)) if valStr, ok := val.(string); ok && valStr == "0s" { // customer specifically disabled the metrics aggregation interval by putting "0" return Append_Dimensions_Mapped_Key, map[string]interface{}{util.High_Resolution_Tag_Key: "true"} } return Append_Dimensions_Mapped_Key, map[string]interface{}{util.Aggregation_Interval_Tag_Key: val} } else { translator.AddErrorMessages( fmt.Sprintf("metrics plugin %s", pluginName), fmt.Sprintf("metrics_aggregation_interval value (%v) in json is not valid for time interval.", val)) } } if defaultValue != "" { return Append_Dimensions_Mapped_Key, map[string]interface{}{util.Aggregation_Interval_Tag_Key: defaultValue} } } return } // check if desiredVal exist in inputs list func ListContains(inputs []string, desiredVal string) bool { for _, val := range inputs { if val == desiredVal { return true } } return false }