github.com/vipernet-xyz/tm@v0.34.24/libs/autofile/cmd/logjack.go (about)

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