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