fix: Add support for opcua datetime values (#12101)
This commit is contained in:
parent
e305973731
commit
e42b0832e0
|
|
@ -3,13 +3,14 @@ package opcua
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gopcua/opcua"
|
"github.com/gopcua/opcua"
|
||||||
"github.com/gopcua/opcua/ua"
|
"github.com/gopcua/opcua/ua"
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
"github.com/influxdata/telegraf/config"
|
"github.com/influxdata/telegraf/config"
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OpcUAWorkarounds struct {
|
type OpcUAWorkarounds struct {
|
||||||
|
|
@ -56,6 +57,7 @@ func (o *OpcUAClientConfig) validateEndpoint() error {
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("invalid security type '%s' in '%s'", o.SecurityMode, o.Endpoint)
|
return fmt.Errorf("invalid security type '%s' in '%s'", o.SecurityMode, o.Endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,16 @@ package input
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gopcua/opcua/ua"
|
"github.com/gopcua/opcua/ua"
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
"github.com/influxdata/telegraf/internal/choice"
|
"github.com/influxdata/telegraf/internal/choice"
|
||||||
"github.com/influxdata/telegraf/metric"
|
"github.com/influxdata/telegraf/metric"
|
||||||
"github.com/influxdata/telegraf/plugins/common/opcua"
|
"github.com/influxdata/telegraf/plugins/common/opcua"
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeSettings describes how to map from a OPC UA node to a Metric
|
// NodeSettings describes how to map from a OPC UA node to a Metric
|
||||||
|
|
@ -52,10 +53,11 @@ const (
|
||||||
// InputClientConfig a configuration for the input client
|
// InputClientConfig a configuration for the input client
|
||||||
type InputClientConfig struct {
|
type InputClientConfig struct {
|
||||||
opcua.OpcUAClientConfig
|
opcua.OpcUAClientConfig
|
||||||
MetricName string `toml:"name"`
|
MetricName string `toml:"name"`
|
||||||
Timestamp TimestampSource `toml:"timestamp"`
|
Timestamp TimestampSource `toml:"timestamp"`
|
||||||
RootNodes []NodeSettings `toml:"nodes"`
|
TimestampFormat string `toml:"timestamp_format"`
|
||||||
Groups []NodeGroupSettings `toml:"group"`
|
RootNodes []NodeSettings `toml:"nodes"`
|
||||||
|
Groups []NodeGroupSettings `toml:"group"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *InputClientConfig) Validate() error {
|
func (o *InputClientConfig) Validate() error {
|
||||||
|
|
@ -68,6 +70,10 @@ func (o *InputClientConfig) Validate() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.TimestampFormat == "" {
|
||||||
|
o.TimestampFormat = time.RFC3339Nano
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -356,8 +362,14 @@ func (o *OpcUAInputClient) UpdateNodeValue(nodeIdx int, d *ua.DataValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.Value != nil {
|
if d.Value != nil {
|
||||||
o.LastReceivedData[nodeIdx].Value = d.Value.Value()
|
|
||||||
o.LastReceivedData[nodeIdx].DataType = d.Value.Type()
|
o.LastReceivedData[nodeIdx].DataType = d.Value.Type()
|
||||||
|
|
||||||
|
o.LastReceivedData[nodeIdx].Value = d.Value.Value()
|
||||||
|
if o.LastReceivedData[nodeIdx].DataType == ua.TypeIDDateTime {
|
||||||
|
if t, ok := d.Value.Value().(time.Time); ok {
|
||||||
|
o.LastReceivedData[nodeIdx].Value = t.Format(o.Config.TimestampFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
o.LastReceivedData[nodeIdx].ServerTime = d.ServerTimestamp
|
o.LastReceivedData[nodeIdx].ServerTime = d.ServerTimestamp
|
||||||
o.LastReceivedData[nodeIdx].SourceTime = d.SourceTimestamp
|
o.LastReceivedData[nodeIdx].SourceTime = d.SourceTimestamp
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ package opcua
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
"github.com/influxdata/telegraf/config"
|
"github.com/influxdata/telegraf/config"
|
||||||
"github.com/influxdata/telegraf/plugins/common/opcua"
|
"github.com/influxdata/telegraf/plugins/common/opcua"
|
||||||
|
|
@ -9,8 +12,6 @@ import (
|
||||||
"github.com/influxdata/telegraf/testutil"
|
"github.com/influxdata/telegraf/testutil"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/testcontainers/testcontainers-go/wait"
|
"github.com/testcontainers/testcontainers-go/wait"
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const servicePort = "4840"
|
const servicePort = "4840"
|
||||||
|
|
@ -119,6 +120,7 @@ func TestReadClientIntegration(t *testing.T) {
|
||||||
{"ManufacturerName", "0", "i", "2263", "open62541"},
|
{"ManufacturerName", "0", "i", "2263", "open62541"},
|
||||||
{"badnode", "1", "i", "1337", nil},
|
{"badnode", "1", "i", "1337", nil},
|
||||||
{"goodnode", "1", "s", "the.answer", int32(42)},
|
{"goodnode", "1", "s", "the.answer", int32(42)},
|
||||||
|
{"DateTime", "1", "i", "51037", "0001-01-01T00:00:00Z"},
|
||||||
}
|
}
|
||||||
|
|
||||||
readConfig := ReadClientConfig{
|
readConfig := ReadClientConfig{
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,12 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||||
## "source" -- uses the timestamp provided by the source
|
## "source" -- uses the timestamp provided by the source
|
||||||
# timestamp = "gather"
|
# timestamp = "gather"
|
||||||
#
|
#
|
||||||
|
## The default timetsamp format is RFC3339Nano
|
||||||
|
# Other timestamp layouts can be configured using the Go language time
|
||||||
|
# layout specification from https://golang.org/pkg/time/#Time.Format
|
||||||
|
# e.g.: json_timestamp_format = "2006-01-02T15:04:05Z07:00"
|
||||||
|
#timestamp_format = ""
|
||||||
|
#
|
||||||
## Node ID configuration
|
## Node ID configuration
|
||||||
## name - field name to use in the output
|
## name - field name to use in the output
|
||||||
## namespace - OPC UA namespace of the node (integer value 0 thru 3)
|
## namespace - OPC UA namespace of the node (integer value 0 thru 3)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ package opcua_listener
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
"github.com/influxdata/telegraf/config"
|
"github.com/influxdata/telegraf/config"
|
||||||
"github.com/influxdata/telegraf/plugins/common/opcua"
|
"github.com/influxdata/telegraf/plugins/common/opcua"
|
||||||
|
|
@ -10,8 +13,6 @@ import (
|
||||||
"github.com/influxdata/telegraf/testutil"
|
"github.com/influxdata/telegraf/testutil"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/testcontainers/testcontainers-go/wait"
|
"github.com/testcontainers/testcontainers-go/wait"
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const servicePort = "4840"
|
const servicePort = "4840"
|
||||||
|
|
@ -54,6 +55,7 @@ func TestSubscribeClientIntegration(t *testing.T) {
|
||||||
{"ManufacturerName", "0", "i", "2263", "open62541"},
|
{"ManufacturerName", "0", "i", "2263", "open62541"},
|
||||||
{"badnode", "1", "i", "1337", nil},
|
{"badnode", "1", "i", "1337", nil},
|
||||||
{"goodnode", "1", "s", "the.answer", int32(42)},
|
{"goodnode", "1", "s", "the.answer", int32(42)},
|
||||||
|
{"DateTime", "1", "i", "51037", "0001-01-01T00:00:00Z"},
|
||||||
}
|
}
|
||||||
var tagsRemaining = make([]string, 0, len(testopctags))
|
var tagsRemaining = make([]string, 0, len(testopctags))
|
||||||
for i, tag := range testopctags {
|
for i, tag := range testopctags {
|
||||||
|
|
@ -152,6 +154,7 @@ security_mode = "auto"
|
||||||
certificate = "/etc/telegraf/cert.pem"
|
certificate = "/etc/telegraf/cert.pem"
|
||||||
private_key = "/etc/telegraf/key.pem"
|
private_key = "/etc/telegraf/key.pem"
|
||||||
auth_method = "Anonymous"
|
auth_method = "Anonymous"
|
||||||
|
timestamp_format = "2006-01-02T15:04:05Z07:00"
|
||||||
username = ""
|
username = ""
|
||||||
password = ""
|
password = ""
|
||||||
nodes = [
|
nodes = [
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,12 @@
|
||||||
## "source" -- uses the timestamp provided by the source
|
## "source" -- uses the timestamp provided by the source
|
||||||
# timestamp = "gather"
|
# timestamp = "gather"
|
||||||
#
|
#
|
||||||
|
## The default timetsamp format is RFC3339Nano
|
||||||
|
# Other timestamp layouts can be configured using the Go language time
|
||||||
|
# layout specification from https://golang.org/pkg/time/#Time.Format
|
||||||
|
# e.g.: json_timestamp_format = "2006-01-02T15:04:05Z07:00"
|
||||||
|
#timestamp_format = ""
|
||||||
|
#
|
||||||
## Node ID configuration
|
## Node ID configuration
|
||||||
## name - field name to use in the output
|
## name - field name to use in the output
|
||||||
## namespace - OPC UA namespace of the node (integer value 0 thru 3)
|
## namespace - OPC UA namespace of the node (integer value 0 thru 3)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue