123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- package types
- import (
- "bufio"
- "bytes"
- "encoding/gob"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "runtime/debug"
- "strconv"
- "strings"
- "time"
- "github.com/crowdsecurity/crowdsec/pkg/cwversion"
- log "github.com/sirupsen/logrus"
- "gopkg.in/natefinch/lumberjack.v2"
- )
- var logFormatter log.Formatter
- var LogOutput *lumberjack.Logger //io.Writer
- var logLevel log.Level
- func SetDefaultLoggerConfig(cfgMode string, cfgFolder string, cfgLevel log.Level, maxSize int, maxFiles int, maxAge int, compress *bool) error {
- /*Configure logs*/
- if cfgMode == "file" {
- _maxsize := 500
- if maxSize != 0 {
- _maxsize = maxSize
- }
- _maxfiles := 3
- if maxFiles != 0 {
- _maxfiles = maxFiles
- }
- _maxage := 28
- if maxAge != 0 {
- _maxage = maxAge
- }
- _compress := true
- if compress != nil {
- _compress = *compress
- }
- /*cf. https://github.com/natefinch/lumberjack/issues/82
- let's create the file beforehand w/ the right perms */
- fname := cfgFolder + "/crowdsec.log"
- // check if file exists
- _, err := os.Stat(fname)
- // create file if not exists, purposefully ignore errors
- if os.IsNotExist(err) {
- file, _ := os.OpenFile(fname, os.O_RDWR|os.O_CREATE, 0600)
- file.Close()
- }
- LogOutput = &lumberjack.Logger{
- Filename: fname,
- MaxSize: _maxsize,
- MaxBackups: _maxfiles,
- MaxAge: _maxage,
- Compress: _compress,
- }
- log.SetOutput(LogOutput)
- } else if cfgMode != "stdout" {
- return fmt.Errorf("log mode '%s' unknown", cfgMode)
- }
- logLevel = cfgLevel
- log.SetLevel(logLevel)
- logFormatter = &log.TextFormatter{TimestampFormat: "02-01-2006 15:04:05", FullTimestamp: true}
- log.SetFormatter(logFormatter)
- return nil
- }
- func ConfigureLogger(clog *log.Logger) error {
- /*Configure logs*/
- if LogOutput != nil {
- clog.SetOutput(LogOutput)
- }
- if logFormatter != nil {
- clog.SetFormatter(logFormatter)
- }
- clog.SetLevel(logLevel)
- return nil
- }
- func Clone(a, b interface{}) error {
- buff := new(bytes.Buffer)
- enc := gob.NewEncoder(buff)
- dec := gob.NewDecoder(buff)
- if err := enc.Encode(a); err != nil {
- return fmt.Errorf("failed cloning %T", a)
- }
- if err := dec.Decode(b); err != nil {
- return fmt.Errorf("failed cloning %T", b)
- }
- return nil
- }
- func WriteStackTrace(iErr interface{}) string {
- tmpfile, err := ioutil.TempFile("", "crowdsec-crash.*.txt")
- if err != nil {
- log.Fatal(err)
- }
- if _, err := tmpfile.Write([]byte(fmt.Sprintf("error : %+v\n", iErr))); err != nil {
- tmpfile.Close()
- log.Fatal(err)
- }
- if _, err := tmpfile.Write([]byte(cwversion.ShowStr())); err != nil {
- tmpfile.Close()
- log.Fatal(err)
- }
- if _, err := tmpfile.Write(debug.Stack()); err != nil {
- tmpfile.Close()
- log.Fatal(err)
- }
- if err := tmpfile.Close(); err != nil {
- log.Fatal(err)
- }
- return tmpfile.Name()
- }
- //CatchPanic is a util func that we should call from all go-routines to ensure proper stacktrace handling
- func CatchPanic(component string) {
- if r := recover(); r != nil {
- log.Errorf("crowdsec - goroutine %s crashed : %s", component, r)
- log.Errorf("please report this error to https://github.com/crowdsecurity/crowdsec/")
- filename := WriteStackTrace(r)
- log.Errorf("stacktrace/report is written to %s : please join it to your issue", filename)
- log.Fatalf("crowdsec stopped")
- }
- }
- func ParseDuration(d string) (time.Duration, error) {
- durationStr := d
- if strings.HasSuffix(d, "d") {
- days := strings.Split(d, "d")[0]
- if len(days) == 0 {
- return 0, fmt.Errorf("'%s' can't be parsed as duration", d)
- }
- daysInt, err := strconv.Atoi(days)
- if err != nil {
- return 0, err
- }
- durationStr = strconv.Itoa(daysInt*24) + "h"
- }
- duration, err := time.ParseDuration(durationStr)
- if err != nil {
- return 0, err
- }
- return duration, nil
- }
- /*help to copy the file, ioutil doesn't offer the feature*/
- func copyFileContents(src, dst string) (err error) {
- in, err := os.Open(src)
- if err != nil {
- return
- }
- defer in.Close()
- out, err := os.Create(dst)
- if err != nil {
- return
- }
- defer func() {
- cerr := out.Close()
- if err == nil {
- err = cerr
- }
- }()
- if _, err = io.Copy(out, in); err != nil {
- return
- }
- err = out.Sync()
- return
- }
- /*copy the file, ioutile doesn't offer the feature*/
- func CopyFile(sourceSymLink, destinationFile string) (err error) {
- sourceFile, err := filepath.EvalSymlinks(sourceSymLink)
- if err != nil {
- log.Infof("Not a symlink : %s", err)
- sourceFile = sourceSymLink
- }
- sourceFileStat, err := os.Stat(sourceFile)
- if err != nil {
- return
- }
- if !sourceFileStat.Mode().IsRegular() {
- // cannot copy non-regular files (e.g., directories,
- // symlinks, devices, etc.)
- return fmt.Errorf("copyFile: non-regular source file %s (%q)", sourceFileStat.Name(), sourceFileStat.Mode().String())
- }
- destinationFileStat, err := os.Stat(destinationFile)
- if err != nil {
- if !os.IsNotExist(err) {
- return
- }
- } else {
- if !(destinationFileStat.Mode().IsRegular()) {
- return fmt.Errorf("copyFile: non-regular destination file %s (%q)", destinationFileStat.Name(), destinationFileStat.Mode().String())
- }
- if os.SameFile(sourceFileStat, destinationFileStat) {
- return
- }
- }
- if err = os.Link(sourceFile, destinationFile); err == nil {
- return
- }
- err = copyFileContents(sourceFile, destinationFile)
- return
- }
- func StrPtr(s string) *string {
- return &s
- }
- func IntPtr(i int) *int {
- return &i
- }
- func Int32Ptr(i int32) *int32 {
- return &i
- }
- func BoolPtr(b bool) *bool {
- return &b
- }
- func InSlice(str string, slice []string) bool {
- for _, item := range slice {
- if str == item {
- return true
- }
- }
- return false
- }
- func UtcNow() time.Time {
- return time.Now().UTC()
- }
- func GetLineCountForFile(filepath string) int {
- f, err := os.Open(filepath)
- if err != nil {
- log.Fatalf("unable to open log file %s : %s", filepath, err)
- }
- defer f.Close()
- lc := 0
- fs := bufio.NewScanner(f)
- for fs.Scan() {
- lc++
- }
- return lc
- }
|