Procházet zdrojové kódy

fix: log path error caused by multi log params #301

close #301
Jacky před 1 rokem
rodič
revize
fdaa11872a
1 změnil soubory, kde provedl 277 přidání a 272 odebrání
  1. 277 272
      api/nginx/nginx_log.go

+ 277 - 272
api/nginx/nginx_log.go

@@ -1,300 +1,305 @@
 package nginx
 
 import (
-	"encoding/json"
-	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/logger"
-	"github.com/0xJacky/Nginx-UI/internal/nginx"
-	"github.com/gin-gonic/gin"
-	"github.com/gorilla/websocket"
-	"github.com/hpcloud/tail"
-	"github.com/pkg/errors"
-	"github.com/spf13/cast"
-	"io"
-	"net/http"
-	"os"
+    "encoding/json"
+    "github.com/0xJacky/Nginx-UI/api"
+    "github.com/0xJacky/Nginx-UI/internal/logger"
+    "github.com/0xJacky/Nginx-UI/internal/nginx"
+    "github.com/gin-gonic/gin"
+    "github.com/gorilla/websocket"
+    "github.com/hpcloud/tail"
+    "github.com/pkg/errors"
+    "github.com/spf13/cast"
+    "io"
+    "net/http"
+    "os"
+    "strings"
 )
 
 const (
-	PageSize = 128 * 1024
+    PageSize = 128 * 1024
 )
 
 type controlStruct struct {
-	Type         string `json:"type"`
-	ConfName     string `json:"conf_name"`
-	ServerIdx    int    `json:"server_idx"`
-	DirectiveIdx int    `json:"directive_idx"`
+    Type         string `json:"type"`
+    ConfName     string `json:"conf_name"`
+    ServerIdx    int    `json:"server_idx"`
+    DirectiveIdx int    `json:"directive_idx"`
 }
 
 type nginxLogPageResp struct {
-	Content string `json:"content"`
-	Page    int64  `json:"page"`
+    Content string `json:"content"`
+    Page    int64  `json:"page"`
 }
 
 func GetNginxLogPage(c *gin.Context) {
-	page := cast.ToInt64(c.Query("page"))
-	if page < 0 {
-		page = 0
-	}
-
-	var control controlStruct
-	if !api.BindAndValid(c, &control) {
-		return
-	}
-
-	logPath, err := getLogPath(&control)
-
-	if err != nil {
-		logger.Error(err)
-		return
-	}
-
-	logFileStat, err := os.Stat(logPath)
-
-	if err != nil {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
-		logger.Error(err)
-		return
-	}
-
-	if !logFileStat.Mode().IsRegular() {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
-		logger.Error("log file is not regular file:", logPath)
-		return
-	}
-
-	f, err := os.Open(logPath)
-
-	if err != nil {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
-		logger.Error(err)
-		return
-	}
-
-	totalPage := logFileStat.Size() / PageSize
-
-	if logFileStat.Size()%PageSize > 0 {
-		totalPage++
-	}
-
-	var buf []byte
-	var offset int64
-	if page == 0 {
-		page = totalPage
-	}
-
-	buf = make([]byte, PageSize)
-	offset = (page - 1) * PageSize
-
-	// seek
-	_, err = f.Seek(offset, io.SeekStart)
-	if err != nil && err != io.EOF {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
-		logger.Error(err)
-		return
-	}
-
-	n, err := f.Read(buf)
-
-	if err != nil && err != io.EOF {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
-		logger.Error(err)
-		return
-	}
-
-	c.JSON(http.StatusOK, nginxLogPageResp{
-		Page:    page,
-		Content: string(buf[:n]),
-	})
+    page := cast.ToInt64(c.Query("page"))
+    if page < 0 {
+        page = 0
+    }
+
+    var control controlStruct
+    if !api.BindAndValid(c, &control) {
+        return
+    }
+
+    logPath, err := getLogPath(&control)
+
+    if err != nil {
+        logger.Error(err)
+        return
+    }
+
+    logFileStat, err := os.Stat(logPath)
+
+    if err != nil {
+        c.JSON(http.StatusOK, nginxLogPageResp{})
+        logger.Error(err)
+        return
+    }
+
+    if !logFileStat.Mode().IsRegular() {
+        c.JSON(http.StatusOK, nginxLogPageResp{})
+        logger.Error("log file is not regular file:", logPath)
+        return
+    }
+
+    f, err := os.Open(logPath)
+
+    if err != nil {
+        c.JSON(http.StatusOK, nginxLogPageResp{})
+        logger.Error(err)
+        return
+    }
+
+    totalPage := logFileStat.Size() / PageSize
+
+    if logFileStat.Size()%PageSize > 0 {
+        totalPage++
+    }
+
+    var buf []byte
+    var offset int64
+    if page == 0 {
+        page = totalPage
+    }
+
+    buf = make([]byte, PageSize)
+    offset = (page - 1) * PageSize
+
+    // seek
+    _, err = f.Seek(offset, io.SeekStart)
+    if err != nil && err != io.EOF {
+        c.JSON(http.StatusOK, nginxLogPageResp{})
+        logger.Error(err)
+        return
+    }
+
+    n, err := f.Read(buf)
+
+    if err != nil && err != io.EOF {
+        c.JSON(http.StatusOK, nginxLogPageResp{})
+        logger.Error(err)
+        return
+    }
+
+    c.JSON(http.StatusOK, nginxLogPageResp{
+        Page:    page,
+        Content: string(buf[:n]),
+    })
 }
 
 func getLogPath(control *controlStruct) (logPath string, err error) {
-	switch control.Type {
-	case "site":
-		var config *nginx.NgxConfig
-		path := nginx.GetConfPath("sites-available", control.ConfName)
-		config, err = nginx.ParseNgxConfig(path)
-		if err != nil {
-			err = errors.Wrap(err, "error parsing ngx config")
-			return
-		}
-
-		if control.ServerIdx >= len(config.Servers) {
-			err = errors.New("serverIdx out of range")
-			return
-		}
-
-		if control.DirectiveIdx >= len(config.Servers[control.ServerIdx].Directives) {
-			err = errors.New("DirectiveIdx out of range")
-			return
-		}
-
-		directive := config.Servers[control.ServerIdx].Directives[control.DirectiveIdx]
-		switch directive.Directive {
-		case "access_log", "error_log":
-			// ok
-		default:
-			err = errors.New("directive.Params neither access_log nor error_log")
-			return
-		}
-
-		if directive.Params == "" {
-			err = errors.New("directive.Params is empty")
-			return
-		}
-
-		logPath = directive.Params
-
-	case "error":
-		path := nginx.GetErrorLogPath()
-
-		if path == "" {
-			err = errors.New("settings.NginxLogSettings.ErrorLogPath is empty," +
-				" refer to https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information")
-			return
-		}
-
-		logPath = path
-	default:
-		path := nginx.GetAccessLogPath()
-
-		if path == "" {
-			err = errors.New("settings.NginxLogSettings.AccessLogPath is empty," +
-				" refer to https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information")
-			return
-		}
-
-		logPath = path
-	}
-
-	return
+    switch control.Type {
+    case "site":
+        var config *nginx.NgxConfig
+        path := nginx.GetConfPath("sites-available", control.ConfName)
+        config, err = nginx.ParseNgxConfig(path)
+        if err != nil {
+            err = errors.Wrap(err, "error parsing ngx config")
+            return
+        }
+
+        if control.ServerIdx >= len(config.Servers) {
+            err = errors.New("serverIdx out of range")
+            return
+        }
+
+        if control.DirectiveIdx >= len(config.Servers[control.ServerIdx].Directives) {
+            err = errors.New("DirectiveIdx out of range")
+            return
+        }
+
+        directive := config.Servers[control.ServerIdx].Directives[control.DirectiveIdx]
+        switch directive.Directive {
+        case "access_log", "error_log":
+            // ok
+        default:
+            err = errors.New("directive.Params neither access_log nor error_log")
+            return
+        }
+
+        if directive.Params == "" {
+            err = errors.New("directive.Params is empty")
+            return
+        }
+
+        // fix: access_log /var/log/test.log main;
+        p := strings.Split(directive.Params, " ")
+        if len(p) > 0 {
+            logPath = p[0]
+        }
+        
+    case "error":
+        path := nginx.GetErrorLogPath()
+
+        if path == "" {
+            err = errors.New("settings.NginxLogSettings.ErrorLogPath is empty," +
+                " refer to https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information")
+            return
+        }
+
+        logPath = path
+    default:
+        path := nginx.GetAccessLogPath()
+
+        if path == "" {
+            err = errors.New("settings.NginxLogSettings.AccessLogPath is empty," +
+                " refer to https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information")
+            return
+        }
+
+        logPath = path
+    }
+
+    return
 }
 
 func tailNginxLog(ws *websocket.Conn, controlChan chan controlStruct, errChan chan error) {
-	defer func() {
-		if err := recover(); err != nil {
-			logger.Error(err)
-			return
-		}
-	}()
-
-	control := <-controlChan
-
-	for {
-		logPath, err := getLogPath(&control)
-
-		if err != nil {
-			errChan <- err
-			return
-		}
-
-		seek := tail.SeekInfo{
-			Offset: 0,
-			Whence: io.SeekEnd,
-		}
-
-		stat, err := os.Stat(logPath)
-		if os.IsNotExist(err) {
-			errChan <- errors.New("[error] log path not exists " + logPath)
-			return
-		}
-
-		if !stat.Mode().IsRegular() {
-			errChan <- errors.New("[error] " + logPath + " is not a regular file. " +
-				"If you are using nginx-ui in docker container, please refer to " +
-				"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information.")
-			return
-		}
-
-		// Create a tail
-		t, err := tail.TailFile(logPath, tail.Config{Follow: true,
-			ReOpen: true, Location: &seek})
-
-		if err != nil {
-			errChan <- errors.Wrap(err, "error tailing log")
-			return
-		}
-
-		for {
-			var next = false
-			select {
-			case line := <-t.Lines:
-				// Print the text of each received line
-				if line == nil {
-					continue
-				}
-
-				err = ws.WriteMessage(websocket.TextMessage, []byte(line.Text))
-
-				if err != nil && websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
-					errChan <- errors.Wrap(err, "error tailNginxLog write message")
-					return
-				}
-			case control = <-controlChan:
-				next = true
-				break
-			}
-			if next {
-				break
-			}
-		}
-	}
+    defer func() {
+        if err := recover(); err != nil {
+            logger.Error(err)
+            return
+        }
+    }()
+
+    control := <-controlChan
+
+    for {
+        logPath, err := getLogPath(&control)
+
+        if err != nil {
+            errChan <- err
+            return
+        }
+
+        seek := tail.SeekInfo{
+            Offset: 0,
+            Whence: io.SeekEnd,
+        }
+
+        stat, err := os.Stat(logPath)
+        if os.IsNotExist(err) {
+            errChan <- errors.New("[error] log path not exists " + logPath)
+            return
+        }
+
+        if !stat.Mode().IsRegular() {
+            errChan <- errors.New("[error] " + logPath + " is not a regular file. " +
+                "If you are using nginx-ui in docker container, please refer to " +
+                "https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information.")
+            return
+        }
+
+        // Create a tail
+        t, err := tail.TailFile(logPath, tail.Config{Follow: true,
+            ReOpen: true, Location: &seek})
+
+        if err != nil {
+            errChan <- errors.Wrap(err, "error tailing log")
+            return
+        }
+
+        for {
+            var next = false
+            select {
+            case line := <-t.Lines:
+                // Print the text of each received line
+                if line == nil {
+                    continue
+                }
+
+                err = ws.WriteMessage(websocket.TextMessage, []byte(line.Text))
+
+                if err != nil && websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
+                    errChan <- errors.Wrap(err, "error tailNginxLog write message")
+                    return
+                }
+            case control = <-controlChan:
+                next = true
+                break
+            }
+            if next {
+                break
+            }
+        }
+    }
 }
 
 func handleLogControl(ws *websocket.Conn, controlChan chan controlStruct, errChan chan error) {
-	defer func() {
-		if err := recover(); err != nil {
-			logger.Error(err)
-			return
-		}
-	}()
-
-	for {
-		msgType, payload, err := ws.ReadMessage()
-		if err != nil && websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
-			errChan <- errors.Wrap(err, "error handleLogControl read message")
-			return
-		}
-
-		if msgType != websocket.TextMessage {
-			errChan <- errors.New("error handleLogControl 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
-	}
+    defer func() {
+        if err := recover(); err != nil {
+            logger.Error(err)
+            return
+        }
+    }()
+
+    for {
+        msgType, payload, err := ws.ReadMessage()
+        if err != nil && websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
+            errChan <- errors.Wrap(err, "error handleLogControl read message")
+            return
+        }
+
+        if msgType != websocket.TextMessage {
+            errChan <- errors.New("error handleLogControl 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 Log(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 {
-		logger.Error(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 {
-		logger.Error(err)
-		_ = ws.WriteMessage(websocket.TextMessage, []byte(err.Error()))
-		return
-	}
+    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 {
+        logger.Error(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 {
+        logger.Error(err)
+        _ = ws.WriteMessage(websocket.TextMessage, []byte(err.Error()))
+        return
+    }
 }