|
@@ -0,0 +1,124 @@
|
|
|
+package api
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "github.com/0xJacky/Nginx-UI/server/settings"
|
|
|
+ "github.com/gin-gonic/gin"
|
|
|
+ "github.com/gorilla/websocket"
|
|
|
+ "github.com/hpcloud/tail"
|
|
|
+ "github.com/pkg/errors"
|
|
|
+ "io"
|
|
|
+ "log"
|
|
|
+ "net/http"
|
|
|
+)
|
|
|
+
|
|
|
+type controlStruct struct {
|
|
|
+ Fetch string `json:"fetch"`
|
|
|
+}
|
|
|
+
|
|
|
+func tailNginxLog(ws *websocket.Conn, controlChan chan controlStruct, errChan chan error) {
|
|
|
+ defer func() {
|
|
|
+ if err := recover(); err != nil {
|
|
|
+ log.Println("tailNginxLog recovery", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
+ var control controlStruct
|
|
|
+
|
|
|
+ for {
|
|
|
+ var seek tail.SeekInfo
|
|
|
+ if control.Fetch != "all" {
|
|
|
+ seek.Offset = 0
|
|
|
+ seek.Whence = io.SeekEnd
|
|
|
+ }
|
|
|
+
|
|
|
+ // Create a tail
|
|
|
+ t, err := tail.TailFile(
|
|
|
+ settings.NginxLogSettings.AccessLogPath, tail.Config{Follow: true,
|
|
|
+ ReOpen: true, Location: &seek})
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ errChan <- errors.Wrap(err, "error NginxAccessLog Tail")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for {
|
|
|
+ var next = false
|
|
|
+ select {
|
|
|
+ case line := <-t.Lines:
|
|
|
+ // Print the text of each received line
|
|
|
+ err = ws.WriteMessage(websocket.TextMessage, []byte(line.Text))
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ errChan <- errors.Wrap(err, "error NginxAccessLog write message")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ case control = <-controlChan:
|
|
|
+ log.Println("control change")
|
|
|
+ next = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ if next {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func handleLogControl(ws *websocket.Conn, controlChan chan controlStruct, errChan chan error) {
|
|
|
+ defer func() {
|
|
|
+ if err := recover(); err != nil {
|
|
|
+ log.Println("tailNginxLog recovery", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
+ for {
|
|
|
+ msgType, payload, err := ws.ReadMessage()
|
|
|
+ if err != nil {
|
|
|
+ errChan <- errors.Wrap(err, "error NginxAccessLog read message")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if msgType != websocket.TextMessage {
|
|
|
+ errChan <- errors.New("error NginxAccessLog message type")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ var msg controlStruct
|
|
|
+ err = json.Unmarshal(payload, &msg)
|
|
|
+ if err != nil {
|
|
|
+ errChan <- errors.Wrap(err, "Error ReadWsAndWritePty json.Unmarshal")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ controlChan <- msg
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func NginxLog(c *gin.Context) {
|
|
|
+ var upGrader = websocket.Upgrader{
|
|
|
+ CheckOrigin: func(r *http.Request) bool {
|
|
|
+ return true
|
|
|
+ },
|
|
|
+ }
|
|
|
+ // upgrade http to websocket
|
|
|
+ ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
|
|
+ if err != nil {
|
|
|
+ log.Println("[Error] NginxAccessLog Upgrade", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ defer ws.Close()
|
|
|
+
|
|
|
+ errChan := make(chan error, 1)
|
|
|
+ controlChan := make(chan controlStruct, 1)
|
|
|
+
|
|
|
+ go tailNginxLog(ws, controlChan, errChan)
|
|
|
+ go handleLogControl(ws, controlChan, errChan)
|
|
|
+
|
|
|
+ if err = <-errChan; err != nil {
|
|
|
+ log.Println(err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|