PKGBUILD/pkg/logfile/logfile.go

134 lines
4.5 KiB
Go

package logfile
import (
"math"
"path/filepath"
"sort"
"time"
"github.com/go-flucky/flucky/pkg/types"
)
// var validUUID = regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
var timeFormat = "2006-01-02T15:04:05.999999Z07:00"
func Append(logfile Logfile, compression bool, round float64, measuredValues []types.MeasuredValue) error {
if round != 0 {
for _, measuredValue := range measuredValues {
measuredValue.SetValue(math.Round(measuredValue.GetValue()/round) * round)
}
}
allMeasuredValues, err := logfile.Read()
if err != nil {
return err
}
allMeasuredValues = append(allMeasuredValues, measuredValues...)
if compression {
allMeasuredValues = Compression(allMeasuredValues)
}
err = logfile.Write(allMeasuredValues)
if err != nil {
return err
}
return nil
}
// Compression the measured values. The system checks whether the measured values
// of the same type correspond to those of the predecessor. If this is the case,
// the current value is discarded and the validity date of the previous value is
// set to that of the current value. This means that no information is lost.
// Only the validity period of the measured value is increased.
func Compression(measuredValues []types.MeasuredValue) []types.MeasuredValue {
compressedMeasuredValues := make([]types.MeasuredValue, 0)
lastMeasuredValuesBySensors := make(map[string]map[types.MeasuredValueType]types.MeasuredValue, 0)
// Sort all measured values according to the start time of the validity date
// in order to successfully implement the subsequent compression.
sort.SliceStable(measuredValues, func(i int, j int) bool {
return measuredValues[i].GetFromDate().Before(measuredValues[j].GetFromDate())
})
now := time.Now()
for _, measuredValue := range measuredValues {
if _, ok := lastMeasuredValuesBySensors[measuredValue.GetSensorID()]; !ok {
lastMeasuredValuesBySensors[measuredValue.GetSensorID()] = make(map[types.MeasuredValueType]types.MeasuredValue, 0)
}
if _, ok := lastMeasuredValuesBySensors[measuredValue.GetSensorID()][measuredValue.GetMeasuredValueType()]; !ok {
lastMeasuredValuesBySensors[measuredValue.GetSensorID()][measuredValue.GetMeasuredValueType()] = measuredValue
continue
}
if lastMeasuredValuesBySensors[measuredValue.GetSensorID()][measuredValue.GetMeasuredValueType()].GetValue() == measuredValue.GetValue() {
lastMeasuredValuesBySensors[measuredValue.GetSensorID()][measuredValue.GetMeasuredValueType()].SetTillDate(measuredValue.GetTillDate())
lastMeasuredValuesBySensors[measuredValue.GetSensorID()][measuredValue.GetMeasuredValueType()].SetUpdateDate(&now)
} else if lastMeasuredValuesBySensors[measuredValue.GetSensorID()][measuredValue.GetMeasuredValueType()].GetValue() != measuredValue.GetValue() {
compressedMeasuredValues = append(compressedMeasuredValues, lastMeasuredValuesBySensors[measuredValue.GetSensorID()][measuredValue.GetMeasuredValueType()])
delete(lastMeasuredValuesBySensors[measuredValue.GetSensorID()], measuredValue.GetMeasuredValueType())
lastMeasuredValuesBySensors[measuredValue.GetSensorID()][measuredValue.GetMeasuredValueType()] = measuredValue
}
}
// Copy all remaining entries from the map into the cache array
for _, lastMeasuredValuesBySensor := range lastMeasuredValuesBySensors {
for _, measuredValueType := range types.MeasuredValueTypes {
if measuredValue, ok := lastMeasuredValuesBySensor[measuredValueType]; ok {
compressedMeasuredValues = append(compressedMeasuredValues, measuredValue)
}
}
}
// Sort all measured values again to include the measured values from the
// cache.
sort.SliceStable(compressedMeasuredValues, func(i int, j int) bool {
return compressedMeasuredValues[i].GetFromDate().Before(compressedMeasuredValues[j].GetFromDate())
})
return compressedMeasuredValues
}
// New returns a log file with basic functions for reading and writing data. The
// file extension of the logfile is taken into account to format the logfile
// into the correct format.
func New(logfile string) Logfile {
ext := filepath.Ext(logfile)
switch ext {
case ".csv":
return &csvLogfile{
logfile: logfile,
}
case ".json":
return &jsonLogfile{
logfile: logfile,
}
// case ".xml":
// return &xmlLogfile{
// logfile: logfile,
// }
default:
return &jsonLogfile{
logfile: logfile,
}
}
}
func writeCreationDate(measuredValues []types.MeasuredValue) {
now := time.Now()
for _, measuredValue := range measuredValues {
if measuredValue.GetCreationDate() == nil {
measuredValue.SetCreationDate(&now)
}
}
}