nginx_log.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package api
  2. import (
  3. "encoding/json"
  4. "github.com/0xJacky/Nginx-UI/server/settings"
  5. "github.com/gin-gonic/gin"
  6. "github.com/gorilla/websocket"
  7. "github.com/hpcloud/tail"
  8. "github.com/pkg/errors"
  9. "io"
  10. "log"
  11. "net/http"
  12. )
  13. type controlStruct struct {
  14. Fetch string `json:"fetch"`
  15. Type string `json:"type"`
  16. }
  17. func tailNginxLog(ws *websocket.Conn, controlChan chan controlStruct, errChan chan error) {
  18. defer func() {
  19. if err := recover(); err != nil {
  20. log.Println("tailNginxLog recovery", err)
  21. return
  22. }
  23. }()
  24. var control controlStruct
  25. for {
  26. var seek tail.SeekInfo
  27. if control.Fetch != "all" {
  28. seek.Offset = 0
  29. seek.Whence = io.SeekEnd
  30. }
  31. logPath := settings.NginxLogSettings.AccessLogPath
  32. if control.Type == "error" {
  33. logPath = settings.NginxLogSettings.ErrorLogPath
  34. }
  35. // Create a tail
  36. t, err := tail.TailFile(logPath, tail.Config{Follow: true,
  37. ReOpen: true, Location: &seek})
  38. if err != nil {
  39. errChan <- errors.Wrap(err, "error NginxAccessLog Tail")
  40. return
  41. }
  42. for {
  43. var next = false
  44. select {
  45. case line := <-t.Lines:
  46. // Print the text of each received line
  47. err = ws.WriteMessage(websocket.TextMessage, []byte(line.Text))
  48. if err != nil {
  49. errChan <- errors.Wrap(err, "error NginxAccessLog write message")
  50. return
  51. }
  52. case control = <-controlChan:
  53. log.Println("control change")
  54. next = true
  55. break
  56. }
  57. if next {
  58. break
  59. }
  60. }
  61. }
  62. }
  63. func handleLogControl(ws *websocket.Conn, controlChan chan controlStruct, errChan chan error) {
  64. defer func() {
  65. if err := recover(); err != nil {
  66. log.Println("tailNginxLog recovery", err)
  67. return
  68. }
  69. }()
  70. for {
  71. msgType, payload, err := ws.ReadMessage()
  72. if err != nil {
  73. errChan <- errors.Wrap(err, "error NginxAccessLog read message")
  74. return
  75. }
  76. if msgType != websocket.TextMessage {
  77. errChan <- errors.New("error NginxAccessLog message type")
  78. return
  79. }
  80. var msg controlStruct
  81. err = json.Unmarshal(payload, &msg)
  82. if err != nil {
  83. errChan <- errors.Wrap(err, "Error ReadWsAndWritePty json.Unmarshal")
  84. return
  85. }
  86. controlChan <- msg
  87. }
  88. }
  89. func NginxLog(c *gin.Context) {
  90. var upGrader = websocket.Upgrader{
  91. CheckOrigin: func(r *http.Request) bool {
  92. return true
  93. },
  94. }
  95. // upgrade http to websocket
  96. ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
  97. if err != nil {
  98. log.Println("[Error] NginxAccessLog Upgrade", err)
  99. return
  100. }
  101. defer ws.Close()
  102. errChan := make(chan error, 1)
  103. controlChan := make(chan controlStruct, 1)
  104. go tailNginxLog(ws, controlChan, errChan)
  105. go handleLogControl(ws, controlChan, errChan)
  106. if err = <-errChan; err != nil {
  107. log.Println(err)
  108. return
  109. }
  110. }