log.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. package log
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "os"
  8. "path"
  9. "runtime"
  10. "sync"
  11. "time"
  12. "strconv"
  13. "github.com/mattn/go-colorable"
  14. "github.com/mattn/go-isatty"
  15. "github.com/valyala/fasttemplate"
  16. "github.com/labstack/gommon/color"
  17. )
  18. type (
  19. Logger struct {
  20. prefix string
  21. level Lvl
  22. output io.Writer
  23. template *fasttemplate.Template
  24. levels []string
  25. color *color.Color
  26. bufferPool sync.Pool
  27. mutex sync.Mutex
  28. }
  29. Lvl uint8
  30. JSON map[string]interface{}
  31. )
  32. const (
  33. DEBUG Lvl = iota
  34. INFO
  35. WARN
  36. ERROR
  37. FATAL
  38. OFF
  39. )
  40. var (
  41. global = New("-")
  42. defaultHeader = `{"time":"${time_rfc3339}","level":"${level}","prefix":"${prefix}",` +
  43. `"file":"${short_file}","line":"${line}"}`
  44. )
  45. func New(prefix string) (l *Logger) {
  46. l = &Logger{
  47. level: INFO,
  48. prefix: prefix,
  49. template: l.newTemplate(defaultHeader),
  50. color: color.New(),
  51. bufferPool: sync.Pool{
  52. New: func() interface{} {
  53. return bytes.NewBuffer(make([]byte, 256))
  54. },
  55. },
  56. }
  57. l.initLevels()
  58. l.SetOutput(colorable.NewColorableStdout())
  59. return
  60. }
  61. func (l *Logger) initLevels() {
  62. l.levels = []string{
  63. l.color.Blue("DEBUG"),
  64. l.color.Green("INFO"),
  65. l.color.Yellow("WARN"),
  66. l.color.Red("ERROR"),
  67. l.color.RedBg("FATAL"),
  68. }
  69. }
  70. func (l *Logger) newTemplate(format string) *fasttemplate.Template {
  71. return fasttemplate.New(format, "${", "}")
  72. }
  73. func (l *Logger) DisableColor() {
  74. l.color.Disable()
  75. l.initLevels()
  76. }
  77. func (l *Logger) EnableColor() {
  78. l.color.Enable()
  79. l.initLevels()
  80. }
  81. func (l *Logger) Prefix() string {
  82. return l.prefix
  83. }
  84. func (l *Logger) SetPrefix(p string) {
  85. l.prefix = p
  86. }
  87. func (l *Logger) Level() Lvl {
  88. return l.level
  89. }
  90. func (l *Logger) SetLevel(v Lvl) {
  91. l.level = v
  92. }
  93. func (l *Logger) Output() io.Writer {
  94. return l.output
  95. }
  96. func (l *Logger) SetHeader(h string) {
  97. l.template = l.newTemplate(h)
  98. }
  99. func (l *Logger) SetOutput(w io.Writer) {
  100. l.output = w
  101. if w, ok := w.(*os.File); !ok || !isatty.IsTerminal(w.Fd()) {
  102. l.DisableColor()
  103. }
  104. }
  105. func (l *Logger) Print(i ...interface{}) {
  106. fmt.Fprintln(l.output, i...)
  107. }
  108. func (l *Logger) Printf(format string, args ...interface{}) {
  109. f := fmt.Sprintf("%s\n", format)
  110. fmt.Fprintf(l.output, f, args...)
  111. }
  112. func (l *Logger) Printj(j JSON) {
  113. json.NewEncoder(l.output).Encode(j)
  114. }
  115. func (l *Logger) Debug(i ...interface{}) {
  116. l.log(DEBUG, "", i...)
  117. }
  118. func (l *Logger) Debugf(format string, args ...interface{}) {
  119. l.log(DEBUG, format, args...)
  120. }
  121. func (l *Logger) Debugj(j JSON) {
  122. l.log(DEBUG, "json", j)
  123. }
  124. func (l *Logger) Info(i ...interface{}) {
  125. l.log(INFO, "", i...)
  126. }
  127. func (l *Logger) Infof(format string, args ...interface{}) {
  128. l.log(INFO, format, args...)
  129. }
  130. func (l *Logger) Infoj(j JSON) {
  131. l.log(INFO, "json", j)
  132. }
  133. func (l *Logger) Warn(i ...interface{}) {
  134. l.log(WARN, "", i...)
  135. }
  136. func (l *Logger) Warnf(format string, args ...interface{}) {
  137. l.log(WARN, format, args...)
  138. }
  139. func (l *Logger) Warnj(j JSON) {
  140. l.log(WARN, "json", j)
  141. }
  142. func (l *Logger) Error(i ...interface{}) {
  143. l.log(ERROR, "", i...)
  144. }
  145. func (l *Logger) Errorf(format string, args ...interface{}) {
  146. l.log(ERROR, format, args...)
  147. }
  148. func (l *Logger) Errorj(j JSON) {
  149. l.log(ERROR, "json", j)
  150. }
  151. func (l *Logger) Fatal(i ...interface{}) {
  152. l.log(FATAL, "", i...)
  153. os.Exit(1)
  154. }
  155. func (l *Logger) Fatalf(format string, args ...interface{}) {
  156. l.log(FATAL, format, args...)
  157. os.Exit(1)
  158. }
  159. func (l *Logger) Fatalj(j JSON) {
  160. l.log(FATAL, "json", j)
  161. }
  162. func DisableColor() {
  163. global.DisableColor()
  164. }
  165. func EnableColor() {
  166. global.EnableColor()
  167. }
  168. func Prefix() string {
  169. return global.Prefix()
  170. }
  171. func SetPrefix(p string) {
  172. global.SetPrefix(p)
  173. }
  174. func Level() Lvl {
  175. return global.Level()
  176. }
  177. func SetLevel(v Lvl) {
  178. global.SetLevel(v)
  179. }
  180. func Output() io.Writer {
  181. return global.Output()
  182. }
  183. func SetOutput(w io.Writer) {
  184. global.SetOutput(w)
  185. }
  186. func SetHeader(h string) {
  187. global.SetHeader(h)
  188. }
  189. func Print(i ...interface{}) {
  190. global.Print(i...)
  191. }
  192. func Printf(format string, args ...interface{}) {
  193. global.Printf(format, args...)
  194. }
  195. func Printj(j JSON) {
  196. global.Printj(j)
  197. }
  198. func Debug(i ...interface{}) {
  199. global.Debug(i...)
  200. }
  201. func Debugf(format string, args ...interface{}) {
  202. global.Debugf(format, args...)
  203. }
  204. func Debugj(j JSON) {
  205. global.Debugj(j)
  206. }
  207. func Info(i ...interface{}) {
  208. global.Info(i...)
  209. }
  210. func Infof(format string, args ...interface{}) {
  211. global.Infof(format, args...)
  212. }
  213. func Infoj(j JSON) {
  214. global.Infoj(j)
  215. }
  216. func Warn(i ...interface{}) {
  217. global.Warn(i...)
  218. }
  219. func Warnf(format string, args ...interface{}) {
  220. global.Warnf(format, args...)
  221. }
  222. func Warnj(j JSON) {
  223. global.Warnj(j)
  224. }
  225. func Error(i ...interface{}) {
  226. global.Error(i...)
  227. }
  228. func Errorf(format string, args ...interface{}) {
  229. global.Errorf(format, args...)
  230. }
  231. func Errorj(j JSON) {
  232. global.Errorj(j)
  233. }
  234. func Fatal(i ...interface{}) {
  235. global.Fatal(i...)
  236. }
  237. func Fatalf(format string, args ...interface{}) {
  238. global.Fatalf(format, args...)
  239. }
  240. func Fatalj(j JSON) {
  241. global.Fatalj(j)
  242. }
  243. func (l *Logger) log(v Lvl, format string, args ...interface{}) {
  244. l.mutex.Lock()
  245. defer l.mutex.Unlock()
  246. buf := l.bufferPool.Get().(*bytes.Buffer)
  247. buf.Reset()
  248. defer l.bufferPool.Put(buf)
  249. _, file, line, _ := runtime.Caller(3)
  250. if v >= l.level {
  251. message := ""
  252. if format == "" {
  253. message = fmt.Sprint(args...)
  254. } else if format == "json" {
  255. b, err := json.Marshal(args[0])
  256. if err != nil {
  257. panic(err)
  258. }
  259. message = string(b)
  260. } else {
  261. message = fmt.Sprintf(format, args...)
  262. }
  263. if v >= ERROR {
  264. // panic(message)
  265. }
  266. _, err := l.template.ExecuteFunc(buf, func(w io.Writer, tag string) (int, error) {
  267. switch tag {
  268. case "time_rfc3339":
  269. return w.Write([]byte(time.Now().Format(time.RFC3339)))
  270. case "level":
  271. return w.Write([]byte(l.levels[v]))
  272. case "prefix":
  273. return w.Write([]byte(l.prefix))
  274. case "long_file":
  275. return w.Write([]byte(file))
  276. case "short_file":
  277. return w.Write([]byte(path.Base(file)))
  278. case "line":
  279. return w.Write([]byte(strconv.Itoa(line)))
  280. }
  281. return 0, nil
  282. })
  283. if err == nil {
  284. s := buf.String()
  285. i := buf.Len() - 1
  286. if s[i] == '}' {
  287. // JSON header
  288. buf.Truncate(i)
  289. buf.WriteByte(',')
  290. if format == "json" {
  291. buf.WriteString(message[1:])
  292. } else {
  293. buf.WriteString(`"message":"`)
  294. buf.WriteString(message)
  295. buf.WriteString(`"}`)
  296. }
  297. } else {
  298. // Text header
  299. buf.WriteByte(' ')
  300. buf.WriteString(message)
  301. }
  302. buf.WriteByte('\n')
  303. l.output.Write(buf.Bytes())
  304. }
  305. }
  306. }