Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ func ResolveConfig() (*Config, error) {
Labels: resolveLabels(),
LibDir: viperInstance.GetString(LibDirPathKey),
SyslogServer: resolveSyslogServer(),
MaxAccessLogFiles: viperInstance.GetInt(MaxAccessLogFilesKey),
}

defaultCollector(collector, config)
Expand Down Expand Up @@ -469,6 +470,12 @@ func registerFlags() {
"The port Agent will start the syslog server on for logs collection",
)

fs.Int(
MaxAccessLogFilesKey,
DefMaxAccessLogFiles,
"The maximum number of access log files to monitor",
)

registerCommonFlags(fs)
registerCommandFlags(fs)
registerAuxiliaryCommandFlags(fs)
Expand Down
1 change: 1 addition & 0 deletions internal/config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
DefNginxReloadMonitoringPeriod = 10 * time.Second
DefTreatErrorsAsWarnings = false
DefNginxApiTlsCa = ""
DefMaxAccessLogFiles = 10

// Nginx Reload Backoff defaults
DefNginxReloadBackoffInitialInterval = 500 * time.Millisecond
Expand Down
1 change: 1 addition & 0 deletions internal/config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
InstanceHealthWatcherMonitoringFrequencyKey = "watchers_instance_health_watcher_monitoring_frequency"
FileWatcherKey = "watchers_file_watcher"
LibDirPathKey = "lib_dir"
MaxAccessLogFilesKey = "max_access_log_files"
)

var (
Expand Down
27 changes: 16 additions & 11 deletions internal/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,22 @@ func parseServerType(str string) (ServerType, bool) {

type (
Config struct {
Command *Command `yaml:"command" mapstructure:"command"`
AuxiliaryCommand *Command `yaml:"auxiliary_command" mapstructure:"auxiliary_command"`
Log *Log `yaml:"log" mapstructure:"log"`
DataPlaneConfig *DataPlaneConfig `yaml:"data_plane_config" mapstructure:"data_plane_config"`
Client *Client `yaml:"client" mapstructure:"client"`
Collector *Collector `yaml:"collector" mapstructure:"collector"`
Watchers *Watchers `yaml:"watchers" mapstructure:"watchers"`
SyslogServer *SyslogServer `yaml:"syslog_server" mapstructure:"syslog_server"`
Labels map[string]any `yaml:"labels" mapstructure:"labels"`
Command *Command `yaml:"command" mapstructure:"command"`
AuxiliaryCommand *Command `yaml:"auxiliary_command" mapstructure:"auxiliary_command"`
Log *Log `yaml:"log" mapstructure:"log"`
DataPlaneConfig *DataPlaneConfig `yaml:"data_plane_config" mapstructure:"data_plane_config"`
Client *Client `yaml:"client" mapstructure:"client"`
Collector *Collector `yaml:"collector" mapstructure:"collector"`
Watchers *Watchers `yaml:"watchers" mapstructure:"watchers"`
SyslogServer *SyslogServer `yaml:"syslog_server" mapstructure:"syslog_server"`
Labels map[string]any `yaml:"labels" mapstructure:"labels"`
Version string `yaml:"-"`
Path string `yaml:"-"`
UUID string `yaml:"-"`
LibDir string `yaml:"-"`
AllowedDirectories []string `yaml:"allowed_directories" mapstructure:"allowed_directories"`
Features []string `yaml:"features" mapstructure:"features"`
AllowedDirectories []string `yaml:"allowed_directories" mapstructure:"allowed_directories"`
Features []string `yaml:"features" mapstructure:"features"`
MaxAccessLogFiles int `yaml:"max_access_log_files" mapstructure:"max_access_log_files"`
}

Log struct {
Expand Down Expand Up @@ -477,6 +478,10 @@ func (c *Config) IsCommandServerProxyConfigured() bool {
return c.Command.Server.Proxy.URL != ""
}

func (c *Config) IsMaxAccessLogFilesConfigured() bool {
return c.MaxAccessLogFiles != 0
}

// isAllowedDir checks if the given path is in the list of allowed directories.
// It recursively checks the parent directories of the path, until it finds a match or reaches the root directory.
func isAllowedDir(path string, allowedDirs []string) bool {
Expand Down
15 changes: 13 additions & 2 deletions internal/datasource/config/nginx_config_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,13 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
if !ncp.ignoreLog(directive.Args[0]) {
accessLog := ncp.accessLog(directive.Args[0], ncp.accessLogDirectiveFormat(directive),
formatMap)
nginxConfigContext.AccessLogs = ncp.addAccessLog(accessLog, nginxConfigContext.AccessLogs)
if ncp.agentConfig.IsMaxAccessLogFilesConfigured() {
nginxConfigContext.AccessLogs = ncp.addAccessLog(accessLog,
nginxConfigContext.AccessLogs, ncp.agentConfig.MaxAccessLogFiles)
} else {
nginxConfigContext.AccessLogs = ncp.addAccessLog(accessLog,
nginxConfigContext.AccessLogs, config.DefMaxAccessLogFiles)
}
}
case "error_log":
if !ncp.ignoreLog(directive.Args[0]) {
Expand Down Expand Up @@ -344,7 +350,7 @@ func (ncp *NginxConfigParser) parseIncludeDirective(
}

func (ncp *NginxConfigParser) addAccessLog(accessLog *model.AccessLog,
accessLogs []*model.AccessLog,
accessLogs []*model.AccessLog, maxAccessLogFiles int,
) []*model.AccessLog {
for i, log := range accessLogs {
if accessLog.Name == log.Name {
Expand All @@ -361,6 +367,11 @@ func (ncp *NginxConfigParser) addAccessLog(accessLog *model.AccessLog,
}
}

if len(accessLogs) >= maxAccessLogFiles {
slog.Warn("Maximum access log files have been reached, additional logs will be skipped")
return accessLogs
}

slog.Debug("Found valid access log", "access_log", accessLog.Name)

return append(accessLogs, accessLog)
Expand Down
55 changes: 52 additions & 3 deletions internal/datasource/config/nginx_config_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@ func TestNginxConfigParser_checkLog(t *testing.T) {
accessLog *model.AccessLog
currentAccessLogs []*model.AccessLog
expectedAccessLogs []*model.AccessLog
maxAccessLogFiles int
}{
{
name: "Test 1: valid access log",
Expand Down Expand Up @@ -790,7 +791,8 @@ func TestNginxConfigParser_checkLog(t *testing.T) {
Readable: true,
},
},
expectedLog: "Found valid access log",
expectedLog: "Found valid access log",
maxAccessLogFiles: 3,
},
{
name: "Test 2: Duplicate access log, with same format",
Expand Down Expand Up @@ -819,7 +821,8 @@ func TestNginxConfigParser_checkLog(t *testing.T) {
Readable: true,
},
},
expectedLog: "Found duplicate access log, skipping",
expectedLog: "Found duplicate access log, skipping",
maxAccessLogFiles: 3,
},

{
Expand All @@ -844,13 +847,59 @@ func TestNginxConfigParser_checkLog(t *testing.T) {
expectedLog: "Found multiple log_format directives for the same access log. " +
"Multiple log formats are not supported in the same access log, metrics from this access log " +
"will not be collected",
maxAccessLogFiles: 3,
},

{
name: "Test 4: valid access log, maximum access logs reached",
accessLog: &model.AccessLog{
Name: "/var/log/nginx/access3.log",
Format: "$remote_addr - $remote_user [$time_local] \"$request\" \"$http_user_agent\" " +
"\"$http_x_forwarded_for\"$status $body_bytes_sent \"$http_referer\"",
Permissions: "",
Readable: true,
},
currentAccessLogs: []*model.AccessLog{
{
Name: "/var/log/nginx/access.log",
Format: "$remote_addr - $remote_user [$time_local] \"$request\" \"$http_user_agent\" " +
"\"$http_x_forwarded_for\"$status $body_bytes_sent \"$http_referer\"",
Permissions: "",
Readable: true,
},
{
Name: "/var/log/nginx/access2.log",
Format: "$remote_addr - $remote_user [$time_local] \"$request\" \"$http_user_agent\" " +
"\"$http_x_forwarded_for\"$status $body_bytes_sent \"$http_referer\"",
Permissions: "",
Readable: true,
},
},
expectedAccessLogs: []*model.AccessLog{
{
Name: "/var/log/nginx/access.log",
Format: "$remote_addr - $remote_user [$time_local] \"$request\" \"$http_user_agent\" " +
"\"$http_x_forwarded_for\"$status $body_bytes_sent \"$http_referer\"",
Permissions: "",
Readable: true,
},
{
Name: "/var/log/nginx/access2.log",
Format: "$remote_addr - $remote_user [$time_local] \"$request\" \"$http_user_agent\" " +
"\"$http_x_forwarded_for\"$status $body_bytes_sent \"$http_referer\"",
Permissions: "",
Readable: true,
},
},
expectedLog: "Maximum access log files have been reached, additional logs will be skipped",
maxAccessLogFiles: 2,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ncp := NewNginxConfigParser(types.AgentConfig())
logs := ncp.addAccessLog(test.accessLog, test.currentAccessLogs)
logs := ncp.addAccessLog(test.accessLog, test.currentAccessLogs, test.maxAccessLogFiles)
assert.Equal(t, test.expectedAccessLogs, logs)

helpers.ValidateLog(t, test.expectedLog, logBuf)
Expand Down
Loading