diff --git a/main.go b/main.go index 497efc9..eb2dee6 100644 --- a/main.go +++ b/main.go @@ -27,13 +27,16 @@ import ( "io" "os" "fmt" + "sync" "bufio" "strings" + "syscall" + "os/signal" "github.com/spf13/pflag" ) const ( - version = "0.6.1" + version = "0.6.2" ) var ( @@ -42,19 +45,43 @@ var ( // Default delimiter delimiter = "," + + Writer *bufio.Writer ) +func NewWriter(file string) (*bufio.Writer, *os.File, error) { + if len(file) > 0 { + var f *os.File + var err error + + f, err = os.OpenFile(file, os.O_CREATE|os.O_WRONLY, 0640) + if err != nil { + return nil, nil, err + } + Writer = bufio.NewWriter(f) + return Writer, f, nil + } else { + Writer = bufio.NewWriter(os.Stdout) + return Writer, nil, nil + } +} + func main() { var flags int var oneLine bool var noUserResolve bool var syslog23 bool var json bool + var outputFile string + // Output file mutex + var outfMtx sync.Mutex + var outFile *os.File pflag.BoolVarP(&oneLine, "oneline", "l", false, "Prints the entire record on the same line") pflag.BoolVarP(&noUserResolve, "numeric", "n", false, "Do not convert user and group IDs to their names but leave in their numeric forms") pflag.BoolVarP(&json, "json", "j", false, "Print compact json") pflag.BoolVarP(&syslog23, "syslog23", "s", false, "Print time as \"2006-01-02T15:04:05.000Z07:00\", RFC339 with ms, also used on RSYSLOG_SyslogProtocol23Format. \"msec\" field will not be print in json output") + pflag.StringVarP(&outputFile, "out", "o", "", "Output to file, overwrite existing. File will be re-opened receiving SIGUSR1.") pflag.BoolVarP(&showVersion, "version", "V", false, "Show version and exit") var Usage = func() { @@ -90,9 +117,35 @@ func main() { } filename := args[len(args)-1] + // Get a writer, file or stdout + _, outFile, err := NewWriter(outputFile) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } + if len(outputFile) > 0 { + // Manage output file rotation when receiving SIGUSR1 + sig := make(chan os.Signal) + signal.Notify(sig, syscall.SIGUSR1) + go func() { + for { + <-sig + outfMtx.Lock() + fmt.Println("SIGUSR1 received, recreating output file") + outFile.Close() + _, outFile, err = NewWriter(outputFile) + if err != nil { + outfMtx.Unlock() + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } + outfMtx.Unlock() + } + }() + } + var f *os.File var r *bufio.Reader - var err error if len(filename) > 0 { // If arg is "-", open stdin to read content if true == strings.EqualFold(filename, "-") { @@ -100,13 +153,12 @@ func main() { } else { f, err = os.Open(filename) if err != nil { - fmt.Printf("Impossible d'ouvrir le fichier %s\n", filename) + fmt.Fprintf(os.Stderr, "Impossible d'ouvrir le fichier %s\n", filename) os.Exit(-1) } r = bufio.NewReader(f) } - //for i := 0 ; i < 20 ; i++ { for { rec, err := readRecordToStruct(r) if err != nil { @@ -116,7 +168,21 @@ func main() { return } } - rec.Print(os.Stdout, ",", flags) + if len(outputFile) > 0 { + outfMtx.Lock() + rec.Print(Writer, ",", flags) + Writer.Flush() // Performance ? + outfMtx.Unlock() + } else { + // No need for mutex with stdout + rec.Print(Writer, ",", flags) + } } } + + if len(outputFile) > 0 && outFile != nil { + outfMtx.Lock() + outFile.Close() + outfMtx.Unlock() + } }