github.com/holochain/holochain-proto@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/log.go (about) 1 // Copyright (C) 2013-2017, The MetaCurrency Project (Eric Harris-Braun, Arthur Brock, et. al.) 2 // Use of this source code is governed by GPLv3 found in the LICENSE file 3 //---------------------------------------------------------------------------------------- 4 5 // log encapsulates logging 6 7 package holochain 8 9 import ( 10 "fmt" 11 "github.com/fatih/color" 12 "io" 13 "os" 14 "path/filepath" 15 "regexp" 16 "runtime" 17 "strings" 18 "time" 19 ) 20 21 // Logger holds logger configuration 22 type Logger struct { 23 Name string 24 Enabled bool 25 Format string 26 f string 27 tf string 28 color *color.Color 29 w io.Writer 30 31 Prefix string 32 PrefixColor *color.Color 33 } 34 35 var colorMap map[string]*color.Color 36 var EnableAllLoggersEnv string = "HC_ENABLE_ALL_LOGS" 37 38 func (h *Logger) GetColor(colorName string) *color.Color { 39 if _, ok := colorMap["red"]; !ok { 40 colorMap = make(map[string]*color.Color) 41 colorMap["red"] = color.New(color.FgRed) 42 colorMap["blue"] = color.New(color.FgBlue) 43 colorMap["green"] = color.New(color.FgGreen) 44 colorMap["yellow"] = color.New(color.FgYellow) 45 colorMap["white"] = color.New(color.FgWhite) 46 colorMap["cyan"] = color.New(color.FgCyan) 47 colorMap["magenta"] = color.New(color.FgMagenta) 48 } 49 if val, ok := colorMap[colorName]; ok { 50 return val 51 } else { 52 return colorMap["white"] 53 } 54 } 55 56 func (l *Logger) setupColor(f string) (colorResult *color.Color, result string) { 57 re := regexp.MustCompile(`(.*)\%\{color:([^\}]+)\}(.*)`) 58 x := re.FindStringSubmatch(f) 59 var txtColor string 60 if len(x) > 0 { 61 result = x[1] + x[3] 62 txtColor = x[2] 63 } else { 64 result = f 65 } 66 67 if txtColor != "" { 68 colorResult = l.GetColor(txtColor) 69 } 70 return 71 } 72 73 func (l *Logger) setupTime(f string) (timeFormat string, result string) { 74 re := regexp.MustCompile(`(.*)\%\{time(:[^\}]+)*\}(.*)`) 75 x := re.FindStringSubmatch(f) 76 if len(x) > 0 { 77 result = x[1] + "%{time}" + x[3] 78 timeFormat = strings.TrimLeft(x[2], ":") 79 if timeFormat == "" { 80 timeFormat = time.Stamp 81 } 82 } else { 83 result = f 84 } 85 return 86 } 87 88 func (l *Logger) New(w io.Writer) (err error) { 89 90 if w == nil { 91 l.w = os.Stdout 92 } else { 93 l.w = w 94 } 95 96 if l.Format == "" { 97 l.f = `%{message}` 98 l.color = nil 99 } else { 100 l.color, l.f = l.setupColor(l.Format) 101 l.tf, l.f = l.setupTime(l.f) 102 } 103 104 d := os.Getenv(EnableAllLoggersEnv) 105 switch d { 106 case "1": 107 l.Enabled = true 108 case "0": 109 l.Enabled = false 110 } 111 112 return 113 } 114 115 func (l *Logger) SetPrefix(prefixFormat string) { 116 l.PrefixColor, l.Prefix = l.setupColor(prefixFormat) 117 } 118 119 func (l *Logger) parse(m string) (output string) { 120 var t *time.Time 121 if l.tf != "" { 122 now := time.Now() 123 t = &now 124 } 125 return l._parse(m, t) 126 } 127 128 func (l *Logger) _parse(m string, t *time.Time) (output string) { 129 output = strings.Replace(l.f, "%{message}", m, -1) 130 if t != nil { 131 tTxt := t.Format(l.tf) 132 output = strings.Replace(output, "%{time}", tTxt, -1) 133 } 134 135 // TODO add the calling depth to the line format string. 136 re := regexp.MustCompile(`(%{line})|(%{file})`) 137 matches := re.FindStringSubmatch(l.f) 138 if len(matches) > 0 { 139 _, file, line, ok := runtime.Caller(6) 140 if ok { 141 // sometimes the stack is one less deep than we expect in which case 142 // the file shows "asm_" so check for this case and redo! 143 if strings.Index(file, "asm_") > 0 { 144 _, file, line, ok = runtime.Caller(5) 145 } 146 output = strings.Replace(output, "%{file}", filepath.Base(file), -1) 147 output = strings.Replace(output, "%{line}", fmt.Sprintf("%d", line), -1) 148 } 149 } 150 return 151 } 152 153 func (l *Logger) p(m interface{}) { 154 l.pf("%v", m) 155 } 156 157 func (l *Logger) pf(m string, args ...interface{}) { 158 if l != nil && l.Enabled { 159 l.prefixPrint() 160 f := l.parse(m) 161 if l.color != nil { 162 l.color.Fprintf(l.w, f+"\n", args...) 163 } else { 164 fmt.Fprintf(l.w, f+"\n", args...) 165 } 166 } 167 } 168 169 func (l *Logger) prefixPrint(args ...interface{}) { 170 if l.PrefixColor != nil { 171 l.PrefixColor.Fprintf(l.w, l.Prefix, args...) 172 } else { 173 fmt.Fprintf(l.w, l.Prefix, args...) 174 } 175 } 176 177 func (l *Logger) Log(m interface{}) { 178 l.p(m) 179 } 180 181 func (l *Logger) Logf(m string, args ...interface{}) { 182 l.pf(m, args...) 183 }