github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/util/log.go (about) 1 package util 2 3 import ( 4 "bufio" 5 "fmt" 6 "github.com/sirupsen/logrus" 7 "io" 8 "math" 9 "os/exec" 10 "runtime" 11 "strings" 12 ) 13 14 type AddTraceHook struct { 15 Full bool 16 } 17 18 func (h *AddTraceHook) Levels() []logrus.Level { 19 return logrus.AllLevels 20 } 21 22 func (h *AddTraceHook) Fire(entry *logrus.Entry) error { 23 entry.Message = h.addTrace(entry.Message) 24 return nil 25 } 26 27 func (h *AddTraceHook) addTrace(message string) string { 28 skip := 2 29 ok := true 30 var stackTrace []string 31 for { 32 var pc uintptr 33 var fn string 34 var line int 35 pc, fn, line, ok = runtime.Caller(skip) 36 if !ok { 37 break 38 } 39 skip++ 40 41 fnName := runtime.FuncForPC(pc).Name() 42 if strings.Contains(fnName, "logrus.") { 43 continue 44 } 45 fnNameComponents := strings.Split(fnName, "/") 46 truncatedFnName := fnNameComponents[len(fnNameComponents)-1] 47 48 pathComponents := strings.Split(fn, "/") 49 var truncatedPath string 50 if len(pathComponents) > 3 { 51 truncatedPath = strings.Join(pathComponents[len(pathComponents)-2:], "/") 52 } else { 53 truncatedPath = strings.Join(pathComponents, "/") 54 } 55 stackTrace = append(stackTrace, fmt.Sprintf("%s[%s:%d]", truncatedFnName, truncatedPath, line)) 56 if !h.Full { 57 break 58 } 59 } 60 61 maxLen := int(math.Max(float64(len(stackTrace)-2), 1)) 62 for i := 0; i < maxLen/2; i++ { 63 tmp := stackTrace[i] 64 stackTrace[i] = stackTrace[maxLen-i-1] 65 stackTrace[maxLen-i-1] = tmp 66 } 67 file := strings.Join(stackTrace[:maxLen], "\n") 68 message = file + "\n" + message 69 return message 70 } 71 72 func LogCommand(cmd *exec.Cmd, asDebug bool) { 73 logrus.WithField("command", cmd.Args).Debugf("running command") 74 stdout, err := cmd.StdoutPipe() 75 if err != nil { 76 return 77 } 78 stderr, err := cmd.StderrPipe() 79 if err != nil { 80 return 81 } 82 go func() { 83 in := bufio.NewScanner(stdout) 84 for in.Scan() { 85 if asDebug { 86 logrus.Debugf(in.Text()) 87 } else { 88 logrus.Infof(in.Text()) 89 } 90 } 91 }() 92 go func() { 93 in := bufio.NewScanner(stderr) 94 for in.Scan() { 95 logrus.Debugf(in.Text()) 96 } 97 }() 98 } 99 100 type TeeHook struct { 101 W io.Writer 102 } 103 104 func (h *TeeHook) Levels() []logrus.Level { 105 return logrus.AllLevels 106 } 107 108 func (h *TeeHook) Fire(entry *logrus.Entry) error { 109 logger := logrus.New() 110 logger.Out = h.W 111 switch entry.Level { 112 case logrus.PanicLevel: 113 logger.WithFields(entry.Data).Panic(entry.Message) 114 break 115 case logrus.FatalLevel: 116 logger.WithFields(entry.Data).Fatal(entry.Message) 117 break 118 case logrus.ErrorLevel: 119 logger.WithFields(entry.Data).Error(entry.Message) 120 break 121 case logrus.WarnLevel: 122 logger.WithFields(entry.Data).Warnf(entry.Message) 123 break 124 case logrus.InfoLevel: 125 logger.WithFields(entry.Data).Info(entry.Message) 126 break 127 case logrus.DebugLevel: 128 logger.WithFields(entry.Data).Info(entry.Message) 129 break 130 } 131 return nil 132 }