in pcap-cli/pkg/pcap/pcap_writer.go [162:218]
func NewPcapWriter(ctx context.Context, ifaceAndInfex, template, extension, timezone *string, interval int) (PcapWriter, error) {
isStdOutOrErr := isStdoutPcapWriter(template, extension, &interval)
loggerPrefix := fmt.Sprintf("[pcap/writer] - [%s] – ", *ifaceAndInfex)
if isStdOutOrErr {
loggerPrefix += "[stdout] – "
} else {
loggerPrefix = fmt.Sprintf("%s[%s] - ", loggerPrefix, *extension)
}
logger := log.New(os.Stderr, loggerPrefix, log.LstdFlags)
var err error
var writer *logrotate.Writer
if isStdOutOrErr {
// Using `logrotate` to make `os.Stdout` safe to be concurrently written by PCAP engines
writer, err = newPcapWriterForStdout(logger)
} else {
writer, err = newPcapWriter(logger, template, extension, timezone, &interval)
}
if err != nil {
return nil, err
}
// `logrotate` does not provide handles to `*bufio.Writer::Flush`/`*os.File::Syinc`
// the underlying Writer/File so it is necessary to get handles on them.
// Since PCAP engines are started atomically and current execution must complete
// before a new one can be started; it is safe to `flush` and `sync` PCAP files.
// https://github.com/easyCZ/logrotate/blob/master/writer.go
v := reflect.ValueOf(writer)
osFile := getSetableField(v, "f")
osFileSync := osFile.MethodByName("Sync")
bufioWriter := getSetableField(v, "bw")
bufioWriterFlush := bufioWriter.MethodByName("Flush")
if isStdOutOrErr {
// injecting `os.Stdout` into `logrotate.Writer` instance
osFile.Set(reflect.ValueOf(os.Stdout))
bufioWriter.Set(reflect.ValueOf(bufio.NewWriterSize(os.Stdout, 1)))
}
w := &pcapWriter{writer, ifaceAndInfex, isStdOutOrErr, v, osFile, osFileSync, bufioWriter, bufioWriterFlush}
go func(ctx context.Context, writer *logrotate.Writer, block bool) {
if !block {
return
}
<-ctx.Done()
logger.Println("- ROTATE")
rotate(writer)
}(ctx, writer, !isStdOutOrErr)
logger.Println("- created")
return w, nil
}