github.com/crowdsecurity/crowdsec@v1.6.1/pkg/appsec/coraza_logger.go (about)

     1  package appsec
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	dbg "github.com/crowdsecurity/coraza/v3/debuglog"
     8  	log "github.com/sirupsen/logrus"
     9  )
    10  
    11  var DebugRules map[int]bool = map[int]bool{}
    12  
    13  func SetRuleDebug(id int, debug bool) {
    14  	DebugRules[id] = debug
    15  }
    16  
    17  func GetRuleDebug(id int) bool {
    18  	if val, ok := DebugRules[id]; ok {
    19  		return val
    20  	}
    21  	return false
    22  }
    23  
    24  // type ContextField func(Event) Event
    25  
    26  type crzLogEvent struct {
    27  	fields log.Fields
    28  	logger *log.Entry
    29  	muted  bool
    30  	level  log.Level
    31  }
    32  
    33  func (e *crzLogEvent) Msg(msg string) {
    34  	if e.muted {
    35  		return
    36  	}
    37  
    38  	/*this is a hack. As we want to have per-level rule debug but it's not allowed by coraza/modsec, if a rule ID is flagged to be in debug mode, the
    39  	.Int("rule_id", <ID>) call will set the log_level of the event to debug. However, given the logger is global to the appsec-runner,
    40  	we are switching forth and back the log level of the logger*/
    41  	oldLvl := e.logger.Logger.GetLevel()
    42  
    43  	if e.level != oldLvl {
    44  		e.logger.Logger.SetLevel(e.level)
    45  	}
    46  
    47  	if len(e.fields) == 0 {
    48  		e.logger.Log(e.level, msg)
    49  	} else {
    50  		e.logger.WithFields(e.fields).Log(e.level, msg)
    51  	}
    52  
    53  	if e.level != oldLvl {
    54  		e.logger.Logger.SetLevel(oldLvl)
    55  		e.level = oldLvl
    56  	}
    57  }
    58  
    59  func (e *crzLogEvent) Str(key, val string) dbg.Event {
    60  	if e.muted {
    61  		return e
    62  	}
    63  	e.fields[key] = val
    64  	return e
    65  }
    66  
    67  func (e *crzLogEvent) Err(err error) dbg.Event {
    68  	if e.muted {
    69  		return e
    70  	}
    71  	e.fields["error"] = err
    72  	return e
    73  }
    74  
    75  func (e *crzLogEvent) Bool(key string, b bool) dbg.Event {
    76  	if e.muted {
    77  		return e
    78  	}
    79  	e.fields[key] = b
    80  	return e
    81  }
    82  
    83  func (e *crzLogEvent) Int(key string, i int) dbg.Event {
    84  	if e.muted {
    85  		//this allows us to have per-rule debug logging
    86  		if key == "rule_id" && GetRuleDebug(i) {
    87  			e.muted = false
    88  			e.fields = map[string]interface{}{}
    89  			e.level = log.DebugLevel
    90  		} else {
    91  			return e
    92  		}
    93  	}
    94  	e.fields[key] = i
    95  	return e
    96  }
    97  
    98  func (e *crzLogEvent) Uint(key string, i uint) dbg.Event {
    99  	if e.muted {
   100  		return e
   101  	}
   102  	e.fields[key] = i
   103  	return e
   104  }
   105  
   106  func (e *crzLogEvent) Stringer(key string, val fmt.Stringer) dbg.Event {
   107  	if e.muted {
   108  		return e
   109  	}
   110  	e.fields[key] = val
   111  	return e
   112  }
   113  
   114  func (e crzLogEvent) IsEnabled() bool {
   115  	return !e.muted
   116  }
   117  
   118  type crzLogger struct {
   119  	logger        *log.Entry
   120  	defaultFields log.Fields
   121  	logLevel      log.Level
   122  }
   123  
   124  func NewCrzLogger(logger *log.Entry) crzLogger {
   125  	return crzLogger{logger: logger, logLevel: logger.Logger.GetLevel()}
   126  }
   127  
   128  func (c crzLogger) NewMutedEvt(lvl log.Level) dbg.Event {
   129  	return &crzLogEvent{muted: true, logger: c.logger, level: lvl}
   130  }
   131  func (c crzLogger) NewEvt(lvl log.Level) dbg.Event {
   132  	evt := &crzLogEvent{fields: map[string]interface{}{}, logger: c.logger, level: lvl}
   133  	if c.defaultFields != nil {
   134  		for k, v := range c.defaultFields {
   135  			evt.fields[k] = v
   136  		}
   137  	}
   138  	return evt
   139  }
   140  
   141  func (c crzLogger) WithOutput(w io.Writer) dbg.Logger {
   142  	return c
   143  }
   144  
   145  func (c crzLogger) WithLevel(lvl dbg.Level) dbg.Logger {
   146  	c.logLevel = log.Level(lvl)
   147  	c.logger.Logger.SetLevel(c.logLevel)
   148  	return c
   149  }
   150  
   151  func (c crzLogger) With(fs ...dbg.ContextField) dbg.Logger {
   152  	var e dbg.Event = c.NewEvt(c.logLevel)
   153  	for _, f := range fs {
   154  		e = f(e)
   155  	}
   156  	c.defaultFields = e.(*crzLogEvent).fields
   157  	return c
   158  }
   159  
   160  func (c crzLogger) Trace() dbg.Event {
   161  	if c.logLevel < log.TraceLevel {
   162  		return c.NewMutedEvt(log.TraceLevel)
   163  	}
   164  	return c.NewEvt(log.TraceLevel)
   165  }
   166  
   167  func (c crzLogger) Debug() dbg.Event {
   168  	if c.logLevel < log.DebugLevel {
   169  		return c.NewMutedEvt(log.DebugLevel)
   170  
   171  	}
   172  	return c.NewEvt(log.DebugLevel)
   173  }
   174  
   175  func (c crzLogger) Info() dbg.Event {
   176  	if c.logLevel < log.InfoLevel {
   177  		return c.NewMutedEvt(log.InfoLevel)
   178  	}
   179  	return c.NewEvt(log.InfoLevel)
   180  }
   181  
   182  func (c crzLogger) Warn() dbg.Event {
   183  	if c.logLevel < log.WarnLevel {
   184  		return c.NewMutedEvt(log.WarnLevel)
   185  	}
   186  	return c.NewEvt(log.WarnLevel)
   187  }
   188  
   189  func (c crzLogger) Error() dbg.Event {
   190  	if c.logLevel < log.ErrorLevel {
   191  		return c.NewMutedEvt(log.ErrorLevel)
   192  	}
   193  	return c.NewEvt(log.ErrorLevel)
   194  }