utils.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. package types
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/gob"
  6. "fmt"
  7. "io"
  8. "os"
  9. "path/filepath"
  10. "regexp"
  11. "runtime/debug"
  12. "strconv"
  13. "strings"
  14. "time"
  15. log "github.com/sirupsen/logrus"
  16. "gopkg.in/natefinch/lumberjack.v2"
  17. "github.com/crowdsecurity/crowdsec/pkg/cwversion"
  18. )
  19. var logFormatter log.Formatter
  20. var LogOutput *lumberjack.Logger //io.Writer
  21. var logLevel log.Level
  22. func SetDefaultLoggerConfig(cfgMode string, cfgFolder string, cfgLevel log.Level, maxSize int, maxFiles int, maxAge int, compress *bool, forceColors bool) error {
  23. /*Configure logs*/
  24. if cfgMode == "file" {
  25. _maxsize := 500
  26. if maxSize != 0 {
  27. _maxsize = maxSize
  28. }
  29. _maxfiles := 3
  30. if maxFiles != 0 {
  31. _maxfiles = maxFiles
  32. }
  33. _maxage := 28
  34. if maxAge != 0 {
  35. _maxage = maxAge
  36. }
  37. _compress := true
  38. if compress != nil {
  39. _compress = *compress
  40. }
  41. /*cf. https://github.com/natefinch/lumberjack/issues/82
  42. let's create the file beforehand w/ the right perms */
  43. fname := cfgFolder + "/crowdsec.log"
  44. // check if file exists
  45. _, err := os.Stat(fname)
  46. // create file if not exists, purposefully ignore errors
  47. if os.IsNotExist(err) {
  48. file, _ := os.OpenFile(fname, os.O_RDWR|os.O_CREATE, 0600)
  49. file.Close()
  50. }
  51. LogOutput = &lumberjack.Logger{
  52. Filename: fname,
  53. MaxSize: _maxsize,
  54. MaxBackups: _maxfiles,
  55. MaxAge: _maxage,
  56. Compress: _compress,
  57. }
  58. log.SetOutput(LogOutput)
  59. } else if cfgMode != "stdout" {
  60. return fmt.Errorf("log mode '%s' unknown", cfgMode)
  61. }
  62. logLevel = cfgLevel
  63. log.SetLevel(logLevel)
  64. logFormatter = &log.TextFormatter{TimestampFormat: "02-01-2006 15:04:05", FullTimestamp: true, ForceColors: forceColors}
  65. log.SetFormatter(logFormatter)
  66. return nil
  67. }
  68. func ConfigureLogger(clog *log.Logger) error {
  69. /*Configure logs*/
  70. if LogOutput != nil {
  71. clog.SetOutput(LogOutput)
  72. }
  73. if logFormatter != nil {
  74. clog.SetFormatter(logFormatter)
  75. }
  76. clog.SetLevel(logLevel)
  77. return nil
  78. }
  79. func Clone(a, b interface{}) error {
  80. buff := new(bytes.Buffer)
  81. enc := gob.NewEncoder(buff)
  82. dec := gob.NewDecoder(buff)
  83. if err := enc.Encode(a); err != nil {
  84. return fmt.Errorf("failed cloning %T", a)
  85. }
  86. if err := dec.Decode(b); err != nil {
  87. return fmt.Errorf("failed cloning %T", b)
  88. }
  89. return nil
  90. }
  91. func WriteStackTrace(iErr interface{}) string {
  92. tmpfile, err := os.CreateTemp("", "crowdsec-crash.*.txt")
  93. if err != nil {
  94. log.Fatal(err)
  95. }
  96. if _, err := tmpfile.Write([]byte(fmt.Sprintf("error : %+v\n", iErr))); err != nil {
  97. tmpfile.Close()
  98. log.Fatal(err)
  99. }
  100. if _, err := tmpfile.Write([]byte(cwversion.ShowStr())); err != nil {
  101. tmpfile.Close()
  102. log.Fatal(err)
  103. }
  104. if _, err := tmpfile.Write(debug.Stack()); err != nil {
  105. tmpfile.Close()
  106. log.Fatal(err)
  107. }
  108. if err := tmpfile.Close(); err != nil {
  109. log.Fatal(err)
  110. }
  111. return tmpfile.Name()
  112. }
  113. //CatchPanic is a util func that we should call from all go-routines to ensure proper stacktrace handling
  114. func CatchPanic(component string) {
  115. if r := recover(); r != nil {
  116. log.Errorf("crowdsec - goroutine %s crashed : %s", component, r)
  117. log.Errorf("please report this error to https://github.com/crowdsecurity/crowdsec/")
  118. filename := WriteStackTrace(r)
  119. log.Errorf("stacktrace/report is written to %s : please join it to your issue", filename)
  120. log.Fatalf("crowdsec stopped")
  121. }
  122. }
  123. func ParseDuration(d string) (time.Duration, error) {
  124. durationStr := d
  125. if strings.HasSuffix(d, "d") {
  126. days := strings.Split(d, "d")[0]
  127. if len(days) == 0 {
  128. return 0, fmt.Errorf("'%s' can't be parsed as duration", d)
  129. }
  130. daysInt, err := strconv.Atoi(days)
  131. if err != nil {
  132. return 0, err
  133. }
  134. durationStr = strconv.Itoa(daysInt*24) + "h"
  135. }
  136. duration, err := time.ParseDuration(durationStr)
  137. if err != nil {
  138. return 0, err
  139. }
  140. return duration, nil
  141. }
  142. /*help to copy the file, ioutil doesn't offer the feature*/
  143. func copyFileContents(src, dst string) (err error) {
  144. in, err := os.Open(src)
  145. if err != nil {
  146. return
  147. }
  148. defer in.Close()
  149. out, err := os.Create(dst)
  150. if err != nil {
  151. return
  152. }
  153. defer func() {
  154. cerr := out.Close()
  155. if err == nil {
  156. err = cerr
  157. }
  158. }()
  159. if _, err = io.Copy(out, in); err != nil {
  160. return
  161. }
  162. err = out.Sync()
  163. return
  164. }
  165. /*copy the file, ioutile doesn't offer the feature*/
  166. func CopyFile(sourceSymLink, destinationFile string) (err error) {
  167. sourceFile, err := filepath.EvalSymlinks(sourceSymLink)
  168. if err != nil {
  169. log.Infof("Not a symlink : %s", err)
  170. sourceFile = sourceSymLink
  171. }
  172. sourceFileStat, err := os.Stat(sourceFile)
  173. if err != nil {
  174. return
  175. }
  176. if !sourceFileStat.Mode().IsRegular() {
  177. // cannot copy non-regular files (e.g., directories,
  178. // symlinks, devices, etc.)
  179. return fmt.Errorf("copyFile: non-regular source file %s (%q)", sourceFileStat.Name(), sourceFileStat.Mode().String())
  180. }
  181. destinationFileStat, err := os.Stat(destinationFile)
  182. if err != nil {
  183. if !os.IsNotExist(err) {
  184. return
  185. }
  186. } else {
  187. if !(destinationFileStat.Mode().IsRegular()) {
  188. return fmt.Errorf("copyFile: non-regular destination file %s (%q)", destinationFileStat.Name(), destinationFileStat.Mode().String())
  189. }
  190. if os.SameFile(sourceFileStat, destinationFileStat) {
  191. return
  192. }
  193. }
  194. if err = os.Link(sourceFile, destinationFile); err == nil {
  195. return
  196. }
  197. err = copyFileContents(sourceFile, destinationFile)
  198. return
  199. }
  200. func StrPtr(s string) *string {
  201. return &s
  202. }
  203. func IntPtr(i int) *int {
  204. return &i
  205. }
  206. func Int32Ptr(i int32) *int32 {
  207. return &i
  208. }
  209. func BoolPtr(b bool) *bool {
  210. return &b
  211. }
  212. func InSlice(str string, slice []string) bool {
  213. for _, item := range slice {
  214. if str == item {
  215. return true
  216. }
  217. }
  218. return false
  219. }
  220. func UtcNow() time.Time {
  221. return time.Now().UTC()
  222. }
  223. func GetLineCountForFile(filepath string) int {
  224. f, err := os.Open(filepath)
  225. if err != nil {
  226. log.Fatalf("unable to open log file %s : %s", filepath, err)
  227. }
  228. defer f.Close()
  229. lc := 0
  230. fs := bufio.NewScanner(f)
  231. for fs.Scan() {
  232. lc++
  233. }
  234. return lc
  235. }
  236. // from https://github.com/acarl005/stripansi
  237. var reStripAnsi = regexp.MustCompile("[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))")
  238. func StripAnsiString(str string) string {
  239. // the byte version doesn't strip correctly
  240. return reStripAnsi.ReplaceAllString(str, "")
  241. }