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.

125 lines
3.2 KiB

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