logger.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. package logger
  2. import (
  3. "database/sql/driver"
  4. "fmt"
  5. "github.com/sirupsen/logrus"
  6. "github.com/spf13/viper"
  7. "gopkg.in/gemnasium/logrus-graylog-hook.v2"
  8. "os"
  9. "reflect"
  10. "regexp"
  11. "runtime"
  12. "strings"
  13. "time"
  14. "unicode"
  15. )
  16. var MaxInt64 = ^int64(0)
  17. type Logger struct {
  18. logrus.Entry
  19. Level logrus.Level
  20. }
  21. func New() *Logger {
  22. timeFormat := "2006/01/02 15:04:05.000 -0700"
  23. if tmFormat, ok := viper.Get("logger.time_format").(string); ok && len(tmFormat) > 0 {
  24. timeFormat = strings.TrimSpace(tmFormat)
  25. }
  26. level := logrus.InfoLevel
  27. if lvStr, ok := viper.Get("logger.level").(string); ok {
  28. lvStr = strings.TrimSpace(strings.ToLower(lvStr))
  29. if lvStr == "warn" {
  30. level = logrus.WarnLevel
  31. } else if lvStr == "debug" {
  32. level = logrus.DebugLevel
  33. } else if lvStr == "error" {
  34. level = logrus.ErrorLevel
  35. } else if lvStr == "fatal" {
  36. level = logrus.FatalLevel
  37. } else if lvStr == "panic" {
  38. level = logrus.PanicLevel
  39. }
  40. }
  41. log := &logrus.Logger{
  42. Out: os.Stderr,
  43. Formatter: &logrus.TextFormatter{TimestampFormat: timeFormat},
  44. Hooks: make(logrus.LevelHooks),
  45. Level: level,
  46. }
  47. if grayAddr, ok := viper.Get("logger.graylog.addr").(string); ok && len(grayAddr) > 0 {
  48. grayHook := graylog.NewGraylogHook(grayAddr, nil)
  49. log.AddHook(grayHook)
  50. }
  51. entry := logrus.NewEntry(log)
  52. extra := viper.GetStringMap("logger.extra")
  53. if nil != extra && len(extra) > 0 {
  54. entry = entry.WithFields(extra)
  55. }
  56. return &Logger{Entry: *entry, Level: level}
  57. }
  58. func (logger *Logger) Print(args ...interface{}) {
  59. if args == nil || len(args) == 0 {
  60. return
  61. }
  62. if tp, ok := args[0].(string); ok {
  63. tp = strings.ToLower(strings.TrimSpace(tp))
  64. if "sql" == tp && len(args) == 6 {
  65. logger.printSql(args...)
  66. } else {
  67. logger.WithCaller(2).Entry.Print(args...)
  68. }
  69. } else {
  70. logger.WithCaller(2).Entry.Print(args...)
  71. }
  72. }
  73. func (logger *Logger) WithField(key string, value interface{}) *Logger {
  74. return &Logger{Entry: *logger.Entry.WithField(key, value)}
  75. }
  76. func (logger *Logger) WithFields(fields map[string]interface{}) *Logger {
  77. return &Logger{Entry: *logger.Entry.WithFields(fields)}
  78. }
  79. func (logger *Logger) WithError(err error) *Logger {
  80. return &Logger{Entry: *logger.Entry.WithError(err)}
  81. }
  82. func (logger *Logger) WithCaller(skip int) *Logger {
  83. if _, ok := logger.Data["codeline"]; ok {
  84. return logger
  85. }
  86. for i := 0; i < 100; i++ {
  87. if _, file, line, ok := runtime.Caller(i); ok {
  88. if strings.Contains(file, "git.haoqitour.com") &&
  89. !strings.Contains(file, "git.haoqitour.com/haoqi/go-common/utils/logger") {
  90. return logger.
  91. WithField("codeline", fmt.Sprintf("%s:%d", file, line))
  92. //WithField("func", runtime.FuncForPC(pc).Name())
  93. }
  94. }
  95. }
  96. if _, file, line, ok := runtime.Caller(skip); ok {
  97. return logger.
  98. WithField("codeline", fmt.Sprintf("%s:%d", file, line))
  99. //WithField("func", runtime.FuncForPC(pc).Name())
  100. }
  101. return logger
  102. }
  103. func (logger *Logger) Debugf(format string, args ...interface{}) {
  104. logger.WithCaller(2).Entry.Debugf(format, args...)
  105. }
  106. func (logger *Logger) Infof(format string, args ...interface{}) {
  107. logger.WithCaller(2).Entry.Infof(format, args...)
  108. }
  109. func (logger *Logger) Printf(format string, args ...interface{}) {
  110. logger.WithCaller(2).Entry.Printf(format, args...)
  111. }
  112. func (logger *Logger) Warnf(format string, args ...interface{}) {
  113. logger.WithCaller(2).Entry.Warnf(format, args...)
  114. }
  115. func (logger *Logger) Warningf(format string, args ...interface{}) {
  116. logger.WithCaller(2).Entry.Warningf(format, args...)
  117. }
  118. func (logger *Logger) Errorf(format string, args ...interface{}) {
  119. logger.WithCaller(2).Entry.Errorf(format, args...)
  120. }
  121. func (logger *Logger) Fatalf(format string, args ...interface{}) {
  122. logger.WithCaller(2).Entry.Fatalf(format, args...)
  123. }
  124. func (logger *Logger) Panicf(format string, args ...interface{}) {
  125. logger.WithCaller(2).Entry.Panicf(format, args...)
  126. }
  127. func (logger *Logger) Debug(args ...interface{}) {
  128. logger.WithCaller(2).Entry.Debug(args...)
  129. }
  130. func (logger *Logger) Info(args ...interface{}) {
  131. logger.WithCaller(2).Entry.Info(args...)
  132. }
  133. func (logger *Logger) Warn(args ...interface{}) {
  134. logger.WithCaller(2).Entry.Warn(args...)
  135. }
  136. func (logger *Logger) Warning(args ...interface{}) {
  137. logger.WithCaller(2).Entry.Warning(args...)
  138. }
  139. func (logger *Logger) Error(args ...interface{}) {
  140. logger.WithCaller(2).Entry.Error(args...)
  141. }
  142. func (logger *Logger) Fatal(args ...interface{}) {
  143. logger.WithCaller(2).Entry.Fatal(args...)
  144. }
  145. func (logger *Logger) Panic(args ...interface{}) {
  146. logger.WithCaller(2).Entry.Panic(args...)
  147. }
  148. func (logger *Logger) Debugln(args ...interface{}) {
  149. logger.WithCaller(2).Entry.Debugln(args...)
  150. }
  151. func (logger *Logger) Infoln(args ...interface{}) {
  152. logger.WithCaller(2).Entry.Infoln(args...)
  153. }
  154. func (logger *Logger) Println(args ...interface{}) {
  155. logger.WithCaller(2).Entry.Println(args...)
  156. }
  157. func (logger *Logger) Warnln(args ...interface{}) {
  158. logger.WithCaller(2).Entry.Warnln(args...)
  159. }
  160. func (logger *Logger) Warningln(args ...interface{}) {
  161. logger.WithCaller(2).Entry.Warningln(args...)
  162. }
  163. func (logger *Logger) Errorln(args ...interface{}) {
  164. logger.WithCaller(2).Entry.Errorln(args...)
  165. }
  166. func (logger *Logger) Fatalln(args ...interface{}) {
  167. logger.WithCaller(2).Entry.Fatalln(args...)
  168. }
  169. func (logger *Logger) Panicln(args ...interface{}) {
  170. logger.WithCaller(2).Entry.Panicln(args...)
  171. }
  172. var (
  173. sqlRegexp = regexp.MustCompile(`\?`)
  174. numericPlaceHolderRegexp = regexp.MustCompile(`\$\d+`)
  175. )
  176. func (logger *Logger) printSql(args ...interface{}) {
  177. length := len(args)
  178. var (
  179. codeLine, sql string
  180. params []interface{}
  181. latency time.Duration
  182. rows int64
  183. ok bool
  184. )
  185. if length > 1 {
  186. codeLine, _ = args[1].(string)
  187. }
  188. if length > 2 {
  189. latency, _ = args[2].(time.Duration)
  190. }
  191. if length > 3 {
  192. sql, ok = args[3].(string)
  193. if ok {
  194. sql = strings.TrimSpace(strings.Replace(strings.Replace(strings.Replace(sql, "\r\n", " ", -1), "\n", " ", -1), "\t", " ", -1))
  195. }
  196. }
  197. if length > 4 {
  198. params, _ = args[4].([]interface{})
  199. }
  200. if length > 5 {
  201. rows, _ = args[5].(int64)
  202. }
  203. lg := logger.
  204. WithField("tag", "SQL").
  205. WithField("sql", logger.getSql(sql, params))
  206. if len(codeLine) > 0 {
  207. lg = lg.WithField("codeline", strings.TrimSpace(codeLine))
  208. } else {
  209. lg = lg.WithCaller(9)
  210. }
  211. if latency > 0 {
  212. lg = lg.WithField("latency", fmt.Sprintf("%v", latency))
  213. }
  214. if rows != MaxInt64 {
  215. lg = lg.WithField("rows", fmt.Sprintf("%d rows affected or returned", rows))
  216. }
  217. lg.Info(fmt.Sprintf("%s %v", sql, params))
  218. }
  219. func (logger *Logger) getSql(originSql string, params []interface{}) string {
  220. var formattedValues []string
  221. for _, value := range params {
  222. indirectValue := reflect.Indirect(reflect.ValueOf(value))
  223. if indirectValue.IsValid() {
  224. value = indirectValue.Interface()
  225. if t, ok := value.(time.Time); ok {
  226. formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format("2006-01-02 15:04:05")))
  227. } else if b, ok := value.([]byte); ok {
  228. if str := string(b); logger.isPrintable(str) {
  229. formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str))
  230. } else {
  231. formattedValues = append(formattedValues, "'<binary>'")
  232. }
  233. } else if r, ok := value.(driver.Valuer); ok {
  234. if value, err := r.Value(); err == nil && value != nil {
  235. formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
  236. } else {
  237. formattedValues = append(formattedValues, "NULL")
  238. }
  239. } else {
  240. formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
  241. }
  242. } else {
  243. formattedValues = append(formattedValues, "NULL")
  244. }
  245. }
  246. var sql string
  247. // differentiate between $n placeholders or else treat like ?
  248. if numericPlaceHolderRegexp.MatchString(originSql) {
  249. for index, value := range formattedValues {
  250. placeholder := fmt.Sprintf(`\$%d([^\d]|$)`, index+1)
  251. sql = regexp.MustCompile(placeholder).ReplaceAllString(originSql, value+"$1")
  252. }
  253. } else {
  254. formattedValuesLength := len(formattedValues)
  255. for index, value := range sqlRegexp.Split(originSql, -1) {
  256. sql += value
  257. if index < formattedValuesLength {
  258. sql += formattedValues[index]
  259. }
  260. }
  261. }
  262. return sql
  263. }
  264. func (logger *Logger) isPrintable(s string) bool {
  265. for _, r := range s {
  266. if !unicode.IsPrint(r) {
  267. return false
  268. }
  269. }
  270. return true
  271. }