log.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package log
  2. //go:generate errorgen
  3. import (
  4. "context"
  5. "runtime"
  6. "sync"
  7. "v2ray.com/core/common"
  8. "v2ray.com/core/common/log"
  9. )
  10. // Instance is a log.Handler that handles logs.
  11. type Instance struct {
  12. sync.RWMutex
  13. config *Config
  14. accessLogger log.Handler
  15. errorLogger log.Handler
  16. active bool
  17. }
  18. // New creates a new log.Instance based on the given config.
  19. func New(ctx context.Context, config *Config) (*Instance, error) {
  20. g := &Instance{
  21. config: config,
  22. active: false,
  23. }
  24. log.RegisterHandler(g)
  25. return g, nil
  26. }
  27. func isMobile() bool {
  28. return runtime.GOOS == "android" || (runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64"))
  29. }
  30. func createStdLogWriter() log.WriterCreator {
  31. if isMobile() {
  32. return log.CreateDefaultLogWriter()
  33. }
  34. return log.CreateStdoutLogWriter()
  35. }
  36. func (g *Instance) initAccessLogger() error {
  37. switch g.config.AccessLogType {
  38. case LogType_File:
  39. creator, err := log.CreateFileLogWriter(g.config.AccessLogPath)
  40. if err != nil {
  41. return err
  42. }
  43. g.accessLogger = log.NewLogger(creator)
  44. case LogType_Console:
  45. g.accessLogger = log.NewLogger(createStdLogWriter())
  46. default:
  47. }
  48. return nil
  49. }
  50. func (g *Instance) initErrorLogger() error {
  51. switch g.config.ErrorLogType {
  52. case LogType_File:
  53. creator, err := log.CreateFileLogWriter(g.config.ErrorLogPath)
  54. if err != nil {
  55. return err
  56. }
  57. g.errorLogger = log.NewLogger(creator)
  58. case LogType_Console:
  59. g.errorLogger = log.NewLogger(createStdLogWriter())
  60. default:
  61. }
  62. return nil
  63. }
  64. // Type implements common.HasType.
  65. func (*Instance) Type() interface{} {
  66. return (*Instance)(nil)
  67. }
  68. func (g *Instance) startInternal() error {
  69. g.Lock()
  70. defer g.Unlock()
  71. if g.active {
  72. return nil
  73. }
  74. g.active = true
  75. if err := g.initAccessLogger(); err != nil {
  76. return newError("failed to initialize access logger").Base(err).AtWarning()
  77. }
  78. if err := g.initErrorLogger(); err != nil {
  79. return newError("failed to initialize error logger").Base(err).AtWarning()
  80. }
  81. return nil
  82. }
  83. // Start implements common.Runnable.Start().
  84. func (g *Instance) Start() error {
  85. if err := g.startInternal(); err != nil {
  86. return err
  87. }
  88. newError("Logger started").AtDebug().WriteToLog()
  89. return nil
  90. }
  91. // Handle implements log.Handler.
  92. func (g *Instance) Handle(msg log.Message) {
  93. g.RLock()
  94. defer g.RUnlock()
  95. if !g.active {
  96. return
  97. }
  98. switch msg := msg.(type) {
  99. case *log.AccessMessage:
  100. if g.accessLogger != nil {
  101. g.accessLogger.Handle(msg)
  102. }
  103. case *log.GeneralMessage:
  104. if g.errorLogger != nil && msg.Severity <= g.config.ErrorLogLevel {
  105. g.errorLogger.Handle(msg)
  106. }
  107. default:
  108. // Swallow
  109. }
  110. }
  111. // Close implements common.Closable.Close().
  112. func (g *Instance) Close() error {
  113. newError("Logger closing").AtDebug().WriteToLog()
  114. g.Lock()
  115. defer g.Unlock()
  116. if !g.active {
  117. return nil
  118. }
  119. g.active = false
  120. common.Close(g.accessLogger) // nolint: errcheck
  121. g.accessLogger = nil
  122. common.Close(g.errorLogger) // nolint: errcheck
  123. g.errorLogger = nil
  124. return nil
  125. }
  126. func init() {
  127. common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
  128. return New(ctx, config.(*Config))
  129. }))
  130. }