writer.go 8.2 KB

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