Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,12 @@ make run
- Enable the plugin
- LogLevel
- string
- default: `INFO`, expected values are: `INFO`, `DEBUG`, `ERROR`
- default: `INFO`, expected values are: `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`
- Log are written to `stdout` / `stderr` or file if LogFilePath is provided
- LogFormat
- string
- default: `common`, expected values are: `common`, `json`
- Log format: `common` for traditional text logs, `json` for structured JSON logs
- LogFilePath
- string
- default: ""
Expand Down Expand Up @@ -542,6 +546,7 @@ http:
bouncer:
enabled: false
logLevel: DEBUG
logFormat: common
LogFilePath: ""
updateIntervalSeconds: 60
updateMaxFailure: 0
Expand Down
21 changes: 11 additions & 10 deletions bouncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"strconv"
Expand Down Expand Up @@ -112,15 +113,15 @@ type Bouncer struct {
httpClient *http.Client
cacheClient *cache.Client
captchaClient *captcha.Client
log *logger.Log
log *slog.Logger
}

// New creates the crowdsec bouncer plugin.
//
//nolint:gocyclo
func New(_ context.Context, next http.Handler, config *configuration.Config, name string) (http.Handler, error) {
config.LogLevel = strings.ToUpper(config.LogLevel)
log := logger.New(config.LogLevel, config.LogFilePath)
log := logger.NewWithFormat(config.LogLevel, config.LogFilePath, config.LogFormat)
err := configuration.ValidateParams(config)
if err != nil {
log.Error("New:validateParams " + err.Error())
Expand Down Expand Up @@ -306,7 +307,7 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
// if our IP is in the trusted list we bypass the next checks
bouncer.log.Debug(fmt.Sprintf("ServeHTTP ip:%s isTrusted:%v", remoteIP, isTrusted))
bouncer.log.Log(context.Background(), logger.LevelTrace, fmt.Sprintf("ServeHTTP ip:%s isTrusted:%v", remoteIP, isTrusted))
if isTrusted {
bouncer.next.ServeHTTP(rw, req)
return
Expand All @@ -322,7 +323,7 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
value, cacheErr := bouncer.cacheClient.Get(remoteIP)
if cacheErr != nil {
cacheErrString := cacheErr.Error()
bouncer.log.Debug(fmt.Sprintf("ServeHTTP:Get ip:%s isBanned:false %s", remoteIP, cacheErrString))
bouncer.log.Log(context.Background(), logger.LevelTrace, fmt.Sprintf("ServeHTTP:Get ip:%s isBanned:false %s", remoteIP, cacheErrString))
if !bouncer.redisUnreachableBlock && cacheErrString == cache.CacheUnreachable {
bouncer.log.Error(fmt.Sprintf("ServeHTTP:Get ip:%s redisUnreachable=true", remoteIP))
handleNextServeHTTP(bouncer, remoteIP, rw, req)
Expand All @@ -334,7 +335,7 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
} else {
bouncer.log.Debug(fmt.Sprintf("ServeHTTP ip:%s cache:hit isBanned:%v", remoteIP, value))
bouncer.log.Log(context.Background(), logger.LevelTrace, fmt.Sprintf("ServeHTTP ip:%s cache:hit isBanned:%v", remoteIP, value))
if value == cache.NoBannedValue {
handleNextServeHTTP(bouncer, remoteIP, rw, req)
} else {
Expand Down Expand Up @@ -406,12 +407,12 @@ func handleBanServeHTTP(bouncer *Bouncer, rw http.ResponseWriter) {
rw.WriteHeader(bouncer.remediationStatusCode)
_, err := fmt.Fprint(rw, bouncer.banTemplateString)
if err != nil {
bouncer.log.Error("handleBanServeHTTP could not write template to ResponseWriter")
bouncer.log.Warn("handleBanServeHTTP could not write template to ResponseWriter: " + err.Error())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Here you are using the loglevel with "bouncer.log.LOGLEVEL",

Above for Trace, you are using bouncer.log.Log(context, logger.LEVEL)
Is it possible to have it written the same way ?

What's the difference except adding the "context"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes... I did not like that either. The thing is that slog only has convenience methods for the out of the box log levels. I solved that by adding a wrapper so log calls are now consistent.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice, with the wrapper, code looks more readable

}
}

func handleRemediationServeHTTP(bouncer *Bouncer, remoteIP, remediation string, rw http.ResponseWriter, req *http.Request) {
bouncer.log.Debug(fmt.Sprintf("handleRemediationServeHTTP ip:%s remediation:%s", remoteIP, remediation))
bouncer.log.Log(context.Background(), logger.LevelTrace, fmt.Sprintf("handleRemediationServeHTTP ip:%s remediation:%s", remoteIP, remediation))
if bouncer.captchaClient.Valid && remediation == cache.CaptchaValue {
if bouncer.captchaClient.Check(remoteIP) {
handleNextServeHTTP(bouncer, remoteIP, rw, req)
Expand All @@ -427,7 +428,7 @@ func handleRemediationServeHTTP(bouncer *Bouncer, remoteIP, remediation string,
func handleNextServeHTTP(bouncer *Bouncer, remoteIP string, rw http.ResponseWriter, req *http.Request) {
if bouncer.appsecEnabled {
if err := appsecQuery(bouncer, remoteIP, req); err != nil {
bouncer.log.Debug(fmt.Sprintf("handleNextServeHTTP ip:%s isWaf:true %s", remoteIP, err.Error()))
bouncer.log.Log(context.Background(), logger.LevelTrace, fmt.Sprintf("handleNextServeHTTP ip:%s isWaf:true %s", remoteIP, err.Error()))
handleBanServeHTTP(bouncer, rw)
return
}
Expand All @@ -437,7 +438,7 @@ func handleNextServeHTTP(bouncer *Bouncer, remoteIP string, rw http.ResponseWrit

func handleStreamTicker(bouncer *Bouncer) {
if err := handleStreamCache(bouncer); err != nil {
bouncer.log.Debug(fmt.Sprintf("handleStreamTicker updateFailure:%d isCrowdsecStreamHealthy:%t %s", updateFailure, isCrowdsecStreamHealthy, err.Error()))
bouncer.log.Warn(fmt.Sprintf("handleStreamTicker updateFailure:%d isCrowdsecStreamHealthy:%t %s", updateFailure, isCrowdsecStreamHealthy, err.Error()))
if bouncer.updateMaxFailure != -1 && updateFailure >= bouncer.updateMaxFailure && isCrowdsecStreamHealthy {
isCrowdsecStreamHealthy = false
bouncer.log.Error(fmt.Sprintf("handleStreamTicker:error updateFailure:%d %s", updateFailure, err.Error()))
Expand All @@ -455,7 +456,7 @@ func handleMetricsTicker(bouncer *Bouncer) {
}
}

func startTicker(name string, updateInterval int64, log *logger.Log, work func()) chan bool {
func startTicker(name string, updateInterval int64, log *slog.Logger, work func()) chan bool {
ticker := time.NewTicker(time.Duration(updateInterval) * time.Second)
stop := make(chan bool, 1)
go func() {
Expand Down
Loading
Loading