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  }