log.go 7.0 KB

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