logger.go 11 KB

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