writer.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. package logx
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "log"
  7. "os"
  8. "path"
  9. "strings"
  10. "sync"
  11. "sync/atomic"
  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. w.writer = v
  58. w.lock.Unlock()
  59. }
  60. func (w *atomicWriter) Swap(v Writer) Writer {
  61. w.lock.Lock()
  62. old := w.writer
  63. w.writer = v
  64. w.lock.Unlock()
  65. return old
  66. }
  67. func newConsoleWriter() Writer {
  68. outLog := newLogWriter(log.New(os.Stdout, "", flags))
  69. errLog := newLogWriter(log.New(os.Stderr, "", 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. accessFile := path.Join(c.Path, accessFilename)
  99. errorFile := path.Join(c.Path, errorFilename)
  100. severeFile := path.Join(c.Path, severeFilename)
  101. slowFile := path.Join(c.Path, slowFilename)
  102. statFile := path.Join(c.Path, statFilename)
  103. handleOptions(opts)
  104. setupLogLevel(c)
  105. if infoLog, err = createOutput(accessFile); err != nil {
  106. return nil, err
  107. }
  108. if errorLog, err = createOutput(errorFile); err != nil {
  109. return nil, err
  110. }
  111. if severeLog, err = createOutput(severeFile); err != nil {
  112. return nil, err
  113. }
  114. if slowLog, err = createOutput(slowFile); err != nil {
  115. return nil, err
  116. }
  117. if statLog, err = createOutput(statFile); err != nil {
  118. return nil, err
  119. }
  120. stackLog = newLessWriter(errorLog, options.logStackCooldownMills)
  121. return &concreteWriter{
  122. infoLog: infoLog,
  123. errorLog: errorLog,
  124. severeLog: severeLog,
  125. slowLog: slowLog,
  126. statLog: statLog,
  127. stackLog: stackLog,
  128. }, nil
  129. }
  130. func (w *concreteWriter) Alert(v interface{}) {
  131. output(w.errorLog, levelAlert, v)
  132. }
  133. func (w *concreteWriter) Close() error {
  134. if err := w.infoLog.Close(); err != nil {
  135. return err
  136. }
  137. if err := w.errorLog.Close(); err != nil {
  138. return err
  139. }
  140. if err := w.severeLog.Close(); err != nil {
  141. return err
  142. }
  143. if err := w.slowLog.Close(); err != nil {
  144. return err
  145. }
  146. return w.statLog.Close()
  147. }
  148. func (w *concreteWriter) Error(v interface{}, fields ...LogField) {
  149. output(w.errorLog, levelError, v, fields...)
  150. }
  151. func (w *concreteWriter) Info(v interface{}, fields ...LogField) {
  152. output(w.infoLog, levelInfo, v, fields...)
  153. }
  154. func (w *concreteWriter) Severe(v interface{}) {
  155. output(w.severeLog, levelFatal, v)
  156. }
  157. func (w *concreteWriter) Slow(v interface{}, fields ...LogField) {
  158. output(w.slowLog, levelSlow, v, fields...)
  159. }
  160. func (w *concreteWriter) Stack(v interface{}) {
  161. output(w.stackLog, levelError, v)
  162. }
  163. func (w *concreteWriter) Stat(v interface{}, fields ...LogField) {
  164. output(w.statLog, levelStat, v, fields...)
  165. }
  166. type nopWriter struct{}
  167. func (n nopWriter) Alert(_ interface{}) {
  168. }
  169. func (n nopWriter) Close() error {
  170. return nil
  171. }
  172. func (n nopWriter) Error(_ interface{}, _ ...LogField) {
  173. }
  174. func (n nopWriter) Info(_ interface{}, _ ...LogField) {
  175. }
  176. func (n nopWriter) Severe(_ interface{}) {
  177. }
  178. func (n nopWriter) Slow(_ interface{}, _ ...LogField) {
  179. }
  180. func (n nopWriter) Stack(_ interface{}) {
  181. }
  182. func (n nopWriter) Stat(_ interface{}, _ ...LogField) {
  183. }
  184. func buildFields(fields ...LogField) []string {
  185. var items []string
  186. for _, field := range fields {
  187. items = append(items, fmt.Sprintf("%s=%v", field.Key, field.Value))
  188. }
  189. return items
  190. }
  191. func output(writer io.Writer, level string, val interface{}, fields ...LogField) {
  192. fields = append(fields, Field(callerKey, getCaller(callerDepth)))
  193. switch atomic.LoadUint32(&encoding) {
  194. case plainEncodingType:
  195. writePlainAny(writer, level, val, buildFields(fields...)...)
  196. default:
  197. entry := make(logEntryWithFields)
  198. for _, field := range fields {
  199. entry[field.Key] = field.Value
  200. }
  201. entry[timestampKey] = getTimestamp()
  202. entry[levelKey] = level
  203. entry[contentKey] = val
  204. writeJson(writer, entry)
  205. }
  206. }
  207. func wrapLevelWithColor(level string) string {
  208. var colour color.Color
  209. switch level {
  210. case levelAlert:
  211. colour = color.FgRed
  212. case levelError:
  213. colour = color.FgRed
  214. case levelFatal:
  215. colour = color.FgRed
  216. case levelInfo:
  217. colour = color.FgBlue
  218. case levelSlow:
  219. colour = color.FgYellow
  220. case levelStat:
  221. colour = color.FgGreen
  222. }
  223. if colour == color.NoColor {
  224. return level
  225. }
  226. return color.WithColorPadding(level, colour)
  227. }
  228. func writeJson(writer io.Writer, info interface{}) {
  229. if content, err := json.Marshal(info); err != nil {
  230. log.Println(err.Error())
  231. } else if writer == nil {
  232. log.Println(string(content))
  233. } else {
  234. writer.Write(append(content, '\n'))
  235. }
  236. }
  237. func writePlainAny(writer io.Writer, level string, val interface{}, fields ...string) {
  238. level = wrapLevelWithColor(level)
  239. switch v := val.(type) {
  240. case string:
  241. writePlainText(writer, level, v, fields...)
  242. case error:
  243. writePlainText(writer, level, v.Error(), fields...)
  244. case fmt.Stringer:
  245. writePlainText(writer, level, v.String(), fields...)
  246. default:
  247. var buf strings.Builder
  248. buf.WriteString(getTimestamp())
  249. buf.WriteByte(plainEncodingSep)
  250. buf.WriteString(level)
  251. buf.WriteByte(plainEncodingSep)
  252. if err := json.NewEncoder(&buf).Encode(val); err != nil {
  253. log.Println(err.Error())
  254. return
  255. }
  256. for _, item := range fields {
  257. buf.WriteByte(plainEncodingSep)
  258. buf.WriteString(item)
  259. }
  260. buf.WriteByte('\n')
  261. if writer == nil {
  262. log.Println(buf.String())
  263. return
  264. }
  265. if _, err := fmt.Fprint(writer, buf.String()); err != nil {
  266. log.Println(err.Error())
  267. }
  268. }
  269. }
  270. func writePlainText(writer io.Writer, level, msg string, fields ...string) {
  271. var buf strings.Builder
  272. buf.WriteString(getTimestamp())
  273. buf.WriteByte(plainEncodingSep)
  274. buf.WriteString(level)
  275. buf.WriteByte(plainEncodingSep)
  276. buf.WriteString(msg)
  277. for _, item := range fields {
  278. buf.WriteByte(plainEncodingSep)
  279. buf.WriteString(item)
  280. }
  281. buf.WriteByte('\n')
  282. if writer == nil {
  283. log.Println(buf.String())
  284. return
  285. }
  286. if _, err := fmt.Fprint(writer, buf.String()); err != nil {
  287. log.Println(err.Error())
  288. }
  289. }