log.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package log
  2. import (
  3. "context"
  4. "fmt"
  5. "regexp"
  6. "strings"
  7. "sync"
  8. "github.com/xtls/xray-core/common"
  9. "github.com/xtls/xray-core/common/errors"
  10. "github.com/xtls/xray-core/common/log"
  11. )
  12. // Instance is a log.Handler that handles logs.
  13. type Instance struct {
  14. sync.RWMutex
  15. config *Config
  16. accessLogger log.Handler
  17. errorLogger log.Handler
  18. active bool
  19. dns bool
  20. }
  21. // New creates a new log.Instance based on the given config.
  22. func New(ctx context.Context, config *Config) (*Instance, error) {
  23. g := &Instance{
  24. config: config,
  25. active: false,
  26. dns: config.EnableDnsLog,
  27. }
  28. log.RegisterHandler(g)
  29. // start logger now,
  30. // then other modules will be able to log during initialization
  31. if err := g.startInternal(); err != nil {
  32. return nil, err
  33. }
  34. errors.LogDebug(ctx, "Logger started")
  35. return g, nil
  36. }
  37. func (g *Instance) initAccessLogger() error {
  38. handler, err := createHandler(g.config.AccessLogType, HandlerCreatorOptions{
  39. Path: g.config.AccessLogPath,
  40. })
  41. if err != nil {
  42. return err
  43. }
  44. g.accessLogger = handler
  45. return nil
  46. }
  47. func (g *Instance) initErrorLogger() error {
  48. handler, err := createHandler(g.config.ErrorLogType, HandlerCreatorOptions{
  49. Path: g.config.ErrorLogPath,
  50. })
  51. if err != nil {
  52. return err
  53. }
  54. g.errorLogger = handler
  55. return nil
  56. }
  57. // Type implements common.HasType.
  58. func (*Instance) Type() interface{} {
  59. return (*Instance)(nil)
  60. }
  61. func (g *Instance) startInternal() error {
  62. g.Lock()
  63. defer g.Unlock()
  64. if g.active {
  65. return nil
  66. }
  67. g.active = true
  68. if err := g.initAccessLogger(); err != nil {
  69. return errors.New("failed to initialize access logger").Base(err).AtWarning()
  70. }
  71. if err := g.initErrorLogger(); err != nil {
  72. return errors.New("failed to initialize error logger").Base(err).AtWarning()
  73. }
  74. return nil
  75. }
  76. // Start implements common.Runnable.Start().
  77. func (g *Instance) Start() error {
  78. return g.startInternal()
  79. }
  80. // Handle implements log.Handler.
  81. func (g *Instance) Handle(msg log.Message) {
  82. g.RLock()
  83. defer g.RUnlock()
  84. if !g.active {
  85. return
  86. }
  87. var Msg log.Message
  88. if g.config.MaskAddress != "" {
  89. Msg = &MaskedMsgWrapper{Message: msg, config: g.config}
  90. } else {
  91. Msg = msg
  92. }
  93. switch msg := msg.(type) {
  94. case *log.AccessMessage:
  95. if g.accessLogger != nil {
  96. g.accessLogger.Handle(Msg)
  97. }
  98. case *log.DNSLog:
  99. if g.dns && g.accessLogger != nil {
  100. g.accessLogger.Handle(Msg)
  101. }
  102. case *log.GeneralMessage:
  103. if g.errorLogger != nil && msg.Severity <= g.config.ErrorLogLevel {
  104. g.errorLogger.Handle(Msg)
  105. }
  106. default:
  107. // Swallow
  108. }
  109. }
  110. // Close implements common.Closable.Close().
  111. func (g *Instance) Close() error {
  112. errors.LogDebug(context.Background(), "Logger closing")
  113. g.Lock()
  114. defer g.Unlock()
  115. if !g.active {
  116. return nil
  117. }
  118. g.active = false
  119. common.Close(g.accessLogger)
  120. g.accessLogger = nil
  121. common.Close(g.errorLogger)
  122. g.errorLogger = nil
  123. return nil
  124. }
  125. // MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.
  126. type MaskedMsgWrapper struct {
  127. log.Message
  128. config *Config
  129. }
  130. func (m *MaskedMsgWrapper) String() string {
  131. str := m.Message.String()
  132. ipv4Regex := regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`)
  133. ipv6Regex := regexp.MustCompile(`((?:[\da-fA-F]{0,4}:[\da-fA-F]{0,4}){2,7})(?:[\/\\%](\d{1,3}))?`)
  134. // Process ipv4
  135. maskedMsg := ipv4Regex.ReplaceAllStringFunc(str, func(ip string) string {
  136. parts := strings.Split(ip, ".")
  137. switch m.config.MaskAddress {
  138. case "half":
  139. return fmt.Sprintf("%s.%s.*.*", parts[0], parts[1])
  140. case "quarter":
  141. return fmt.Sprintf("%s.*.*.*", parts[0])
  142. case "full":
  143. return "[Masked IPv4]"
  144. default:
  145. return ip
  146. }
  147. })
  148. // process ipv6
  149. maskedMsg = ipv6Regex.ReplaceAllStringFunc(maskedMsg, func(ip string) string {
  150. parts := strings.Split(ip, ":")
  151. switch m.config.MaskAddress {
  152. case "half":
  153. if len(parts) >= 2 {
  154. return fmt.Sprintf("%s:%s::/32", parts[0], parts[1])
  155. }
  156. case "quarter":
  157. if len(parts) >= 1 {
  158. return fmt.Sprintf("%s::/16", parts[0])
  159. }
  160. case "full":
  161. return "Masked IPv6" // Do not use [Masked IPv6] like ipv4, or you will get "[[Masked IPv6]]" (v6 address already has [])
  162. default:
  163. return ip
  164. }
  165. return ip
  166. })
  167. return maskedMsg
  168. }
  169. func init() {
  170. common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
  171. return New(ctx, config.(*Config))
  172. }))
  173. }