writer.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. package logx
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "log"
  7. "path"
  8. "strings"
  9. "sync"
  10. "sync/atomic"
  11. fatihcolor "github.com/fatih/color"
  12. "github.com/zeromicro/go-zero/core/color"
  13. )
  14. type (
  15. Writer interface {
  16. Alert(v interface{})
  17. Close() error
  18. Error(v interface{}, fields ...LogField)
  19. Info(v interface{}, fields ...LogField)
  20. Severe(v interface{})
  21. Slow(v interface{}, fields ...LogField)
  22. Stack(v interface{})
  23. Stat(v interface{}, fields ...LogField)
  24. }
  25. atomicWriter struct {
  26. writer Writer
  27. lock sync.RWMutex
  28. }
  29. concreteWriter struct {
  30. infoLog io.WriteCloser
  31. errorLog io.WriteCloser
  32. severeLog io.WriteCloser
  33. slowLog io.WriteCloser
  34. statLog io.WriteCloser
  35. stackLog io.Writer
  36. }
  37. )
  38. // NewWriter creates a new Writer with the given io.Writer.
  39. func NewWriter(w io.Writer) Writer {
  40. lw := newLogWriter(log.New(w, "", flags))
  41. return &concreteWriter{
  42. infoLog: lw,
  43. errorLog: lw,
  44. severeLog: lw,
  45. slowLog: lw,
  46. statLog: lw,
  47. stackLog: lw,
  48. }
  49. }
  50. func (w *atomicWriter) Load() Writer {
  51. w.lock.RLock()
  52. defer w.lock.RUnlock()
  53. return w.writer
  54. }
  55. func (w *atomicWriter) Store(v Writer) {
  56. w.lock.Lock()
  57. defer w.lock.Unlock()
  58. w.writer = v
  59. }
  60. func (w *atomicWriter) Swap(v Writer) Writer {
  61. w.lock.Lock()
  62. defer w.lock.Unlock()
  63. old := w.writer
  64. w.writer = v
  65. return old
  66. }
  67. func newConsoleWriter() Writer {
  68. outLog := newLogWriter(log.New(fatihcolor.Output, "", flags))
  69. errLog := newLogWriter(log.New(fatihcolor.Error, "", flags))
  70. return &concreteWriter{
  71. infoLog: outLog,
  72. errorLog: errLog,
  73. severeLog: errLog,
  74. slowLog: errLog,
  75. stackLog: newLessWriter(errLog, options.logStackCooldownMills),
  76. statLog: outLog,
  77. }
  78. }
  79. func newFileWriter(c LogConf) (Writer, error) {
  80. var err error
  81. var opts []LogOption
  82. var infoLog io.WriteCloser
  83. var errorLog io.WriteCloser
  84. var severeLog io.WriteCloser
  85. var slowLog io.WriteCloser
  86. var statLog io.WriteCloser
  87. var stackLog io.Writer
  88. if len(c.Path) == 0 {
  89. return nil, ErrLogPathNotSet
  90. }
  91. opts = append(opts, WithCooldownMillis(c.StackCooldownMillis))
  92. if c.Compress {
  93. opts = append(opts, WithGzip())
  94. }
  95. if c.KeepDays > 0 {
  96. opts = append(opts, WithKeepDays(c.KeepDays))
  97. }
  98. if c.MaxBackups > 0 {
  99. opts = append(opts, WithMaxBackups(c.MaxBackups))
  100. }
  101. if c.MaxSize > 0 {
  102. opts = append(opts, WithMaxSize(c.MaxSize))
  103. }
  104. opts = append(opts, WithRotation(c.Rotation))
  105. accessFile := path.Join(c.Path, accessFilename)
  106. errorFile := path.Join(c.Path, errorFilename)
  107. severeFile := path.Join(c.Path, severeFilename)
  108. slowFile := path.Join(c.Path, slowFilename)
  109. statFile := path.Join(c.Path, statFilename)
  110. handleOptions(opts)
  111. setupLogLevel(c)
  112. if infoLog, err = createOutput(accessFile); err != nil {
  113. return nil, err
  114. }
  115. if errorLog, err = createOutput(errorFile); err != nil {
  116. return nil, err
  117. }
  118. if severeLog, err = createOutput(severeFile); err != nil {
  119. return nil, err
  120. }
  121. if slowLog, err = createOutput(slowFile); err != nil {
  122. return nil, err
  123. }
  124. if statLog, err = createOutput(statFile); err != nil {
  125. return nil, err
  126. }
  127. stackLog = newLessWriter(errorLog, options.logStackCooldownMills)
  128. return &concreteWriter{
  129. infoLog: infoLog,
  130. errorLog: errorLog,
  131. severeLog: severeLog,
  132. slowLog: slowLog,
  133. statLog: statLog,
  134. stackLog: stackLog,
  135. }, nil
  136. }
  137. func (w *concreteWriter) Alert(v interface{}) {
  138. output(w.errorLog, levelAlert, v)
  139. }
  140. func (w *concreteWriter) Close() error {
  141. if err := w.infoLog.Close(); err != nil {
  142. return err
  143. }
  144. if err := w.errorLog.Close(); err != nil {
  145. return err
  146. }
  147. if err := w.severeLog.Close(); err != nil {
  148. return err
  149. }
  150. if err := w.slowLog.Close(); err != nil {
  151. return err
  152. }
  153. return w.statLog.Close()
  154. }
  155. func (w *concreteWriter) Error(v interface{}, fields ...LogField) {
  156. output(w.errorLog, levelError, v, fields...)
  157. }
  158. func (w *concreteWriter) Info(v interface{}, fields ...LogField) {
  159. output(w.infoLog, levelInfo, v, fields...)
  160. }
  161. func (w *concreteWriter) Severe(v interface{}) {
  162. output(w.severeLog, levelFatal, v)
  163. }
  164. func (w *concreteWriter) Slow(v interface{}, fields ...LogField) {
  165. output(w.slowLog, levelSlow, v, fields...)
  166. }
  167. func (w *concreteWriter) Stack(v interface{}) {
  168. output(w.stackLog, levelError, v)
  169. }
  170. func (w *concreteWriter) Stat(v interface{}, fields ...LogField) {
  171. output(w.statLog, levelStat, v, fields...)
  172. }
  173. type nopWriter struct{}
  174. func (n nopWriter) Alert(_ interface{}) {
  175. }
  176. func (n nopWriter) Close() error {
  177. return nil
  178. }
  179. func (n nopWriter) Error(_ interface{}, _ ...LogField) {
  180. }
  181. func (n nopWriter) Info(_ interface{}, _ ...LogField) {
  182. }
  183. func (n nopWriter) Severe(_ interface{}) {
  184. }
  185. func (n nopWriter) Slow(_ interface{}, _ ...LogField) {
  186. }
  187. func (n nopWriter) Stack(_ interface{}) {
  188. }
  189. func (n nopWriter) Stat(_ interface{}, _ ...LogField) {
  190. }
  191. func buildFields(fields ...LogField) []string {
  192. var items []string
  193. for _, field := range fields {
  194. items = append(items, fmt.Sprintf("%s=%v", field.Key, field.Value))
  195. }
  196. return items
  197. }
  198. func output(writer io.Writer, level string, val interface{}, fields ...LogField) {
  199. fields = append(fields, Field(callerKey, getCaller(callerDepth)))
  200. switch atomic.LoadUint32(&encoding) {
  201. case plainEncodingType:
  202. writePlainAny(writer, level, val, buildFields(fields...)...)
  203. default:
  204. entry := make(logEntryWithFields)
  205. for _, field := range fields {
  206. entry[field.Key] = field.Value
  207. }
  208. entry[timestampKey] = getTimestamp()
  209. entry[levelKey] = level
  210. entry[contentKey] = val
  211. writeJson(writer, entry)
  212. }
  213. }
  214. func wrapLevelWithColor(level string) string {
  215. var colour color.Color
  216. switch level {
  217. case levelAlert:
  218. colour = color.FgRed
  219. case levelError:
  220. colour = color.FgRed
  221. case levelFatal:
  222. colour = color.FgRed
  223. case levelInfo:
  224. colour = color.FgBlue
  225. case levelSlow:
  226. colour = color.FgYellow
  227. case levelStat:
  228. colour = color.FgGreen
  229. }
  230. if colour == color.NoColor {
  231. return level
  232. }
  233. return color.WithColorPadding(level, colour)
  234. }
  235. func writeJson(writer io.Writer, info interface{}) {
  236. if content, err := json.Marshal(info); err != nil {
  237. log.Println(err.Error())
  238. } else if writer == nil {
  239. log.Println(string(content))
  240. } else {
  241. writer.Write(append(content, '\n'))
  242. }
  243. }
  244. func writePlainAny(writer io.Writer, level string, val interface{}, fields ...string) {
  245. level = wrapLevelWithColor(level)
  246. switch v := val.(type) {
  247. case string:
  248. writePlainText(writer, level, v, fields...)
  249. case error:
  250. writePlainText(writer, level, v.Error(), fields...)
  251. case fmt.Stringer:
  252. writePlainText(writer, level, v.String(), fields...)
  253. default:
  254. writePlainValue(writer, level, v, fields...)
  255. }
  256. }
  257. func writePlainText(writer io.Writer, level, msg string, fields ...string) {
  258. var buf strings.Builder
  259. buf.WriteString(getTimestamp())
  260. buf.WriteByte(plainEncodingSep)
  261. buf.WriteString(level)
  262. buf.WriteByte(plainEncodingSep)
  263. buf.WriteString(msg)
  264. for _, item := range fields {
  265. buf.WriteByte(plainEncodingSep)
  266. buf.WriteString(item)
  267. }
  268. buf.WriteByte('\n')
  269. if writer == nil {
  270. log.Println(buf.String())
  271. return
  272. }
  273. if _, err := fmt.Fprint(writer, buf.String()); err != nil {
  274. log.Println(err.Error())
  275. }
  276. }
  277. func writePlainValue(writer io.Writer, level string, val interface{}, fields ...string) {
  278. var buf strings.Builder
  279. buf.WriteString(getTimestamp())
  280. buf.WriteByte(plainEncodingSep)
  281. buf.WriteString(level)
  282. buf.WriteByte(plainEncodingSep)
  283. if err := json.NewEncoder(&buf).Encode(val); err != nil {
  284. log.Println(err.Error())
  285. return
  286. }
  287. for _, item := range fields {
  288. buf.WriteByte(plainEncodingSep)
  289. buf.WriteString(item)
  290. }
  291. buf.WriteByte('\n')
  292. if writer == nil {
  293. log.Println(buf.String())
  294. return
  295. }
  296. if _, err := fmt.Fprint(writer, buf.String()); err != nil {
  297. log.Println(err.Error())
  298. }
  299. }