|
@ -5,6 +5,7 @@ import ( |
|
|
"flag" |
|
|
"flag" |
|
|
"fmt" |
|
|
"fmt" |
|
|
"io" |
|
|
"io" |
|
|
|
|
|
stdlog "log" |
|
|
"os" |
|
|
"os" |
|
|
"os/signal" |
|
|
"os/signal" |
|
|
"strconv" |
|
|
"strconv" |
|
@ -19,19 +20,26 @@ const Version = "0.0.1" |
|
|
const readBufferSize = 1024 // 1KB at a time
|
|
|
const readBufferSize = 1024 // 1KB at a time
|
|
|
|
|
|
|
|
|
// Parse command-line options
|
|
|
// Parse command-line options
|
|
|
func parseFlags() (headPath string, chopSize int64, limitSize int64, version bool) { |
|
|
|
|
|
|
|
|
func parseFlags() (headPath string, chopSize int64, limitSize int64, version bool, err error) { |
|
|
var flagSet = flag.NewFlagSet(os.Args[0], flag.ExitOnError) |
|
|
var flagSet = flag.NewFlagSet(os.Args[0], flag.ExitOnError) |
|
|
var chopSizeStr, limitSizeStr string |
|
|
var chopSizeStr, limitSizeStr string |
|
|
flagSet.StringVar(&headPath, "head", "logjack.out", "Destination (head) file.") |
|
|
flagSet.StringVar(&headPath, "head", "logjack.out", "Destination (head) file.") |
|
|
flagSet.StringVar(&chopSizeStr, "chop", "100M", "Move file if greater than this") |
|
|
flagSet.StringVar(&chopSizeStr, "chop", "100M", "Move file if greater than this") |
|
|
flagSet.StringVar(&limitSizeStr, "limit", "10G", "Only keep this much (for each specified file). Remove old files.") |
|
|
flagSet.StringVar(&limitSizeStr, "limit", "10G", "Only keep this much (for each specified file). Remove old files.") |
|
|
flagSet.BoolVar(&version, "version", false, "Version") |
|
|
flagSet.BoolVar(&version, "version", false, "Version") |
|
|
if err := flagSet.Parse(os.Args[1:]); err != nil { |
|
|
|
|
|
fmt.Printf("err parsing flag: %v\n", err) |
|
|
|
|
|
os.Exit(1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err = flagSet.Parse(os.Args[1:]); err != nil { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
chopSize, err = parseByteSize(chopSizeStr) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
limitSize, err = parseByteSize(limitSizeStr) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return |
|
|
} |
|
|
} |
|
|
chopSize = parseBytesize(chopSizeStr) |
|
|
|
|
|
limitSize = parseBytesize(limitSizeStr) |
|
|
|
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -41,22 +49,23 @@ func main() { |
|
|
defer func() { fmt.Println("logjack shutting down") }() |
|
|
defer func() { fmt.Println("logjack shutting down") }() |
|
|
|
|
|
|
|
|
// Read options
|
|
|
// Read options
|
|
|
headPath, chopSize, limitSize, version := parseFlags() |
|
|
|
|
|
|
|
|
headPath, chopSize, limitSize, version, err := parseFlags() |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
stdlog.Fatalf("problem parsing arguments: %q", err.Error()) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if version { |
|
|
if version { |
|
|
fmt.Printf("logjack version %v\n", Version) |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
stdlog.Printf("logjack version %s", Version) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Open Group
|
|
|
// Open Group
|
|
|
group, err := auto.OpenGroup(ctx, log.NewNopLogger(), headPath, auto.GroupHeadSizeLimit(chopSize), auto.GroupTotalSizeLimit(limitSize)) |
|
|
group, err := auto.OpenGroup(ctx, log.NewNopLogger(), headPath, auto.GroupHeadSizeLimit(chopSize), auto.GroupTotalSizeLimit(limitSize)) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
fmt.Printf("logjack couldn't create output file %v\n", headPath) |
|
|
|
|
|
os.Exit(1) |
|
|
|
|
|
|
|
|
stdlog.Fatalf("logjack couldn't create output file %q", headPath) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if err = group.Start(ctx); err != nil { |
|
|
if err = group.Start(ctx); err != nil { |
|
|
fmt.Printf("logjack couldn't start with file %v\n", headPath) |
|
|
|
|
|
os.Exit(1) |
|
|
|
|
|
|
|
|
stdlog.Fatalf("logjack couldn't start with file %q", headPath) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Forever read from stdin and write to AutoFile.
|
|
|
// Forever read from stdin and write to AutoFile.
|
|
@ -65,25 +74,21 @@ func main() { |
|
|
n, err := os.Stdin.Read(buf) |
|
|
n, err := os.Stdin.Read(buf) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
if err == io.EOF { |
|
|
if err == io.EOF { |
|
|
os.Exit(0) |
|
|
|
|
|
} else { |
|
|
|
|
|
fmt.Println("logjack errored:", err.Error()) |
|
|
|
|
|
os.Exit(1) |
|
|
|
|
|
|
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
stdlog.Fatalln("logjack errored:", err.Error()) |
|
|
} |
|
|
} |
|
|
_, err = group.Write(buf[:n]) |
|
|
_, err = group.Write(buf[:n]) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
fmt.Fprintf(os.Stderr, "logjack failed write with error %v\n", headPath) |
|
|
|
|
|
os.Exit(1) |
|
|
|
|
|
|
|
|
stdlog.Fatalf("logjack failed write %q with error: %q", headPath, err.Error()) |
|
|
} |
|
|
} |
|
|
if err := group.FlushAndSync(); err != nil { |
|
|
if err := group.FlushAndSync(); err != nil { |
|
|
fmt.Fprintf(os.Stderr, "logjack flushsync fail with error %v\n", headPath) |
|
|
|
|
|
os.Exit(1) |
|
|
|
|
|
|
|
|
stdlog.Fatalf("logjack flushsync %q fail with error: %q", headPath, err.Error()) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func parseBytesize(chopSize string) int64 { |
|
|
|
|
|
|
|
|
func parseByteSize(chopSize string) (int64, error) { |
|
|
// Handle suffix multiplier
|
|
|
// Handle suffix multiplier
|
|
|
var multiplier int64 = 1 |
|
|
var multiplier int64 = 1 |
|
|
if strings.HasSuffix(chopSize, "T") { |
|
|
if strings.HasSuffix(chopSize, "T") { |
|
@ -106,8 +111,8 @@ func parseBytesize(chopSize string) int64 { |
|
|
// Parse the numeric part
|
|
|
// Parse the numeric part
|
|
|
chopSizeInt, err := strconv.Atoi(chopSize) |
|
|
chopSizeInt, err := strconv.Atoi(chopSize) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
panic(err) |
|
|
|
|
|
|
|
|
return 0, err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return int64(chopSizeInt) * multiplier |
|
|
|
|
|
|
|
|
return int64(chopSizeInt) * multiplier, nil |
|
|
} |
|
|
} |