tendermint/cmd/logjack/main.go

149 lines
3.4 KiB
Go

package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
. "github.com/tendermint/go-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
}