feat(logs) add supports write logs to files (#217)

*  feat(logs) add supports write logs to files

* fix(lint) 🚨 fix go lint

* 🐛 fix(bug) check path is done only if provided

* 📝 doc(vars) add LogFilePath to vars

* 🦺 chore(review) update doc, configuration check and logger
This commit is contained in:
mathieuHa
2025-03-31 20:19:44 +02:00
committed by GitHub
parent a184ae6db9
commit 5418d35feb
7 changed files with 110 additions and 61 deletions
+3 -3
View File
@@ -11,7 +11,7 @@ import (
func Test_Get(t *testing.T) {
IPInCache := "10.0.0.10"
IPNotInCache := "10.0.0.20"
client := &Client{cache: &localCache{}, log: logger.New("INFO")}
client := &Client{cache: &localCache{}, log: logger.New("INFO", "")}
client.Set(IPInCache, BannedValue, 10)
type args struct {
clientIP string
@@ -47,7 +47,7 @@ func Test_Get(t *testing.T) {
}
func Test_Set(t *testing.T) {
client := &Client{cache: &localCache{}, log: logger.New("INFO")}
client := &Client{cache: &localCache{}, log: logger.New("INFO", "")}
IPInCache := "10.0.0.11"
type args struct {
clientIP string
@@ -88,7 +88,7 @@ func Test_Set(t *testing.T) {
func Test_Delete(t *testing.T) {
IPInCache := "10.0.0.12"
IPNotInCache := "10.0.0.22"
client := &Client{cache: &localCache{}, log: logger.New("INFO")}
client := &Client{cache: &localCache{}, log: logger.New("INFO", "")}
client.Set(IPInCache, BannedValue, 10)
type args struct {
clientIP string
+18 -2
View File
@@ -28,6 +28,9 @@ const (
AppsecMode = "appsec"
HTTPS = "https"
HTTP = "http"
LogDEBUG = "DEBUG"
LogINFO = "INFO"
LogERROR = "ERROR"
HcaptchaProvider = "hcaptcha"
RecaptchaProvider = "recaptcha"
TurnstileProvider = "turnstile"
@@ -37,6 +40,7 @@ const (
type Config struct {
Enabled bool `json:"enabled,omitempty"`
LogLevel string `json:"logLevel,omitempty"`
LogFilePath string `json:"logFilePath,omitempty"`
CrowdsecMode string `json:"crowdsecMode,omitempty"`
CrowdsecAppsecEnabled bool `json:"crowdsecAppsecEnabled,omitempty"`
CrowdsecAppsecHost string `json:"crowdsecAppsecHost,omitempty"`
@@ -98,7 +102,8 @@ func contains(source []string, target string) bool {
func New() *Config {
return &Config{
Enabled: false,
LogLevel: "INFO",
LogLevel: LogINFO,
LogFilePath: "",
CrowdsecMode: LiveMode,
CrowdsecAppsecEnabled: false,
CrowdsecAppsecHost: "crowdsec:7422",
@@ -262,6 +267,17 @@ func ValidateParams(config *Config) error {
}
}
// Check logging configuration
if !contains([]string{LogERROR, LogDEBUG, LogINFO}, config.LogLevel) {
return fmt.Errorf("LogLevel should be one of (%s,%s,%s)", LogDEBUG, LogINFO, LogERROR)
}
if config.LogFilePath != "" {
_, err = os.OpenFile(filepath.Clean(config.LogFilePath), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return fmt.Errorf("LogFilePath is not writable %w", err)
}
}
return nil
}
@@ -304,7 +320,7 @@ func validateParamsTLS(config *Config) error {
func validateParamsIPs(listIP []string, key string) error {
if len(listIP) > 0 {
if _, err := ip.NewChecker(logger.New("INFO"), listIP); err != nil {
if _, err := ip.NewChecker(logger.New(LogINFO, ""), listIP); err != nil {
return fmt.Errorf("%s must be a list of IP/CIDR :%w", key, err)
}
}
+1 -1
View File
@@ -233,7 +233,7 @@ func Test_GetTLSConfigCrowdsec(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetTLSConfigCrowdsec(tt.args.config, logger.New("INFO"))
got, err := GetTLSConfigCrowdsec(tt.args.config, logger.New("INFO", ""))
if (err != nil) != tt.wantErr {
t.Errorf("getTLSConfigCrowdsec() error = %v, wantErr %v", err, tt.wantErr)
return
+18 -1
View File
@@ -3,9 +3,11 @@
package logger
import (
"fmt"
"io"
"log"
"os"
"path/filepath"
)
// Log Logger struct.
@@ -16,15 +18,30 @@ type Log struct {
}
// New Set Default log level to info in case log level to defined.
func New(logLevel string) *Log {
func New(logLevel string, logFilePath string) *Log {
logError := log.New(io.Discard, "ERROR: CrowdsecBouncerTraefikPlugin: ", log.Ldate|log.Ltime)
logInfo := log.New(io.Discard, "INFO: CrowdsecBouncerTraefikPlugin: ", log.Ldate|log.Ltime)
logDebug := log.New(io.Discard, "DEBUG: CrowdsecBouncerTraefikPlugin: ", log.Ldate|log.Ltime)
logError.SetOutput(os.Stderr)
logInfo.SetOutput(os.Stdout)
// we initialize logger to STDOUT/STDERR first so if the file logger cannot be initialized we can inform the user
if logLevel == "DEBUG" {
logDebug.SetOutput(os.Stdout)
}
if logFilePath != "" {
logFile, err := os.OpenFile(filepath.Clean(logFilePath), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
_ = fmt.Errorf("LogFilePath is not writable %w", err)
} else {
logInfo.SetOutput(logFile)
logError.SetOutput(logFile)
if logLevel == "DEBUG" {
logDebug.SetOutput(logFile)
}
}
}
return &Log{
logError: logError,
logInfo: logInfo,