123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- package nginx_log
- import (
- "io"
- "net/http"
- "os"
- "strings"
- "github.com/0xJacky/Nginx-UI/internal/nginx_log"
- "github.com/gin-gonic/gin"
- "github.com/pkg/errors"
- "github.com/spf13/cast"
- "github.com/uozi-tech/cosy"
- "github.com/uozi-tech/cosy/logger"
- )
- const (
- // PageSize defines the size of log chunks returned by the API
- PageSize = 128 * 1024
- )
- // controlStruct represents the request parameters for getting log content
- type controlStruct struct {
- Type string `json:"type"` // Type of log: "access" or "error"
- LogPath string `json:"log_path"` // Path to the log file
- }
- // nginxLogPageResp represents the response format for log content
- type nginxLogPageResp struct {
- Content string `json:"content"` // Log content
- Page int64 `json:"page"` // Current page number
- Error string `json:"error,omitempty"` // Error message if any
- }
- // GetNginxLogPage handles retrieving a page of log content from a log file
- func GetNginxLogPage(c *gin.Context) {
- page := cast.ToInt64(c.Query("page"))
- if page < 0 {
- page = 0
- }
- var control controlStruct
- if !cosy.BindAndValid(c, &control) {
- return
- }
- logPath, err := getLogPath(&control)
- if err != nil {
- c.JSON(http.StatusInternalServerError, nginxLogPageResp{
- Error: err.Error(),
- })
- logger.Error(err)
- return
- }
- logFileStat, err := os.Stat(logPath)
- if err != nil {
- c.JSON(http.StatusInternalServerError, nginxLogPageResp{
- Error: err.Error(),
- })
- logger.Error(err)
- return
- }
- if !logFileStat.Mode().IsRegular() {
- c.JSON(http.StatusInternalServerError, nginxLogPageResp{
- Error: "log file is not regular file",
- })
- logger.Errorf("log file is not regular file: %s", logPath)
- return
- }
- // to fix: seek invalid argument #674
- if logFileStat.Size() == 0 {
- c.JSON(http.StatusOK, nginxLogPageResp{
- Page: 1,
- Content: "",
- })
- return
- }
- f, err := os.Open(logPath)
- if err != nil {
- c.JSON(http.StatusInternalServerError, nginxLogPageResp{
- Error: err.Error(),
- })
- logger.Error(err)
- return
- }
- defer f.Close()
- 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 to the correct position in the file
- _, err = f.Seek(offset, io.SeekStart)
- if err != nil && err != io.EOF {
- c.JSON(http.StatusInternalServerError, nginxLogPageResp{
- Error: err.Error(),
- })
- logger.Error(err)
- return
- }
- n, err := f.Read(buf)
- if err != nil && !errors.Is(err, io.EOF) {
- c.JSON(http.StatusInternalServerError, nginxLogPageResp{
- Error: err.Error(),
- })
- logger.Error(err)
- return
- }
- c.JSON(http.StatusOK, nginxLogPageResp{
- Page: page,
- Content: string(buf[:n]),
- })
- }
- // GetLogList returns a list of Nginx log files
- func GetLogList(c *gin.Context) {
- filters := []func(*nginx_log.NginxLogCache) bool{}
- if c.Query("type") != "" {
- filters = append(filters, func(entry *nginx_log.NginxLogCache) bool {
- return entry.Type == c.Query("type")
- })
- }
- if c.Query("name") != "" {
- filters = append(filters, func(entry *nginx_log.NginxLogCache) bool {
- return strings.Contains(entry.Name, c.Query("name"))
- })
- }
- if c.Query("path") != "" {
- filters = append(filters, func(entry *nginx_log.NginxLogCache) bool {
- return strings.Contains(entry.Path, c.Query("path"))
- })
- }
- data := nginx_log.GetAllLogs(filters...)
- orderBy := c.DefaultQuery("sort_by", "name")
- sort := c.DefaultQuery("order", "desc")
- data = nginx_log.Sort(orderBy, sort, data)
- c.JSON(http.StatusOK, gin.H{
- "data": data,
- })
- }
|