From fd638452ac750563111716fab4e04d1cf321caea Mon Sep 17 00:00:00 2001 From: Markus Pesch Date: Mon, 4 Mar 2019 10:45:00 +0100 Subject: [PATCH] feat: file logger --- cmd/cmd.go | 8 ++ pkg/config/fluckyconfig.go | 7 +- pkg/logger/file_logger.go | 161 +++++++++++++++++++++++++++++++++++++ pkg/logger/logger.go | 24 ++++++ 4 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 pkg/logger/file_logger.go create mode 100644 pkg/logger/logger.go diff --git a/cmd/cmd.go b/cmd/cmd.go index aae02ab..90b5b15 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -8,6 +8,7 @@ import ( "git.cryptic.systems/fh-trier/go-flucky/cmd/remote" "git.cryptic.systems/fh-trier/go-flucky/cmd/sensor" "git.cryptic.systems/fh-trier/go-flucky/cmd/temperature" + "git.cryptic.systems/fh-trier/go-flucky/pkg/logger" "git.cryptic.systems/fh-trier/go-flucky/pkg/types" "git.cryptic.systems/fh-trier/go-flucky/pkg/config" @@ -29,12 +30,19 @@ var rootCmd = &cobra.Command{ return fmt.Errorf("Can not locate the hostname: %v", err) } + logfiles := make(map[logger.LogValue][]string) + logfiles[logger.LogHumidity] = []string{"/var/log/flucky/humidity.log"} + logfiles[logger.LogTemperature] = []string{"/var/log/flucky/temperature.log"} + fc := config.FluckyConfig{ Device: &types.Device{ DeviceID: uuid.NewV4().String(), DeviceName: hostname, CreationDate: time.Now(), }, + FileLogger: &logger.FileLogger{ + LogFiles: logfiles, + }, } err = config.Write(&fc, cfg) diff --git a/pkg/config/fluckyconfig.go b/pkg/config/fluckyconfig.go index 33c8317..d76ef3e 100644 --- a/pkg/config/fluckyconfig.go +++ b/pkg/config/fluckyconfig.go @@ -8,6 +8,8 @@ import ( "text/tabwriter" "time" + "git.cryptic.systems/fh-trier/go-flucky/pkg/logger" + "git.cryptic.systems/fh-trier/go-flucky/pkg/sensor" "git.cryptic.systems/fh-trier/go-flucky/pkg/types" @@ -16,9 +18,10 @@ import ( // FluckyConfig dasd type FluckyConfig struct { - Device *types.Device `json:"device"` - Sensors []*types.Sensor `json:"sensors"` + Device *types.Device `json:"device"` + *logger.FileLogger Remotes []*Remote `json:"remotes"` + Sensors []*types.Sensor `json:"sensors"` } // AddSensor add a new sensor diff --git a/pkg/logger/file_logger.go b/pkg/logger/file_logger.go new file mode 100644 index 0000000..8704f9e --- /dev/null +++ b/pkg/logger/file_logger.go @@ -0,0 +1,161 @@ +package logger + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sync" + + "git.cryptic.systems/fh-trier/go-flucky/pkg/internal/errutils" + + "git.cryptic.systems/fh-trier/go-flucky/pkg/types" +) + +type FileLogger struct { + LogFiles map[LogValue][]string `json:"logfiles"` + writer io.Writer +} + +func (fl *FileLogger) AddLogFile(logfile string, logValue LogValue) { + fl.LogFiles[logValue] = append(fl.LogFiles[logValue], logfile) +} + +func (fl *FileLogger) LogHumidities(humidities []*types.Humidity) error { + countLogfiles := len(fl.LogFiles[LogHumidity]) + wg := sync.WaitGroup{} + wg.Add(countLogfiles) + + errChan := make(chan error) + + for _, logfile := range fl.LogFiles[LogHumidity] { + go func(humidities []*types.Humidity, logfile string) { + defer wg.Done() + + // read existing humidities as bytes + bytes, err := ioutil.ReadFile(logfile) + if err != nil { + errChan <- err + return + } + + // convert bytes into humidities + logHumidities := []*types.Humidity{} + err = json.Unmarshal(bytes, &logHumidities) + if err != nil { + errChan <- err + return + } + + // append new humidities with exsisting humidities from logfile + logHumidities = append(logHumidities, humidities...) + + // convert humidities into json file + bytes, err = json.MarshalIndent(logHumidities, "", " ") + err = json.Unmarshal(bytes, &logHumidities) + if err != nil { + errChan <- err + return + } + + ioutil.WriteFile(logfile, bytes, os.ModePerm) + + }(humidities, logfile) + } + + wg.Wait() + + errList := errutils.CollectErrors(errChan) + err := errutils.FormatErrors(errList) + if err != nil { + return err + } + return nil +} + +func (fl *FileLogger) LogTemperatures(temperatures []*types.Temperature) error { + countLogfiles := len(fl.LogFiles[LogTemperature]) + wg := sync.WaitGroup{} + wg.Add(countLogfiles) + + errChan := make(chan error) + + for _, logfile := range fl.LogFiles[LogTemperature] { + go func(temps []*types.Temperature, lf string) { + defer wg.Done() + + if _, err := os.Stat(lf); os.IsNotExist(err) { + err := os.MkdirAll(filepath.Dir(lf), os.ModeDir) + if err != nil { + errChan <- fmt.Errorf("Can not create directory: %v", err) + return + } + f, err := os.Create(lf) + if err != nil { + errChan <- fmt.Errorf("Can not create log file: %v", err) + return + } + f.Close() + } + + // open logfile + f, err := os.Open(lf) + if err != nil { + errChan <- err + return + } + + // decode file content into temperatures + logTemperatures := []*types.Temperature{} + decoder := json.NewDecoder(f) + err = decoder.Decode(&logTemperatures) + if err != nil { + errChan <- err + return + } + + // close file + f.Close() + + // append new humidities with exsisting humidities from logfile + logTemperatures = append(logTemperatures, temps...) + + // create new logfile + f, err = os.Create(lf) + if err != nil { + errChan <- err + return + } + + // convert humidities into json file + encoder := json.NewEncoder(f) + encoder.SetIndent("", " ") + err = encoder.Encode(logTemperatures) + if err != nil { + errChan <- err + return + } + + f.Close() + + }(temperatures, logfile) + } + + wg.Wait() + + errList := errutils.CollectErrors(errChan) + err := errutils.FormatErrors(errList) + if err != nil { + return err + } + + return nil +} + +func NewFileLogger(w io.Writer) *FileLogger { + return &FileLogger{ + writer: w, + } +} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go new file mode 100644 index 0000000..f9fc484 --- /dev/null +++ b/pkg/logger/logger.go @@ -0,0 +1,24 @@ +package logger + +import ( + "git.cryptic.systems/fh-trier/go-flucky/pkg/types" +) + +type Logger interface { + LogHumidities(humidities []*types.Humidity) error + LogTemperatures(temperatures []*types.Temperature) error +} + +type LoggerType string + +const ( + LogFile LoggerType = "file" + LogRemote = "remote" +) + +type LogValue string + +const ( + LogHumidity LogValue = "humidity" + LogTemperature = "temperature" +)