src.dualinventive.com/go/influxdb-logger/internal/influxdb/process.go

190 lines
4.2 KiB
Go

package influxdb
import (
"fmt"
"time"
client "github.com/influxdata/influxdb1-client/v2"
"github.com/sirupsen/logrus"
"src.dualinventive.com/go/dinet/rpc"
)
// Fetch the state and error fields from m.Result for device:data
func processDeviceDataFields(m *rpc.Msg) (map[string]interface{}, error) {
var result []map[string]interface{}
err := m.Result.Unmarshal(&result)
if err != nil {
return nil, fmt.Errorf("device:data error while unmarshalling result: %v", err)
}
if len(result) != 1 {
return nil, fmt.Errorf("device:data invalid number of items")
}
fields := make(map[string]interface{})
if state, ok := result[0]["state"].(string); ok {
fields["state"] = state
} else {
logrus.Warnf("Missing state in device:data, UID: %s", m.DeviceUID)
}
if resError, ok := result[0]["error"].(bool); ok {
fields["error"] = resError
} else {
logrus.Warnf("Missing error in device:data, UID: %s", m.DeviceUID)
}
if resErrors, ok := result[0]["errors"]; ok {
if errors, ok := resErrors.([]interface{}); ok {
fields["errors"] = errors
} else {
logrus.Warnf("device:data errors isn't a slice, T: %T, UID: %s", resErrors, m.DeviceUID)
}
}
return fields, nil
}
func (i *Influx) processDeviceData(m *rpc.Msg) error {
fields, err := processDeviceDataFields(m)
if err != nil {
return err
}
d, err := i.devCache.Device(m.DeviceUID)
if err != nil {
logrus.Warnf("cannot get device '%s' from cache: %v", m.DeviceUID, err)
}
keys := map[string]string{
"uid": m.DeviceUID,
"group": m.DeviceUID[0:2],
}
if d != nil && len(d.Type) != 0 {
keys["type"] = d.Type
}
if errors, ok := fields["errors"].([]interface{}); ok {
i.writeErrors(keys, errors, m.Time.ToTime())
}
rpcPt, err := client.NewPoint(
measurementDevice,
keys,
fields,
m.Time.ToTime(),
)
if err != nil {
logrus.Errorf("error while creating new samplepoint: %v", err)
return err
}
i.writer.Add(rpcPt)
return nil
}
func (i *Influx) writeResultValuesItem(rvi *rpc.ResultValueItem, class string, label string, keys map[string]string) {
time := rvi.Time.ToTime()
for _, sample := range rvi.Values.Samples {
pt, err := client.NewPoint(
class,
keys,
map[string]interface{}{label: sample},
time,
)
if err != nil {
logrus.Errorf("error while creating new samplepoint: %v", err)
continue
}
i.writer.Add(pt)
time = time.Add(rvi.Values.Interval)
}
}
func (i *Influx) processResultValueItems(m *rpc.Msg, class rpc.Class) error {
var items []rpc.ResultValueItem
err := m.Result.Unmarshal(&items)
if err != nil {
return err
}
d, err := i.devCache.Device(m.DeviceUID)
if err != nil {
logrus.Warnf("cannot get device '%s' from cache: %v", m.DeviceUID, err)
}
keys := map[string]string{
"uid": m.DeviceUID,
"group": m.DeviceUID[0:2],
}
// add the device type when this is known
if d != nil {
keys["type"] = d.Type
}
for _, data := range items {
_data := data
fieldInfo, err := d.FieldInfo(class, _data.UID)
// err is not nil when the field info is not found
if err != nil {
logrus.Warnf("cannot find %s info uid %d for device '%s' err: %v", class, _data.UID, m.DeviceUID, err)
continue
}
if data.Values != nil {
i.writeResultValuesItem(&_data, string(class), fieldInfo.Label, keys)
continue
}
fields, err := fieldInfo.Parse(&_data)
if err != nil {
logrus.Errorf("cannot use %v as type %s: %v", data.Value, fieldInfo.Type, err)
continue
}
pt, err := client.NewPoint(
string(class),
keys,
fields,
data.Time.ToTime(),
)
if err != nil {
logrus.Errorf("error while creating new samplepoint: %v", err)
continue
}
i.writer.Add(pt)
}
return nil
}
func (i *Influx) writeErrors(keys map[string]string, errors []interface{}, t time.Time) {
for _, diError := range errors {
if iErr, ok := diError.(float64); ok {
keys["error"] = fmt.Sprintf("%v", diError)
pt, err := client.NewPoint(
measurementDeviceError,
keys,
map[string]interface{}{
"code": int(iErr),
},
t,
)
if err != nil {
logrus.Errorf("error while creating new samplepoint: %v", err)
continue
}
i.writer.Add(pt)
} else {
logrus.Warnf("errors doesn't contain an int error, T: %T", diError)
}
}
delete(keys, "error")
}