log.go 6.4 KB

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