logger.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package logger
  2. import (
  3. "fmt"
  4. "net/http"
  5. "os"
  6. "time"
  7. "golang-fave/engine/consts"
  8. "golang-fave/engine/domains"
  9. "golang-fave/engine/utils"
  10. )
  11. type logMsg struct {
  12. host string
  13. message string
  14. isError bool
  15. }
  16. type Logger struct {
  17. wwwDir string
  18. cdata chan logMsg
  19. cclose chan bool
  20. }
  21. func (this *Logger) console(msg *logMsg) {
  22. if consts.ParamDebug {
  23. if !msg.isError {
  24. if consts.IS_WIN {
  25. fmt.Fprintln(os.Stdout, "[ACCESS] "+msg.message)
  26. } else {
  27. fmt.Fprintln(os.Stdout, "\033[0;32m[ACCESS] "+msg.message+"\033[0m")
  28. }
  29. } else {
  30. if consts.IS_WIN {
  31. fmt.Fprintln(os.Stdout, "[ERROR] "+msg.message)
  32. } else {
  33. fmt.Fprintln(os.Stdout, "\033[0;31m[ERROR] "+msg.message+"\033[0m")
  34. }
  35. }
  36. return
  37. }
  38. if !msg.isError {
  39. fmt.Fprintln(os.Stdout, msg.message)
  40. } else {
  41. fmt.Fprintln(os.Stderr, msg.message)
  42. }
  43. }
  44. func (this *Logger) write(msg *logMsg) {
  45. // Ignore file if debug
  46. if consts.ParamDebug {
  47. this.console(msg)
  48. return
  49. }
  50. // Ignore file if host not set
  51. if msg.host == "" {
  52. this.console(msg)
  53. return
  54. }
  55. // Ignore file if www dir is not exists
  56. if !utils.IsDirExists(this.wwwDir) {
  57. this.console(msg)
  58. return
  59. }
  60. // Extract host
  61. host, _ := utils.ExtractHostPort(msg.host, false)
  62. // --- TODO: optimize this later
  63. curr_host := host
  64. doms := domains.New(this.wwwDir)
  65. if mhost := doms.GetHost(host); mhost != "" {
  66. curr_host = mhost
  67. }
  68. // ---
  69. logs_dir := this.wwwDir + string(os.PathSeparator) + curr_host + string(os.PathSeparator) + "logs"
  70. // Try use localhost folder for logs
  71. if !utils.IsDirExists(logs_dir) {
  72. logs_dir = this.wwwDir + string(os.PathSeparator) + "localhost" + string(os.PathSeparator) + "logs"
  73. }
  74. // Ignore file if logs dir is not exists
  75. if !utils.IsDirExists(logs_dir) {
  76. this.console(msg)
  77. return
  78. }
  79. // Detect which log file
  80. log_file := logs_dir + string(os.PathSeparator) + "access.log"
  81. if msg.isError {
  82. log_file = logs_dir + string(os.PathSeparator) + "error.log"
  83. }
  84. // Try write to file
  85. f, err := os.OpenFile(log_file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  86. if err == nil {
  87. defer f.Close()
  88. fmt.Fprintln(f, msg.message)
  89. return
  90. }
  91. // By default
  92. this.console(msg)
  93. }
  94. func New() *Logger {
  95. // Logs channel
  96. cdata := make(chan logMsg)
  97. // Close channel
  98. cclose := make(chan bool)
  99. // Init logger pointer
  100. lg := Logger{cdata: cdata, cclose: cclose}
  101. // Write log string in background
  102. go func() {
  103. for {
  104. select {
  105. case msg := <-cdata:
  106. lg.write(&msg)
  107. case <-cclose:
  108. cclose <- true
  109. return
  110. }
  111. }
  112. }()
  113. return &lg
  114. }
  115. func (this *Logger) Log(msg string, r *http.Request, isError bool, vars ...interface{}) {
  116. var host string = ""
  117. if r != nil {
  118. host = r.Host
  119. }
  120. if len(vars) > 0 {
  121. msg = fmt.Sprintf(msg, vars...)
  122. }
  123. select {
  124. case <-r.Context().Done():
  125. return
  126. case this.cdata <- logMsg{host, msg, isError}:
  127. return
  128. case <-time.After(1 * time.Second):
  129. fmt.Printf("Logger, can't send msg (overflow): %s, %s, %v\n", host, msg, isError)
  130. return
  131. }
  132. }
  133. func (this *Logger) SetWwwDir(dir string) {
  134. this.wwwDir = dir
  135. }
  136. func (this *Logger) Handler(h http.Handler) http.Handler {
  137. return handler{
  138. h: h,
  139. w: os.Stdout,
  140. c: this.cdata,
  141. }
  142. }
  143. func (this *Logger) Close() {
  144. this.cclose <- true
  145. <-this.cclose
  146. }