logger.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. package logger
  2. import (
  3. "database/sql/driver"
  4. "fmt"
  5. "github.com/lestrrat-go/file-rotatelogs"
  6. "github.com/rifflock/lfshook"
  7. "github.com/sirupsen/logrus"
  8. "github.com/spf13/viper"
  9. "gopkg.in/gemnasium/logrus-graylog-hook.v2"
  10. "os"
  11. "reflect"
  12. "regexp"
  13. "runtime"
  14. "strings"
  15. "time"
  16. "unicode"
  17. )
  18. var MaxInt64 = ^int64(0)
  19. type Logger struct {
  20. logrus.Entry
  21. Level logrus.Level
  22. }
  23. func New() *Logger {
  24. timeFormat := "2006/01/02 15:04:05.000 -0700"
  25. if tmFormat, ok := viper.Get("logger.time_format").(string); ok && len(tmFormat) > 0 {
  26. timeFormat = strings.TrimSpace(tmFormat)
  27. }
  28. level := logrus.InfoLevel
  29. if lvStr, ok := viper.Get("logger.level").(string); ok {
  30. lvStr = strings.TrimSpace(strings.ToLower(lvStr))
  31. if lvStr == "warn" {
  32. level = logrus.WarnLevel
  33. } else if lvStr == "debug" {
  34. level = logrus.DebugLevel
  35. } else if lvStr == "error" {
  36. level = logrus.ErrorLevel
  37. } else if lvStr == "fatal" {
  38. level = logrus.FatalLevel
  39. } else if lvStr == "panic" {
  40. level = logrus.PanicLevel
  41. } else if lvStr == "trace" {
  42. level = logrus.TraceLevel
  43. }
  44. }
  45. var formatter logrus.Formatter
  46. if viper.GetString("logger.formatter") == "json" {
  47. formatter = &logrus.JSONFormatter{TimestampFormat: timeFormat}
  48. } else {
  49. formatter = &logrus.TextFormatter{TimestampFormat: timeFormat}
  50. }
  51. log := &logrus.Logger{
  52. Out: os.Stderr,
  53. Formatter: formatter,
  54. Hooks: make(logrus.LevelHooks),
  55. Level: level,
  56. }
  57. if grayAddr, ok := viper.Get("logger.graylog.addr").(string); ok && len(grayAddr) > 0 {
  58. grayHook := graylog.NewGraylogHook(grayAddr, nil)
  59. log.AddHook(grayHook)
  60. }
  61. lfMap := viper.GetStringMapString("logger.local.file.path")
  62. if nil != lfMap && len(lfMap) > 0 {
  63. viper.SetDefault("logger.local.file.rotation.hours", 24)
  64. viper.SetDefault("logger.local.file.rotation.count", 7)
  65. viper.SetDefault("logger.local.file.rotation.postfix", ".%Y%m%d%H%M")
  66. rotationHours := viper.GetInt("logger.local.file.rotation.hours")
  67. rotationCount := viper.GetInt("logger.local.file.rotation.count")
  68. rotationPostfix := viper.GetString("logger.local.file.rotation.postfix")
  69. writerMap := lfshook.WriterMap{}
  70. if v, ok := lfMap["panic"]; ok {
  71. writerMap[logrus.PanicLevel], _ = rotatelogs.New(
  72. v+rotationPostfix,
  73. rotatelogs.WithLinkName(v), // 为最新的日志建立软连接,以方便随着找到当前日志文件
  74. rotatelogs.WithRotationCount(uint(rotationCount)), // 设置文件清理前最多保存的个数,也可通过WithMaxAge设置最长保存时间,二者取其一
  75. rotatelogs.WithRotationTime(time.Duration(rotationHours)*time.Hour), // 设置日志分割的时间,例如一天一次
  76. )
  77. }
  78. if v, ok := lfMap["fatal"]; ok {
  79. writerMap[logrus.FatalLevel], _ = rotatelogs.New(
  80. v+rotationPostfix,
  81. rotatelogs.WithLinkName(v),
  82. rotatelogs.WithRotationCount(uint(rotationCount)),
  83. rotatelogs.WithRotationTime(time.Duration(rotationHours)*time.Hour),
  84. )
  85. }
  86. if v, ok := lfMap["error"]; ok {
  87. writerMap[logrus.ErrorLevel], _ = rotatelogs.New(
  88. v+rotationPostfix,
  89. rotatelogs.WithLinkName(v),
  90. rotatelogs.WithRotationCount(uint(rotationCount)),
  91. rotatelogs.WithRotationTime(time.Duration(rotationHours)*time.Hour),
  92. )
  93. }
  94. if v, ok := lfMap["warn"]; ok {
  95. writerMap[logrus.WarnLevel], _ = rotatelogs.New(
  96. v+rotationPostfix,
  97. rotatelogs.WithLinkName(v),
  98. rotatelogs.WithRotationCount(uint(rotationCount)),
  99. rotatelogs.WithRotationTime(time.Duration(rotationHours)*time.Hour),
  100. )
  101. }
  102. if v, ok := lfMap["info"]; ok {
  103. writerMap[logrus.InfoLevel], _ = rotatelogs.New(
  104. v+rotationPostfix,
  105. rotatelogs.WithLinkName(v),
  106. rotatelogs.WithRotationCount(uint(rotationCount)),
  107. rotatelogs.WithRotationTime(time.Duration(rotationHours)*time.Hour),
  108. )
  109. }
  110. if v, ok := lfMap["debug"]; ok {
  111. writerMap[logrus.DebugLevel], _ = rotatelogs.New(
  112. v+rotationPostfix,
  113. rotatelogs.WithLinkName(v),
  114. rotatelogs.WithRotationCount(uint(rotationCount)),
  115. rotatelogs.WithRotationTime(time.Duration(rotationHours)*time.Hour),
  116. )
  117. }
  118. if v, ok := lfMap["trace"]; ok {
  119. writerMap[logrus.TraceLevel], _ = rotatelogs.New(
  120. v+rotationPostfix,
  121. rotatelogs.WithLinkName(v),
  122. rotatelogs.WithRotationCount(uint(rotationCount)),
  123. rotatelogs.WithRotationTime(time.Duration(rotationHours)*time.Hour),
  124. )
  125. }
  126. var lfFormatter logrus.Formatter
  127. if viper.GetString("logger.local.file.formatter") == "json" {
  128. lfFormatter = &logrus.JSONFormatter{TimestampFormat: timeFormat}
  129. } else {
  130. lfFormatter = &logrus.TextFormatter{TimestampFormat: timeFormat}
  131. }
  132. lfHook := lfshook.NewHook(writerMap, lfFormatter)
  133. log.AddHook(lfHook)
  134. }
  135. entry := logrus.NewEntry(log)
  136. extra := viper.GetStringMap("logger.extra")
  137. if nil != extra && len(extra) > 0 {
  138. entry = entry.WithFields(extra)
  139. }
  140. return &Logger{Entry: *entry, Level: level}
  141. }
  142. func (logger *Logger) Print(args ...interface{}) {
  143. if args == nil || len(args) == 0 {
  144. return
  145. }
  146. if tp, ok := args[0].(string); ok {
  147. tp = strings.ToLower(strings.TrimSpace(tp))
  148. if "sql" == tp && len(args) == 6 {
  149. logger.printSql(args...)
  150. } else {
  151. logger.WithCaller(2).Entry.Print(args...)
  152. }
  153. } else {
  154. logger.WithCaller(2).Entry.Print(args...)
  155. }
  156. }
  157. func (logger *Logger) WithField(key string, value interface{}) *Logger {
  158. return &Logger{Entry: *logger.Entry.WithField(key, value)}
  159. }
  160. func (logger *Logger) WithFields(fields map[string]interface{}) *Logger {
  161. return &Logger{Entry: *logger.Entry.WithFields(fields)}
  162. }
  163. func (logger *Logger) WithError(err error) *Logger {
  164. return &Logger{Entry: *logger.Entry.WithError(err)}
  165. }
  166. func (logger *Logger) WithCaller(skip int) *Logger {
  167. if _, ok := logger.Data["codeline"]; ok {
  168. return logger
  169. }
  170. for i := 0; i < 100; i++ {
  171. if _, file, line, ok := runtime.Caller(i); ok {
  172. if strings.Contains(file, "git.aionnect.com") &&
  173. !strings.Contains(file, "git.aionnect.com/aionnect/go-common/utils/logger") {
  174. return logger.
  175. WithField("codeline", fmt.Sprintf("%s:%d", file, line))
  176. //WithField("func", runtime.FuncForPC(pc).Name())
  177. }
  178. }
  179. }
  180. if _, file, line, ok := runtime.Caller(skip); ok {
  181. return logger.
  182. WithField("codeline", fmt.Sprintf("%s:%d", file, line))
  183. //WithField("func", runtime.FuncForPC(pc).Name())
  184. }
  185. return logger
  186. }
  187. func (logger *Logger) Debugf(format string, args ...interface{}) {
  188. logger.WithCaller(2).Entry.Debugf(format, args...)
  189. }
  190. func (logger *Logger) Infof(format string, args ...interface{}) {
  191. logger.WithCaller(2).Entry.Infof(format, args...)
  192. }
  193. func (logger *Logger) Printf(format string, args ...interface{}) {
  194. logger.WithCaller(2).Entry.Printf(format, args...)
  195. }
  196. func (logger *Logger) Warnf(format string, args ...interface{}) {
  197. logger.WithCaller(2).Entry.Warnf(format, args...)
  198. }
  199. func (logger *Logger) Warningf(format string, args ...interface{}) {
  200. logger.WithCaller(2).Entry.Warningf(format, args...)
  201. }
  202. func (logger *Logger) Errorf(format string, args ...interface{}) {
  203. logger.WithCaller(2).Entry.Errorf(format, args...)
  204. }
  205. func (logger *Logger) Fatalf(format string, args ...interface{}) {
  206. logger.WithCaller(2).Entry.Fatalf(format, args...)
  207. }
  208. func (logger *Logger) Panicf(format string, args ...interface{}) {
  209. logger.WithCaller(2).Entry.Panicf(format, args...)
  210. }
  211. func (logger *Logger) Debug(args ...interface{}) {
  212. logger.WithCaller(2).Entry.Debug(args...)
  213. }
  214. func (logger *Logger) Info(args ...interface{}) {
  215. logger.WithCaller(2).Entry.Info(args...)
  216. }
  217. func (logger *Logger) Warn(args ...interface{}) {
  218. logger.WithCaller(2).Entry.Warn(args...)
  219. }
  220. func (logger *Logger) Warning(args ...interface{}) {
  221. logger.WithCaller(2).Entry.Warning(args...)
  222. }
  223. func (logger *Logger) Error(args ...interface{}) {
  224. logger.WithCaller(2).Entry.Error(args...)
  225. }
  226. func (logger *Logger) Fatal(args ...interface{}) {
  227. logger.WithCaller(2).Entry.Fatal(args...)
  228. }
  229. func (logger *Logger) Panic(args ...interface{}) {
  230. logger.WithCaller(2).Entry.Panic(args...)
  231. }
  232. func (logger *Logger) Debugln(args ...interface{}) {
  233. logger.WithCaller(2).Entry.Debugln(args...)
  234. }
  235. func (logger *Logger) Infoln(args ...interface{}) {
  236. logger.WithCaller(2).Entry.Infoln(args...)
  237. }
  238. func (logger *Logger) Println(args ...interface{}) {
  239. logger.WithCaller(2).Entry.Println(args...)
  240. }
  241. func (logger *Logger) Warnln(args ...interface{}) {
  242. logger.WithCaller(2).Entry.Warnln(args...)
  243. }
  244. func (logger *Logger) Warningln(args ...interface{}) {
  245. logger.WithCaller(2).Entry.Warningln(args...)
  246. }
  247. func (logger *Logger) Errorln(args ...interface{}) {
  248. logger.WithCaller(2).Entry.Errorln(args...)
  249. }
  250. func (logger *Logger) Fatalln(args ...interface{}) {
  251. logger.WithCaller(2).Entry.Fatalln(args...)
  252. }
  253. func (logger *Logger) Panicln(args ...interface{}) {
  254. logger.WithCaller(2).Entry.Panicln(args...)
  255. }
  256. func (logger *Logger) V(v int) bool {
  257. return false
  258. }
  259. var (
  260. sqlRegexp = regexp.MustCompile(`\?`)
  261. numericPlaceHolderRegexp = regexp.MustCompile(`\$\d+`)
  262. )
  263. func (logger *Logger) printSql(args ...interface{}) {
  264. length := len(args)
  265. var (
  266. codeLine, sql string
  267. params []interface{}
  268. latency time.Duration
  269. rows int64
  270. ok bool
  271. )
  272. if length > 1 {
  273. codeLine, _ = args[1].(string)
  274. }
  275. if length > 2 {
  276. latency, _ = args[2].(time.Duration)
  277. }
  278. if length > 3 {
  279. sql, ok = args[3].(string)
  280. if ok {
  281. sql = strings.TrimSpace(strings.Replace(strings.Replace(strings.Replace(sql, "\r\n", " ", -1), "\n", " ", -1), "\t", " ", -1))
  282. }
  283. }
  284. if length > 4 {
  285. params, _ = args[4].([]interface{})
  286. }
  287. if length > 5 {
  288. rows, _ = args[5].(int64)
  289. }
  290. lg := logger.
  291. WithField("tag", "SQL").
  292. WithField("sql", logger.getSql(sql, params))
  293. if len(codeLine) > 0 {
  294. lg = lg.WithField("codeline", strings.TrimSpace(codeLine))
  295. } else {
  296. lg = lg.WithCaller(9)
  297. }
  298. if latency > 0 {
  299. lg = lg.WithField("latency", fmt.Sprintf("%v", latency))
  300. }
  301. if rows != MaxInt64 {
  302. lg = lg.WithField("rows", fmt.Sprintf("%d rows affected or returned", rows))
  303. }
  304. lg.Info(fmt.Sprintf("%s %v", sql, params))
  305. }
  306. func (logger *Logger) getSql(originSql string, params []interface{}) string {
  307. var formattedValues []string
  308. for _, value := range params {
  309. indirectValue := reflect.Indirect(reflect.ValueOf(value))
  310. if indirectValue.IsValid() {
  311. value = indirectValue.Interface()
  312. if t, ok := value.(time.Time); ok {
  313. formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format("2006-01-02 15:04:05")))
  314. } else if b, ok := value.([]byte); ok {
  315. if str := string(b); logger.isPrintable(str) {
  316. formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str))
  317. } else {
  318. formattedValues = append(formattedValues, "'<binary>'")
  319. }
  320. } else if r, ok := value.(driver.Valuer); ok {
  321. if value, err := r.Value(); err == nil && value != nil {
  322. formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
  323. } else {
  324. formattedValues = append(formattedValues, "NULL")
  325. }
  326. } else {
  327. formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
  328. }
  329. } else {
  330. formattedValues = append(formattedValues, "NULL")
  331. }
  332. }
  333. if nil == formattedValues {
  334. return ""
  335. }
  336. var sql string
  337. // differentiate between $n placeholders or else treat like ?
  338. if numericPlaceHolderRegexp.MatchString(originSql) {
  339. for index, value := range formattedValues {
  340. placeholder := fmt.Sprintf(`\$%d([^\d]|$)`, index+1)
  341. sql = regexp.MustCompile(placeholder).ReplaceAllString(originSql, value+"$1")
  342. }
  343. } else {
  344. formattedValuesLength := len(formattedValues)
  345. for index, value := range sqlRegexp.Split(originSql, -1) {
  346. sql += value
  347. if index < formattedValuesLength {
  348. sql += formattedValues[index]
  349. }
  350. }
  351. }
  352. return sql
  353. }
  354. func (logger *Logger) isPrintable(s string) bool {
  355. for _, r := range s {
  356. if !unicode.IsPrint(r) {
  357. return false
  358. }
  359. }
  360. return true
  361. }