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.

116 lines
3.0 KiB

  1. package main
  2. import (
  3. "context"
  4. "flag"
  5. "fmt"
  6. "io"
  7. "os"
  8. "os/signal"
  9. "strconv"
  10. "strings"
  11. "syscall"
  12. auto "github.com/tendermint/tendermint/internal/libs/autofile"
  13. )
  14. const Version = "0.0.1"
  15. const readBufferSize = 1024 // 1KB at a time
  16. // Parse command-line options
  17. func parseFlags() (headPath string, chopSize int64, limitSize int64, version bool) {
  18. var flagSet = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
  19. var chopSizeStr, limitSizeStr string
  20. flagSet.StringVar(&headPath, "head", "logjack.out", "Destination (head) file.")
  21. flagSet.StringVar(&chopSizeStr, "chop", "100M", "Move file if greater than this")
  22. flagSet.StringVar(&limitSizeStr, "limit", "10G", "Only keep this much (for each specified file). Remove old files.")
  23. flagSet.BoolVar(&version, "version", false, "Version")
  24. if err := flagSet.Parse(os.Args[1:]); err != nil {
  25. fmt.Printf("err parsing flag: %v\n", err)
  26. os.Exit(1)
  27. }
  28. chopSize = parseBytesize(chopSizeStr)
  29. limitSize = parseBytesize(limitSizeStr)
  30. return
  31. }
  32. func main() {
  33. ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM)
  34. defer cancel()
  35. defer func() { fmt.Println("logjack shutting down") }()
  36. // Read options
  37. headPath, chopSize, limitSize, version := parseFlags()
  38. if version {
  39. fmt.Printf("logjack version %v\n", Version)
  40. return
  41. }
  42. // Open Group
  43. group, err := auto.OpenGroup(headPath, auto.GroupHeadSizeLimit(chopSize), auto.GroupTotalSizeLimit(limitSize))
  44. if err != nil {
  45. fmt.Printf("logjack couldn't create output file %v\n", headPath)
  46. os.Exit(1)
  47. }
  48. if err = group.Start(ctx); err != nil {
  49. fmt.Printf("logjack couldn't start with file %v\n", headPath)
  50. os.Exit(1)
  51. }
  52. // Forever read from stdin and write to AutoFile.
  53. buf := make([]byte, readBufferSize)
  54. for {
  55. n, err := os.Stdin.Read(buf)
  56. if err != nil {
  57. if err := group.Stop(); err != nil {
  58. fmt.Fprintf(os.Stderr, "logjack stopped with error %v\n", headPath)
  59. os.Exit(1)
  60. }
  61. if err == io.EOF {
  62. os.Exit(0)
  63. } else {
  64. fmt.Println("logjack errored")
  65. os.Exit(1)
  66. }
  67. }
  68. _, err = group.Write(buf[:n])
  69. if err != nil {
  70. fmt.Fprintf(os.Stderr, "logjack failed write with error %v\n", headPath)
  71. os.Exit(1)
  72. }
  73. if err := group.FlushAndSync(); err != nil {
  74. fmt.Fprintf(os.Stderr, "logjack flushsync fail with error %v\n", headPath)
  75. os.Exit(1)
  76. }
  77. }
  78. }
  79. func parseBytesize(chopSize string) int64 {
  80. // Handle suffix multiplier
  81. var multiplier int64 = 1
  82. if strings.HasSuffix(chopSize, "T") {
  83. multiplier = 1042 * 1024 * 1024 * 1024
  84. chopSize = chopSize[:len(chopSize)-1]
  85. }
  86. if strings.HasSuffix(chopSize, "G") {
  87. multiplier = 1042 * 1024 * 1024
  88. chopSize = chopSize[:len(chopSize)-1]
  89. }
  90. if strings.HasSuffix(chopSize, "M") {
  91. multiplier = 1042 * 1024
  92. chopSize = chopSize[:len(chopSize)-1]
  93. }
  94. if strings.HasSuffix(chopSize, "K") {
  95. multiplier = 1042
  96. chopSize = chopSize[:len(chopSize)-1]
  97. }
  98. // Parse the numeric part
  99. chopSizeInt, err := strconv.Atoi(chopSize)
  100. if err != nil {
  101. panic(err)
  102. }
  103. return int64(chopSizeInt) * multiplier
  104. }