Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AGENTCFG-79] Remove usage of Viper from comp/logs/agent/config/parser.go #34427

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions comp/logs/agent/config/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ require (
github.com/DataDog/datadog-agent/pkg/util/log v0.64.0-devel
github.com/DataDog/datadog-agent/pkg/util/pointer v0.61.0
github.com/DataDog/datadog-agent/pkg/util/scrubber v0.62.3
github.com/DataDog/viper v1.14.0
github.com/stretchr/testify v1.10.0
go.uber.org/atomic v1.11.0
go.uber.org/fx v1.23.0
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand All @@ -38,6 +38,7 @@ require (
github.com/DataDog/datadog-agent/pkg/util/system/socket v0.61.0 // indirect
github.com/DataDog/datadog-agent/pkg/util/winutil v0.61.0 // indirect
github.com/DataDog/datadog-agent/pkg/version v0.62.3 // indirect
github.com/DataDog/viper v1.14.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
Expand Down Expand Up @@ -72,7 +73,6 @@ require (
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

// This section was automatically added by 'invoke modules.add-all-replace' command, do not edit manually
Expand Down
67 changes: 47 additions & 20 deletions comp/logs/agent/config/integration_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,22 @@ type LogsConfig struct {
IntegrationName string

Port int // Network
IdleTimeout string `mapstructure:"idle_timeout" json:"idle_timeout"` // Network
IdleTimeout string `mapstructure:"idle_timeout" json:"idle_timeout" yaml:"idle_timeout"` // Network
Path string // File, Journald

Encoding string `mapstructure:"encoding" json:"encoding"` // File
ExcludePaths []string `mapstructure:"exclude_paths" json:"exclude_paths"` // File
TailingMode string `mapstructure:"start_position" json:"start_position"` // File
Encoding string `mapstructure:"encoding" json:"encoding" yaml:"encoding"` // File
ExcludePaths StringSliceField `mapstructure:"exclude_paths" json:"exclude_paths" yaml:"exclude_paths"` // File
TailingMode string `mapstructure:"start_position" json:"start_position" yaml:"start_position"` // File

//nolint:revive // TODO(AML) Fix revive linter
ConfigId string `mapstructure:"config_id" json:"config_id"` // Journald
IncludeSystemUnits []string `mapstructure:"include_units" json:"include_units"` // Journald
ExcludeSystemUnits []string `mapstructure:"exclude_units" json:"exclude_units"` // Journald
IncludeUserUnits []string `mapstructure:"include_user_units" json:"include_user_units"` // Journald
ExcludeUserUnits []string `mapstructure:"exclude_user_units" json:"exclude_user_units"` // Journald
IncludeMatches []string `mapstructure:"include_matches" json:"include_matches"` // Journald
ExcludeMatches []string `mapstructure:"exclude_matches" json:"exclude_matches"` // Journald
ContainerMode bool `mapstructure:"container_mode" json:"container_mode"` // Journald
ConfigId string `mapstructure:"config_id" json:"config_id" yaml:"config_id"` // Journald
IncludeSystemUnits StringSliceField `mapstructure:"include_units" json:"include_units" yaml:"include_units"` // Journald
ExcludeSystemUnits StringSliceField `mapstructure:"exclude_units" json:"exclude_units" yaml:"exclude_units"` // Journald
IncludeUserUnits StringSliceField `mapstructure:"include_user_units" json:"include_user_units" yaml:"include_user_units"` // Journald
ExcludeUserUnits StringSliceField `mapstructure:"exclude_user_units" json:"exclude_user_units" yaml:"exclude_user_units"` // Journald
IncludeMatches StringSliceField `mapstructure:"include_matches" json:"include_matches" yaml:"include_matches"` // Journald
ExcludeMatches StringSliceField `mapstructure:"exclude_matches" json:"exclude_matches" yaml:"exclude_matches"` // Journald
ContainerMode bool `mapstructure:"container_mode" json:"container_mode" yaml:"container_mode"` // Journald

Image string // Docker
Label string // Docker
Expand All @@ -67,7 +67,7 @@ type LogsConfig struct {
// determine the appropriate tags for the logs.
Identifier string // Docker, File

ChannelPath string `mapstructure:"channel_path" json:"channel_path"` // Windows Event
ChannelPath string `mapstructure:"channel_path" json:"channel_path" yaml:"channel_path"` // Windows Event
Query string // Windows Event

// used as input only by the Channel tailer.
Expand All @@ -76,22 +76,49 @@ type LogsConfig struct {

// ChannelTags are the tags attached to messages on Channel; unlike Tags this can be
// modified at runtime (as long as ChannelTagsMutex is held).
ChannelTags []string
ChannelTags StringSliceField

// ChannelTagsMutex guards ChannelTags.
ChannelTagsMutex sync.Mutex

Service string
Source string
SourceCategory string
Tags []string
ProcessingRules []*ProcessingRule `mapstructure:"log_processing_rules" json:"log_processing_rules"`
Tags StringSliceField
ProcessingRules []*ProcessingRule `mapstructure:"log_processing_rules" json:"log_processing_rules" yaml:"log_processing_rules"`
// ProcessRawMessage is used to process the raw message instead of only the content part of the message.
ProcessRawMessage *bool `mapstructure:"process_raw_message" json:"process_raw_message"`
ProcessRawMessage *bool `mapstructure:"process_raw_message" json:"process_raw_message" yaml:"process_raw_message"`

AutoMultiLine *bool `mapstructure:"auto_multi_line_detection" json:"auto_multi_line_detection"`
AutoMultiLineSampleSize int `mapstructure:"auto_multi_line_sample_size" json:"auto_multi_line_sample_size"`
AutoMultiLineMatchThreshold float64 `mapstructure:"auto_multi_line_match_threshold" json:"auto_multi_line_match_threshold"`
AutoMultiLine *bool `mapstructure:"auto_multi_line_detection" json:"auto_multi_line_detection" yaml:"auto_multi_line_detection"`
AutoMultiLineSampleSize int `mapstructure:"auto_multi_line_sample_size" json:"auto_multi_line_sample_size" yaml:"auto_multi_line_sample_size"`
AutoMultiLineMatchThreshold float64 `mapstructure:"auto_multi_line_match_threshold" json:"auto_multi_line_match_threshold" yaml:"auto_multi_line_match_threshold"`
}

// StringSliceField is a custom type for unmarshalling comma-separated string values or typical yaml fields into a slice of strings.
type StringSliceField []string

// UnmarshalYAML is a custom unmarshalling function is needed for string array fields to split comma-separated values.
func (t *StringSliceField) UnmarshalYAML(unmarshal func(interface{}) error) error {
var str string
if err := unmarshal(&str); err == nil {
// note that we are intentionally avoiding the trimming of any spaces whilst splitting the string
str = strings.ReplaceAll(str, "\n", "")
*t = strings.Split(str, ",")
return nil
}

var raw []interface{}
if err := unmarshal(&raw); err == nil {
for _, item := range raw {
if str, ok := item.(string); ok {
*t = append(*t, str)
} else {
return fmt.Errorf("cannot unmarshal %v into a string", item)
}
}
return nil
}
return fmt.Errorf("could not parse YAML config, please double check the yaml files")
}

// Dump dumps the contents of this struct to a string, for debugging purposes.
Expand Down
24 changes: 8 additions & 16 deletions comp/logs/agent/config/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
package config

import (
"bytes"
"encoding/json"
"fmt"

"github.com/DataDog/viper"
yaml "gopkg.in/yaml.v3"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We seems to have a split in the code base between v2 and v3 (108 import of gopkg.in/yaml.v2 vs 33 fo gopkg.in/yaml.v3"). Any reasons to use v3 in particular ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems that we are migrating to yaml.v3, so I thought that I would get ahead of the curve: #33450

)

type yamlLogsConfigsWrapper struct {
Logs []*LogsConfig
}

// ParseJSON parses the data formatted in JSON
// returns an error if the parsing failed.
func ParseJSON(data []byte) ([]*LogsConfig, error) {
Expand All @@ -24,23 +26,13 @@ func ParseJSON(data []byte) ([]*LogsConfig, error) {
return configs, nil
}

const yaml = "yaml"
const logsPath = "logs"

// ParseYAML parses the data formatted in YAML,
// returns an error if the parsing failed.
func ParseYAML(data []byte) ([]*LogsConfig, error) {
var configs []*LogsConfig
var err error
v := viper.New()
v.SetConfigType(yaml)
err = v.ReadConfig(bytes.NewBuffer(data))
var yamlConfigsWrapper yamlLogsConfigsWrapper
err := yaml.Unmarshal(data, &yamlConfigsWrapper)
if err != nil {
return nil, fmt.Errorf("could not decode YAML logs config: %v", err)
}
err = v.UnmarshalKey(logsPath, &configs)
if err != nil {
return nil, fmt.Errorf("could not parse YAML logs config: %v", err)
}
return configs, nil
return yamlConfigsWrapper.Logs, nil
}
Loading
Loading