utils.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package types
  2. import (
  3. "bytes"
  4. "encoding/gob"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "os"
  9. "path/filepath"
  10. "runtime/debug"
  11. "strconv"
  12. "strings"
  13. "time"
  14. "github.com/crowdsecurity/crowdsec/pkg/cwversion"
  15. log "github.com/sirupsen/logrus"
  16. "gopkg.in/natefinch/lumberjack.v2"
  17. )
  18. var logFormatter log.Formatter
  19. var LogOutput *lumberjack.Logger //io.Writer
  20. var logLevel log.Level
  21. func SetDefaultLoggerConfig(cfgMode string, cfgFolder string, cfgLevel log.Level, maxSize int, maxFiles int, maxAge int, compress *bool) error {
  22. /*Configure logs*/
  23. if cfgMode == "file" {
  24. _maxsize := 500
  25. if maxSize != 0 {
  26. _maxsize = maxSize
  27. }
  28. _maxfiles := 3
  29. if maxFiles != 0 {
  30. _maxfiles = maxFiles
  31. }
  32. _maxage := 28
  33. if maxAge != 0 {
  34. _maxage = maxAge
  35. }
  36. _compress := true
  37. if compress != nil {
  38. _compress = *compress
  39. }
  40. LogOutput = &lumberjack.Logger{
  41. Filename: cfgFolder + "/crowdsec.log",
  42. MaxSize: _maxsize,
  43. MaxBackups: _maxfiles,
  44. MaxAge: _maxage,
  45. Compress: _compress,
  46. }
  47. log.SetOutput(LogOutput)
  48. } else if cfgMode != "stdout" {
  49. return fmt.Errorf("log mode '%s' unknown", cfgMode)
  50. }
  51. logLevel = cfgLevel
  52. log.SetLevel(logLevel)
  53. logFormatter = &log.TextFormatter{TimestampFormat: "02-01-2006 15:04:05", FullTimestamp: true}
  54. log.SetFormatter(logFormatter)
  55. return nil
  56. }
  57. func ConfigureLogger(clog *log.Logger) error {
  58. /*Configure logs*/
  59. if LogOutput != nil {
  60. clog.SetOutput(LogOutput)
  61. }
  62. if logFormatter != nil {
  63. clog.SetFormatter(logFormatter)
  64. }
  65. clog.SetLevel(logLevel)
  66. return nil
  67. }
  68. func Clone(a, b interface{}) error {
  69. buff := new(bytes.Buffer)
  70. enc := gob.NewEncoder(buff)
  71. dec := gob.NewDecoder(buff)
  72. if err := enc.Encode(a); err != nil {
  73. return fmt.Errorf("failed cloning %T", a)
  74. }
  75. if err := dec.Decode(b); err != nil {
  76. return fmt.Errorf("failed cloning %T", b)
  77. }
  78. return nil
  79. }
  80. func WriteStackTrace(iErr interface{}) string {
  81. tmpfile, err := ioutil.TempFile("/tmp/", "crowdsec-crash.*.txt")
  82. if err != nil {
  83. log.Fatal(err)
  84. }
  85. if _, err := tmpfile.Write([]byte(fmt.Sprintf("error : %+v\n", iErr))); err != nil {
  86. tmpfile.Close()
  87. log.Fatal(err)
  88. }
  89. if _, err := tmpfile.Write([]byte(cwversion.ShowStr())); err != nil {
  90. tmpfile.Close()
  91. log.Fatal(err)
  92. }
  93. if _, err := tmpfile.Write(debug.Stack()); err != nil {
  94. tmpfile.Close()
  95. log.Fatal(err)
  96. }
  97. if err := tmpfile.Close(); err != nil {
  98. log.Fatal(err)
  99. }
  100. return tmpfile.Name()
  101. }
  102. //CatchPanic is a util func that we should call from all go-routines to ensure proper stacktrace handling
  103. func CatchPanic(component string) {
  104. if r := recover(); r != nil {
  105. log.Errorf("crowdsec - goroutine %s crashed : %s", component, r)
  106. log.Errorf("please report this error to https://github.com/crowdsecurity/crowdsec/")
  107. filename := WriteStackTrace(r)
  108. log.Errorf("stacktrace/report is written to %s : please join it to your issue", filename)
  109. log.Fatalf("crowdsec stopped")
  110. }
  111. }
  112. func ParseDuration(d string) (time.Duration, error) {
  113. durationStr := d
  114. if strings.HasSuffix(d, "d") {
  115. days := strings.Split(d, "d")[0]
  116. if len(days) == 0 {
  117. return 0, fmt.Errorf("'%s' can't be parsed as duration", d)
  118. }
  119. daysInt, err := strconv.Atoi(days)
  120. if err != nil {
  121. return 0, err
  122. }
  123. durationStr = strconv.Itoa(daysInt*24) + "h"
  124. }
  125. duration, err := time.ParseDuration(durationStr)
  126. if err != nil {
  127. return 0, err
  128. }
  129. return duration, nil
  130. }
  131. /*help to copy the file, ioutil doesn't offer the feature*/
  132. func copyFileContents(src, dst string) (err error) {
  133. in, err := os.Open(src)
  134. if err != nil {
  135. return
  136. }
  137. defer in.Close()
  138. out, err := os.Create(dst)
  139. if err != nil {
  140. return
  141. }
  142. defer func() {
  143. cerr := out.Close()
  144. if err == nil {
  145. err = cerr
  146. }
  147. }()
  148. if _, err = io.Copy(out, in); err != nil {
  149. return
  150. }
  151. err = out.Sync()
  152. return
  153. }
  154. /*copy the file, ioutile doesn't offer the feature*/
  155. func CopyFile(sourceSymLink, destinationFile string) (err error) {
  156. sourceFile, err := filepath.EvalSymlinks(sourceSymLink)
  157. if err != nil {
  158. log.Infof("Not a symlink : %s", err)
  159. sourceFile = sourceSymLink
  160. }
  161. sourceFileStat, err := os.Stat(sourceFile)
  162. if err != nil {
  163. return
  164. }
  165. if !sourceFileStat.Mode().IsRegular() {
  166. // cannot copy non-regular files (e.g., directories,
  167. // symlinks, devices, etc.)
  168. return fmt.Errorf("copyFile: non-regular source file %s (%q)", sourceFileStat.Name(), sourceFileStat.Mode().String())
  169. }
  170. destinationFileStat, err := os.Stat(destinationFile)
  171. if err != nil {
  172. if !os.IsNotExist(err) {
  173. return
  174. }
  175. } else {
  176. if !(destinationFileStat.Mode().IsRegular()) {
  177. return fmt.Errorf("copyFile: non-regular destination file %s (%q)", destinationFileStat.Name(), destinationFileStat.Mode().String())
  178. }
  179. if os.SameFile(sourceFileStat, destinationFileStat) {
  180. return
  181. }
  182. }
  183. if err = os.Link(sourceFile, destinationFile); err == nil {
  184. return
  185. }
  186. err = copyFileContents(sourceFile, destinationFile)
  187. return
  188. }
  189. func StrPtr(s string) *string {
  190. return &s
  191. }
  192. func Int32Ptr(i int32) *int32 {
  193. return &i
  194. }
  195. func BoolPtr(b bool) *bool {
  196. return &b
  197. }