writer.go 7.7 KB

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