access.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package log
  2. import (
  3. "log"
  4. "os"
  5. "github.com/v2ray/v2ray-core/common/platform"
  6. )
  7. // AccessStatus is the status of an access request from clients.
  8. type AccessStatus string
  9. const (
  10. AccessAccepted = AccessStatus("accepted")
  11. AccessRejected = AccessStatus("rejected")
  12. )
  13. type accessLogger interface {
  14. Log(from, to string, status AccessStatus, reason string)
  15. }
  16. type noOpAccessLogger struct {
  17. }
  18. func (logger *noOpAccessLogger) Log(from, to string, status AccessStatus, reason string) {
  19. // Swallow
  20. }
  21. type accessLog struct {
  22. From string
  23. To string
  24. Status AccessStatus
  25. Reason string
  26. }
  27. type fileAccessLogger struct {
  28. queue chan *accessLog
  29. logger *log.Logger
  30. file *os.File
  31. }
  32. func (logger *fileAccessLogger) close() {
  33. logger.file.Close()
  34. }
  35. func (logger *fileAccessLogger) Log(from, to string, status AccessStatus, reason string) {
  36. select {
  37. case logger.queue <- &accessLog{
  38. From: from,
  39. To: to,
  40. Status: status,
  41. Reason: reason,
  42. }:
  43. default:
  44. // We don't expect this to happen, but don't want to block main thread as well.
  45. }
  46. }
  47. func (logger *fileAccessLogger) Run() {
  48. for entry := range logger.queue {
  49. logger.logger.Println(entry.From + " " + string(entry.Status) + " " + entry.To + " " + entry.Reason)
  50. }
  51. }
  52. func newFileAccessLogger(path string) accessLogger {
  53. file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
  54. if err != nil {
  55. log.Printf("Unable to create or open file (%s): %v%s", path, err, platform.LineSeparator())
  56. return nil
  57. }
  58. return &fileAccessLogger{
  59. queue: make(chan *accessLog, 16),
  60. logger: log.New(file, "", log.Ldate|log.Ltime),
  61. file: file,
  62. }
  63. }
  64. var accessLoggerInstance accessLogger = &noOpAccessLogger{}
  65. // InitAccessLogger initializes the access logger to write into the give file.
  66. func InitAccessLogger(file string) {
  67. logger := newFileAccessLogger(file)
  68. if logger != nil {
  69. go logger.(*fileAccessLogger).Run()
  70. accessLoggerInstance = logger
  71. }
  72. }
  73. // Access writes an access log.
  74. func Access(from, to string, status AccessStatus, reason string) {
  75. accessLoggerInstance.Log(from, to, status, reason)
  76. }