nginx_log.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package nginx_log
  2. import (
  3. "io"
  4. "net/http"
  5. "os"
  6. "strings"
  7. "github.com/0xJacky/Nginx-UI/internal/nginx_log"
  8. "github.com/gin-gonic/gin"
  9. "github.com/pkg/errors"
  10. "github.com/spf13/cast"
  11. "github.com/uozi-tech/cosy"
  12. "github.com/uozi-tech/cosy/logger"
  13. )
  14. const (
  15. // PageSize defines the size of log chunks returned by the API
  16. PageSize = 128 * 1024
  17. )
  18. // controlStruct represents the request parameters for getting log content
  19. type controlStruct struct {
  20. Type string `json:"type"` // Type of log: "access" or "error"
  21. LogPath string `json:"log_path"` // Path to the log file
  22. }
  23. // nginxLogPageResp represents the response format for log content
  24. type nginxLogPageResp struct {
  25. Content string `json:"content"` // Log content
  26. Page int64 `json:"page"` // Current page number
  27. Error string `json:"error,omitempty"` // Error message if any
  28. }
  29. // GetNginxLogPage handles retrieving a page of log content from a log file
  30. func GetNginxLogPage(c *gin.Context) {
  31. page := cast.ToInt64(c.Query("page"))
  32. if page < 0 {
  33. page = 0
  34. }
  35. var control controlStruct
  36. if !cosy.BindAndValid(c, &control) {
  37. return
  38. }
  39. logPath, err := getLogPath(&control)
  40. if err != nil {
  41. c.JSON(http.StatusInternalServerError, nginxLogPageResp{
  42. Error: err.Error(),
  43. })
  44. logger.Error(err)
  45. return
  46. }
  47. logFileStat, err := os.Stat(logPath)
  48. if err != nil {
  49. c.JSON(http.StatusInternalServerError, nginxLogPageResp{
  50. Error: err.Error(),
  51. })
  52. logger.Error(err)
  53. return
  54. }
  55. if !logFileStat.Mode().IsRegular() {
  56. c.JSON(http.StatusInternalServerError, nginxLogPageResp{
  57. Error: "log file is not regular file",
  58. })
  59. logger.Errorf("log file is not regular file: %s", logPath)
  60. return
  61. }
  62. // to fix: seek invalid argument #674
  63. if logFileStat.Size() == 0 {
  64. c.JSON(http.StatusOK, nginxLogPageResp{
  65. Page: 1,
  66. Content: "",
  67. })
  68. return
  69. }
  70. f, err := os.Open(logPath)
  71. if err != nil {
  72. c.JSON(http.StatusInternalServerError, nginxLogPageResp{
  73. Error: err.Error(),
  74. })
  75. logger.Error(err)
  76. return
  77. }
  78. defer f.Close()
  79. totalPage := logFileStat.Size() / PageSize
  80. if logFileStat.Size()%PageSize > 0 {
  81. totalPage++
  82. }
  83. var buf []byte
  84. var offset int64
  85. if page == 0 {
  86. page = totalPage
  87. }
  88. buf = make([]byte, PageSize)
  89. offset = (page - 1) * PageSize
  90. // seek to the correct position in the file
  91. _, err = f.Seek(offset, io.SeekStart)
  92. if err != nil && err != io.EOF {
  93. c.JSON(http.StatusInternalServerError, nginxLogPageResp{
  94. Error: err.Error(),
  95. })
  96. logger.Error(err)
  97. return
  98. }
  99. n, err := f.Read(buf)
  100. if err != nil && !errors.Is(err, io.EOF) {
  101. c.JSON(http.StatusInternalServerError, nginxLogPageResp{
  102. Error: err.Error(),
  103. })
  104. logger.Error(err)
  105. return
  106. }
  107. c.JSON(http.StatusOK, nginxLogPageResp{
  108. Page: page,
  109. Content: string(buf[:n]),
  110. })
  111. }
  112. // GetLogList returns a list of Nginx log files
  113. func GetLogList(c *gin.Context) {
  114. filters := []func(*nginx_log.NginxLogCache) bool{}
  115. if c.Query("type") != "" {
  116. filters = append(filters, func(entry *nginx_log.NginxLogCache) bool {
  117. return entry.Type == c.Query("type")
  118. })
  119. }
  120. if c.Query("name") != "" {
  121. filters = append(filters, func(entry *nginx_log.NginxLogCache) bool {
  122. return strings.Contains(entry.Name, c.Query("name"))
  123. })
  124. }
  125. if c.Query("path") != "" {
  126. filters = append(filters, func(entry *nginx_log.NginxLogCache) bool {
  127. return strings.Contains(entry.Path, c.Query("path"))
  128. })
  129. }
  130. data := nginx_log.GetAllLogs(filters...)
  131. orderBy := c.DefaultQuery("sort_by", "name")
  132. sort := c.DefaultQuery("order", "desc")
  133. data = nginx_log.Sort(orderBy, sort, data)
  134. c.JSON(http.StatusOK, gin.H{
  135. "data": data,
  136. })
  137. }