log.go 6.8 KB

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