You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
3.4 KiB

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "regexp"
  8. "strconv"
  9. "strings"
  10. "time"
  11. . "github.com/tendermint/tendermint/common"
  12. )
  13. const Version = "0.0.1"
  14. const sleepSeconds = 1 // Every second
  15. // Parse command-line options
  16. func parseFlags() (chopSize int64, limitSize int64, version bool, logFiles []string) {
  17. var chopSizeStr, limitSizeStr string
  18. flag.StringVar(&chopSizeStr, "chopSize", "1M", "Move file if greater than this")
  19. flag.StringVar(&limitSizeStr, "limitSize", "1G", "Only keep this much (for each specified file). Remove old files.")
  20. flag.BoolVar(&version, "version", false, "Version")
  21. flag.Parse()
  22. logFiles = flag.Args()
  23. chopSize = parseBytesize(chopSizeStr)
  24. limitSize = parseBytesize(limitSizeStr)
  25. return
  26. }
  27. func main() {
  28. // Read options
  29. chopSize, limitSize, version, logFiles := parseFlags()
  30. if version {
  31. fmt.Println(Fmt("logjack version %v", Version))
  32. return
  33. }
  34. // Print args.
  35. // fmt.Println(chopSize, limitSiz,e version, logFiles)
  36. go func() {
  37. for {
  38. for _, logFilePath := range logFiles {
  39. minIndex, maxIndex, totalSize, baseSize := readLogInfo(logFilePath)
  40. if chopSize < baseSize {
  41. moveLog(logFilePath, Fmt("%v.%03d", logFilePath, maxIndex+1))
  42. }
  43. if limitSize < totalSize {
  44. // NOTE: we only remove one file at a time.
  45. removeLog(Fmt("%v.%03d", logFilePath, minIndex))
  46. }
  47. }
  48. time.Sleep(sleepSeconds * time.Second)
  49. }
  50. }()
  51. // Trap signal
  52. TrapSignal(func() {
  53. fmt.Println("logjack shutting down")
  54. })
  55. }
  56. func moveLog(oldPath, newPath string) {
  57. err := os.Rename(oldPath, newPath)
  58. if err != nil {
  59. panic(err)
  60. }
  61. }
  62. func removeLog(path string) {
  63. err := os.Remove(path)
  64. if err != nil {
  65. panic(err)
  66. }
  67. }
  68. // This is a strange function. Refactor everything to make it less strange?
  69. func readLogInfo(logPath string) (minIndex, maxIndex int, totalSize int64, baseSize int64) {
  70. logDir := filepath.Dir(logPath)
  71. logFile := filepath.Base(logPath)
  72. minIndex, maxIndex = -1, -1
  73. dir, err := os.Open(logDir)
  74. if err != nil {
  75. panic(err)
  76. }
  77. fi, err := dir.Readdir(0)
  78. if err != nil {
  79. panic(err)
  80. }
  81. for _, fileInfo := range fi {
  82. indexedFilePattern := regexp.MustCompile("^.+\\.([0-9]{3,})$")
  83. if fileInfo.Name() == logFile {
  84. baseSize = fileInfo.Size()
  85. continue
  86. } else if strings.HasPrefix(fileInfo.Name(), logFile) {
  87. totalSize += fileInfo.Size()
  88. submatch := indexedFilePattern.FindSubmatch([]byte(fileInfo.Name()))
  89. if len(submatch) != 0 {
  90. // Matches
  91. logIndex, err := strconv.Atoi(string(submatch[1]))
  92. if err != nil {
  93. panic(err)
  94. }
  95. if maxIndex < logIndex {
  96. maxIndex = logIndex
  97. }
  98. if minIndex == -1 || logIndex < minIndex {
  99. minIndex = logIndex
  100. }
  101. }
  102. }
  103. }
  104. return minIndex, maxIndex, totalSize, baseSize
  105. }
  106. func parseBytesize(chopSize string) int64 {
  107. // Handle suffix multiplier
  108. var multiplier int64 = 1
  109. if strings.HasSuffix(chopSize, "T") {
  110. multiplier = 1042 * 1024 * 1024 * 1024
  111. chopSize = chopSize[:len(chopSize)-1]
  112. }
  113. if strings.HasSuffix(chopSize, "G") {
  114. multiplier = 1042 * 1024 * 1024
  115. chopSize = chopSize[:len(chopSize)-1]
  116. }
  117. if strings.HasSuffix(chopSize, "M") {
  118. multiplier = 1042 * 1024
  119. chopSize = chopSize[:len(chopSize)-1]
  120. }
  121. if strings.HasSuffix(chopSize, "K") {
  122. multiplier = 1042
  123. chopSize = chopSize[:len(chopSize)-1]
  124. }
  125. // Parse the numeric part
  126. chopSizeInt, err := strconv.Atoi(chopSize)
  127. if err != nil {
  128. panic(err)
  129. }
  130. return int64(chopSizeInt) * multiplier
  131. }