log.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Author: NiuJiuRu
  2. // Email: niujiuru@qq.com
  3. package baseapp
  4. import "C"
  5. import (
  6. "fmt"
  7. "io"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. "github.com/sirupsen/logrus"
  12. "gopkg.in/ini.v1"
  13. "gopkg.in/natefinch/lumberjack.v2"
  14. )
  15. // 日志级别
  16. type level uint32
  17. const (
  18. LEVEL_TRACE level = level(logrus.TraceLevel) // trace
  19. LEVEL_DEBUG = level(logrus.DebugLevel) // debug
  20. LEVEL_INFO = level(logrus.InfoLevel) // info
  21. LEVEL_WARN = level(logrus.WarnLevel) // warning
  22. LEVEL_ERROR = level(logrus.ErrorLevel) // error
  23. LEVEL_FATAL = level(logrus.FatalLevel) // fatal, 会结束程序运行, 会自动调用os.Exit(1)
  24. LEVEL_PANIC = level(logrus.PanicLevel) // panic, 会触发程序崩溃, 不处理的话, 程序退出
  25. )
  26. func (l *level) fromString(s string) {
  27. switch strings.ToLower(s) {
  28. case "trace":
  29. *l = LEVEL_TRACE
  30. case "debug":
  31. *l = LEVEL_DEBUG
  32. case "warn":
  33. *l = LEVEL_WARN
  34. case "error":
  35. *l = LEVEL_ERROR
  36. case "fatal":
  37. *l = LEVEL_FATAL
  38. case "panic":
  39. *l = LEVEL_PANIC
  40. default:
  41. *l = LEVEL_INFO
  42. }
  43. }
  44. // 输出目标
  45. type target uint32
  46. const (
  47. TARGET_NONE target = iota // 不输出日志
  48. TARGET_CONSOLE target = 1 << iota // 控制台输出
  49. TARGET_FILE // 输出到文件
  50. )
  51. func (t *target) fromString(s string) {
  52. switch strings.ToLower(s) {
  53. case "console":
  54. *t = TARGET_CONSOLE
  55. case "file":
  56. *t = TARGET_FILE
  57. case "all":
  58. *t = (TARGET_CONSOLE | TARGET_FILE)
  59. default:
  60. *t = TARGET_NONE
  61. }
  62. }
  63. // 输出格式
  64. type formatter struct{}
  65. func (f *formatter) Format(entry *logrus.Entry) ([]byte, error) {
  66. msg := ""
  67. pid := os.Getpid()
  68. if entry.Caller != nil {
  69. file := filepath.Base(entry.Caller.File)
  70. line := entry.Caller.Line
  71. msg = fmt.Sprintf("[%s, PID: %d] [%s] (%s:%d): %s\n", entry.Time.Format("2006-01-02 15:04:05"), pid, entry.Level.String(), file, line, entry.Message)
  72. } else {
  73. msg = fmt.Sprintf("[%s, PID: %d] [%s]: %s\n", entry.Time.Format("2006-01-02 15:04:05"), pid, entry.Level.String(), entry.Message)
  74. }
  75. return []byte(msg), nil
  76. }
  77. // 日志配置
  78. type config struct {
  79. // 日志输出级别
  80. Level level
  81. // 日志输出目标
  82. Target target
  83. // 每个日志文件的最大大下, 以"MB"为单位
  84. MaxSize int `ini:"MaxFileSize"`
  85. // 保留日志文件的最大天数, 以"天"为单位
  86. MaxAge int `ini:"MaxReserveDays"`
  87. // 保留的最大备份文件数量, 以"个"为单位
  88. MaxBackups int `ini:"MaxBackupFileCnts"`
  89. // 轮转文件是否压缩(gzip)减少占用的空间
  90. Compress bool `ini:"IsCompress"`
  91. }
  92. var (
  93. Logger *logrus.Logger
  94. logFileWriter *lumberjack.Logger
  95. cfgLog = &config{
  96. Level: LEVEL_TRACE,
  97. Target: TARGET_CONSOLE,
  98. MaxSize: 0,
  99. MaxAge: 0,
  100. MaxBackups: 0,
  101. Compress: true,
  102. }
  103. )
  104. func InitLogger() {
  105. cfgFile := filepath.Join(CFG_DIR, "config.ini")
  106. cfgIni, err := ini.Load(cfgFile) // 从配置文件中加载相关配置项覆盖默认值
  107. if err == nil && cfgIni.HasSection("Log") {
  108. tmpCfgLog := *cfgLog
  109. err = cfgIni.Section("Log").MapTo(&tmpCfgLog)
  110. if err != nil {
  111. fmt.Printf("Failed to load the \"[Log]\" section data from the \"%s\" file: %v\n", cfgFile, err)
  112. } else {
  113. *cfgLog = tmpCfgLog
  114. }
  115. if cfgIni.Section("Log").HasKey("Level") {
  116. cfgLog.Level.fromString(cfgIni.Section("Log").Key("Level").String())
  117. }
  118. if cfgIni.Section("Log").HasKey("Target") {
  119. cfgLog.Target.fromString(cfgIni.Section("Log").Key("Target").String())
  120. }
  121. }
  122. Logger = logrus.New()
  123. Logger.SetLevel(logrus.Level(cfgLog.Level))
  124. if cfgLog.Level == LEVEL_TRACE || cfgLog.Level == LEVEL_DEBUG {
  125. Logger.SetReportCaller(true) // 使得输出日志时能够获取到文件名和行号
  126. }
  127. Logger.SetFormatter(new(formatter))
  128. writers := make([]io.Writer, 0)
  129. if (cfgLog.Target & TARGET_CONSOLE) != 0 {
  130. writers = append(writers, os.Stdout)
  131. }
  132. if (cfgLog.Target & TARGET_FILE) != 0 {
  133. logFile := filepath.Join(LOG_DIR, EXEC_FILENAME+".log")
  134. logFileWriter = &lumberjack.Logger{Filename: logFile, MaxSize: cfgLog.MaxSize, MaxAge: cfgLog.MaxAge,
  135. MaxBackups: cfgLog.MaxBackups, Compress: cfgLog.Compress}
  136. writers = append(writers, logFileWriter)
  137. }
  138. if len(writers) > 0 {
  139. multiWriter := io.MultiWriter(writers...)
  140. Logger.SetOutput(multiWriter)
  141. } else {
  142. Logger.SetOutput(io.Discard) // 不输出
  143. }
  144. }
  145. func ExitLogger() {
  146. if Logger != nil {
  147. Logger.Out = io.Discard
  148. }
  149. if logFileWriter != nil {
  150. logFileWriter.Close() // 关闭日志文件, 只是将日志提交到内核缓存区, 如果要强制落盘, 避免日志丢失,
  151. // 需要修改开源库代码, 在关闭函数中调用"l.file.Sync()"方法并等待一会儿, 20251021 by niujiuru.
  152. logFileWriter = nil
  153. }
  154. }
  155. //export LogFromGo
  156. func LogFromGo(level *C.char, file *C.char, line C.int, message *C.char) {
  157. goLevel := C.GoString(level)
  158. goMessage := C.GoString(message)
  159. if (cfgLog.Level == LEVEL_TRACE || cfgLog.Level == LEVEL_DEBUG) && line > 0 {
  160. gofile := filepath.Base(C.GoString(file))
  161. goline := int(line)
  162. goMessage = fmt.Sprintf("(from %s:%d): %s", gofile, goline, goMessage)
  163. }
  164. switch goLevel {
  165. case "trace":
  166. Logger.Tracef("%s", goMessage)
  167. case "debug":
  168. Logger.Debugf("%s", goMessage)
  169. case "info":
  170. Logger.Infof("%s", goMessage)
  171. case "warn":
  172. Logger.Warnf("%s", goMessage)
  173. case "error":
  174. Logger.Errorf("%s", goMessage)
  175. case "fatal":
  176. Logger.Fatalf("%s", goMessage)
  177. }
  178. }