diff --git a/config/config.go b/config/config.go index 6f005332..f06e1201 100644 --- a/config/config.go +++ b/config/config.go @@ -33,6 +33,11 @@ type Config struct { // Flag to enable chaining with root program BpfChainingEnabled bool + FileLogLocation string + FileLogMaxSize int + FileLogMaxBackups int + FileLogMaxAge int + // stats // Prometheus endpoint for pull/scrape the metrics. MetricsAddr string @@ -105,6 +110,10 @@ func ReadConfig(configPath string) (*Config, error) { BPFLogDir: LoadOptionalConfigString(confReader, "l3afd", "bpf-log-dir", ""), MinKernelMajorVer: LoadOptionalConfigInt(confReader, "l3afd", "kernel-major-version", 5), MinKernelMinorVer: LoadOptionalConfigInt(confReader, "l3afd", "kernel-minor-version", 15), + FileLogLocation: LoadOptionalConfigString(confReader, "l3afd", "file-log-location", ""), + FileLogMaxSize: LoadOptionalConfigInt(confReader, "l3afd", "file-log-max-size", 100), + FileLogMaxBackups: LoadOptionalConfigInt(confReader, "l3afd", "file-log-max-backups", 20), + FileLogMaxAge: LoadOptionalConfigInt(confReader, "l3afd", "file-log-max-age", 60), EBPFRepoURL: LoadConfigString(confReader, "ebpf-repo", "url"), HttpClientTimeout: LoadOptionalConfigDuration(confReader, "l3afd", "http-client-timeout", 30*time.Second), MaxEBPFReStartCount: LoadOptionalConfigInt(confReader, "l3afd", "max-ebpf-restart-count", 3), diff --git a/config/l3afd.cfg b/config/l3afd.cfg index 18ea6d22..f82a2c43 100644 --- a/config/l3afd.cfg +++ b/config/l3afd.cfg @@ -14,7 +14,7 @@ swagger-api-enabled: false environment: PROD # BpfMapDefaultPath is base path for storing maps BpfMapDefaultPath: /sys/fs/bpf - +file-log-location: /var/log/l3afd.log [ebpf-repo] url: file:///var/l3afd/repo diff --git a/docs/configdoc.md b/docs/configdoc.md index 313e8b2b..1b13ed66 100644 --- a/docs/configdoc.md +++ b/docs/configdoc.md @@ -41,6 +41,10 @@ environment: PROD |swagger-api-enabled| `"false"` |Whether the swagger API is enabled or not. For more info see [swagger.md](https://github.com/l3af-project/l3afd/blob/main/docs/swagger.md)| No | |environment| `"PROD"` |If set to anything other than "PROD", mTLS security will not be checked| Yes | |BpfMapDefaultPath| `"/sys/fs/bpf"` |The base pin path for eBPF maps| Yes | +| file-log-location | `"/var/log/l3afd.log"` | Location of the log file | No | +| file-log-max-size | `"100"` | Max size in megabytes for Log file rotation | No | +| file-log-max-backups | `"20"` | Max size in megabytes for Log file rotation | No | +| file-log-max-age | `"60"` | Max number of days to keep Log files | No | ## [ebpf-repo] | FieldName | Default | Description | Required | @@ -112,4 +116,4 @@ This section is needed when bpf-chaining-enabled is set to true. |server-crt-filename| `"server.crt"` | Server's ca certificate filename | No | |server-key-filename| `"server.key"` | Server's mtls key filename | No | |cert-expiry-warning-days| `"30"` | How many days before expiry you want warning | No | -|san-match-rules| `".*l3af.l3af.io,^l3afd.l3af.io$"` | List of domain names (exact match) or regular expressions to validate client SAN DNS Names against | No | +|san-match-rules| `".*l3af.l3af.io,^l3afd.l3af.io$"` | List of domain names (exact match) or regular expressions to validate client SAN DNS Names against | No | \ No newline at end of file diff --git a/go.mod b/go.mod index 7e31941a..f7f7255f 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( require ( github.com/florianl/go-tc v0.4.3 github.com/golang/mock v1.6.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( diff --git a/go.sum b/go.sum index 86c3a771..99e8ae42 100644 --- a/go.sum +++ b/go.sum @@ -242,6 +242,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/main.go b/main.go index 7bddd26e..6ca58fdf 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,7 @@ import ( "github.com/l3af-project/l3afd/v2/models" "github.com/l3af-project/l3afd/v2/pidfile" "github.com/l3af-project/l3afd/v2/stats" + "gopkg.in/natefinch/lumberjack.v2" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -58,6 +59,19 @@ func setupLogging() { log.Debug().Msgf("Log level set to %q", logLevel) } +func saveLogsToFile(conf *config.Config) { + + logFileWithRotation := &lumberjack.Logger{ + Filename: conf.FileLogLocation, + MaxSize: conf.FileLogMaxSize, // Max size in megabytes + MaxBackups: conf.FileLogMaxBackups, // Max number of old log files to keep + MaxAge: conf.FileLogMaxAge, // Max number of days to keep log files + } + multi := zerolog.MultiLevelWriter(os.Stdout, logFileWithRotation) + log.Logger = log.Output(zerolog.ConsoleWriter{ + Out: multi, TimeFormat: time.RFC3339Nano}) +} + func main() { setupLogging() ctx, cancel := context.WithCancel(context.Background()) @@ -74,6 +88,11 @@ func main() { log.Fatal().Err(err).Msgf("Unable to parse config %q", confPath) } + if conf.FileLogLocation != "" { + log.Info().Msgf("Saving logs to file: %s", conf.FileLogLocation) + saveLogsToFile(conf) + } + if err = pidfile.CheckPIDConflict(conf.PIDFilename); err != nil { log.Fatal().Err(err).Msgf("The PID file: %s, is in an unacceptable state", conf.PIDFilename) }