From 686497ea5c9c69b858e672c59e92a49547d01f51 Mon Sep 17 00:00:00 2001
From: lspgn <lspgn@users.noreply.github.com>
Date: Thu, 27 May 2021 19:33:19 -0700
Subject: [PATCH] feature: implement SIGHUP for log rotation when using
 transport.destination

---
 transport/file/transport.go | 56 +++++++++++++++++++++++++++++++++----
 1 file changed, 51 insertions(+), 5 deletions(-)

diff --git a/transport/file/transport.go b/transport/file/transport.go
index 7cb867ca..b3d4e432 100644
--- a/transport/file/transport.go
+++ b/transport/file/transport.go
@@ -7,12 +7,17 @@ import (
 	"github.com/netsampler/goflow2/transport"
 	"io"
 	"os"
+	"os/signal"
+	"sync"
+	"syscall"
 )
 
 type FileDriver struct {
 	fileDestination string
 	w               io.Writer
 	file            *os.File
+	lock            *sync.RWMutex
+	q               chan bool
 }
 
 func (d *FileDriver) Prepare() error {
@@ -21,33 +26,74 @@ func (d *FileDriver) Prepare() error {
 	return nil
 }
 
+func (d *FileDriver) openFile() error {
+	file, err := os.OpenFile(d.fileDestination, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+	if err != nil {
+		return err
+	}
+	d.file = file
+	d.w = d.file
+	return err
+}
+
 func (d *FileDriver) Init(context.Context) error {
+	d.q = make(chan bool, 1)
+
 	if d.fileDestination == "" {
 		d.w = os.Stdout
 	} else {
 		var err error
-		d.file, err = os.OpenFile(d.fileDestination, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+
+		d.lock.Lock()
+		err = d.openFile()
+		d.lock.Unlock()
 		if err != nil {
 			return err
 		}
-		d.w = d.file
+
+		c := make(chan os.Signal, 1)
+		signal.Notify(c, syscall.SIGHUP)
+		go func() {
+			for {
+				select {
+				case <-c:
+					d.lock.Lock()
+					d.file.Close()
+					d.openFile()
+					d.lock.Unlock()
+					// if there is an error, keeps using the old file
+				case <-d.q:
+					return
+				}
+			}
+		}()
+
 	}
 	return nil
 }
 
 func (d *FileDriver) Send(key, data []byte) error {
-	fmt.Fprintln(d.w, string(data))
-	return nil
+	d.lock.RLock()
+	w := d.w
+	d.lock.RUnlock()
+	_, err := fmt.Fprintln(w, string(data))
+	return err
 }
 
 func (d *FileDriver) Close(context.Context) error {
 	if d.fileDestination != "" {
+		d.lock.Lock()
 		d.file.Close()
+		d.lock.Unlock()
+		signal.Ignore(syscall.SIGHUP)
 	}
+	close(d.q)
 	return nil
 }
 
 func init() {
-	d := &FileDriver{}
+	d := &FileDriver{
+		lock: &sync.RWMutex{},
+	}
 	transport.RegisterTransportDriver("file", d)
 }