nginx_log.go 3.1 KB

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