package main import ( "flag" "fmt" "os" "path/filepath" "regexp" "strconv" "strings" "time" . "github.com/tendermint/tendermint/common" ) const Version = "0.0.1" const sleepSeconds = 1 // Every second // Parse command-line options func parseFlags() (chopSize int64, limitSize int64, version bool, logFiles []string) { var chopSizeStr, limitSizeStr string flag.StringVar(&chopSizeStr, "chopSize", "1M", "Move file if greater than this") flag.StringVar(&limitSizeStr, "limitSize", "1G", "Only keep this much (for each specified file). Remove old files.") flag.BoolVar(&version, "version", false, "Version") flag.Parse() logFiles = flag.Args() chopSize = parseBytesize(chopSizeStr) limitSize = parseBytesize(limitSizeStr) return } func main() { // Read options chopSize, limitSize, version, logFiles := parseFlags() if version { fmt.Println(Fmt("logjack version %v", Version)) return } // Print args. // fmt.Println(chopSize, limitSiz,e version, logFiles) go func() { for { for _, logFilePath := range logFiles { minIndex, maxIndex, totalSize, baseSize := readLogInfo(logFilePath) if chopSize < baseSize { moveLog(logFilePath, Fmt("%v.%03d", logFilePath, maxIndex+1)) } if limitSize < totalSize { // NOTE: we only remove one file at a time. removeLog(Fmt("%v.%03d", logFilePath, minIndex)) } } time.Sleep(sleepSeconds * time.Second) } }() // Trap signal TrapSignal(func() { fmt.Println("logjack shutting down") }) } func moveLog(oldPath, newPath string) { err := os.Rename(oldPath, newPath) if err != nil { panic(err) } } func removeLog(path string) { err := os.Remove(path) if err != nil { panic(err) } } // This is a strange function. Refactor everything to make it less strange? func readLogInfo(logPath string) (minIndex, maxIndex int, totalSize int64, baseSize int64) { logDir := filepath.Dir(logPath) logFile := filepath.Base(logPath) minIndex, maxIndex = -1, -1 dir, err := os.Open(logDir) if err != nil { panic(err) } fi, err := dir.Readdir(0) if err != nil { panic(err) } for _, fileInfo := range fi { indexedFilePattern := regexp.MustCompile("^.+\\.([0-9]{3,})$") if fileInfo.Name() == logFile { baseSize = fileInfo.Size() continue } else if strings.HasPrefix(fileInfo.Name(), logFile) { totalSize += fileInfo.Size() submatch := indexedFilePattern.FindSubmatch([]byte(fileInfo.Name())) if len(submatch) != 0 { // Matches logIndex, err := strconv.Atoi(string(submatch[1])) if err != nil { panic(err) } if maxIndex < logIndex { maxIndex = logIndex } if minIndex == -1 || logIndex < minIndex { minIndex = logIndex } } } } return minIndex, maxIndex, totalSize, baseSize } func parseBytesize(chopSize string) int64 { // Handle suffix multiplier var multiplier int64 = 1 if strings.HasSuffix(chopSize, "T") { multiplier = 1042 * 1024 * 1024 * 1024 chopSize = chopSize[:len(chopSize)-1] } if strings.HasSuffix(chopSize, "G") { multiplier = 1042 * 1024 * 1024 chopSize = chopSize[:len(chopSize)-1] } if strings.HasSuffix(chopSize, "M") { multiplier = 1042 * 1024 chopSize = chopSize[:len(chopSize)-1] } if strings.HasSuffix(chopSize, "K") { multiplier = 1042 chopSize = chopSize[:len(chopSize)-1] } // Parse the numeric part chopSizeInt, err := strconv.Atoi(chopSize) if err != nil { panic(err) } return int64(chopSizeInt) * multiplier }