feat: Migrate xpath parser to new style (#11218)
This commit is contained in:
parent
0b7c3c4b24
commit
0d96968819
|
|
@ -1842,9 +1842,7 @@ func (c *Config) missingTomlField(_ reflect.Type, key string) error {
|
|||
"prefix", "prometheus_export_timestamp", "prometheus_ignore_timestamp", "prometheus_sort_metrics", "prometheus_string_as_label",
|
||||
"separator", "splunkmetric_hec_routing", "splunkmetric_multimetric", "tag_keys",
|
||||
"tagdrop", "tagexclude", "taginclude", "tagpass", "tags", "template", "templates",
|
||||
"value_field_name", "wavefront_source_override", "wavefront_use_strict", "wavefront_disable_prefix_conversion",
|
||||
"xml", "xpath", "xpath_json", "xpath_msgpack", "xpath_protobuf", "xpath_print_document",
|
||||
"xpath_protobuf_file", "xpath_protobuf_type", "xpath_protobuf_import_paths":
|
||||
"value_field_name", "wavefront_source_override", "wavefront_use_strict", "wavefront_disable_prefix_conversion":
|
||||
|
||||
// ignore fields that are common to all plugins.
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -406,7 +406,6 @@ func TestConfig_ParserInterfaceNewFormat(t *testing.T) {
|
|||
}
|
||||
|
||||
override := map[string]struct {
|
||||
cfg *parsers.Config
|
||||
param map[string]interface{}
|
||||
mask []string
|
||||
}{
|
||||
|
|
@ -420,11 +419,6 @@ func TestConfig_ParserInterfaceNewFormat(t *testing.T) {
|
|||
mask: []string{"Now"},
|
||||
},
|
||||
"xpath_protobuf": {
|
||||
cfg: &parsers.Config{
|
||||
MetricName: "parser_test_new",
|
||||
XPathProtobufFile: "testdata/addressbook.proto",
|
||||
XPathProtobufType: "addressbook.AddressBook",
|
||||
},
|
||||
param: map[string]interface{}{
|
||||
"ProtobufMessageDef": "testdata/addressbook.proto",
|
||||
"ProtobufMessageType": "addressbook.AddressBook",
|
||||
|
|
@ -435,10 +429,6 @@ func TestConfig_ParserInterfaceNewFormat(t *testing.T) {
|
|||
expected := make([]telegraf.Parser, 0, len(formats))
|
||||
for _, format := range formats {
|
||||
formatCfg := &cfg
|
||||
settings, hasOverride := override[format]
|
||||
if hasOverride && settings.cfg != nil {
|
||||
formatCfg = settings.cfg
|
||||
}
|
||||
formatCfg.DataFormat = format
|
||||
|
||||
logger := models.NewLogger("parsers", format, cfg.MetricName)
|
||||
|
|
@ -555,7 +545,6 @@ func TestConfig_ParserInterfaceOldFormat(t *testing.T) {
|
|||
}
|
||||
|
||||
override := map[string]struct {
|
||||
cfg *parsers.Config
|
||||
param map[string]interface{}
|
||||
mask []string
|
||||
}{
|
||||
|
|
@ -569,11 +558,6 @@ func TestConfig_ParserInterfaceOldFormat(t *testing.T) {
|
|||
mask: []string{"Now"},
|
||||
},
|
||||
"xpath_protobuf": {
|
||||
cfg: &parsers.Config{
|
||||
MetricName: "parser_test_new",
|
||||
XPathProtobufFile: "testdata/addressbook.proto",
|
||||
XPathProtobufType: "addressbook.AddressBook",
|
||||
},
|
||||
param: map[string]interface{}{
|
||||
"ProtobufMessageDef": "testdata/addressbook.proto",
|
||||
"ProtobufMessageType": "addressbook.AddressBook",
|
||||
|
|
@ -584,10 +568,6 @@ func TestConfig_ParserInterfaceOldFormat(t *testing.T) {
|
|||
expected := make([]telegraf.Parser, 0, len(formats))
|
||||
for _, format := range formats {
|
||||
formatCfg := &cfg
|
||||
settings, hasOverride := override[format]
|
||||
if hasOverride && settings.cfg != nil {
|
||||
formatCfg = settings.cfg
|
||||
}
|
||||
formatCfg.DataFormat = format
|
||||
|
||||
logger := models.NewLogger("parsers", format, cfg.MetricName)
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ package all
|
|||
import (
|
||||
//Blank imports for plugins to register themselves
|
||||
_ "github.com/influxdata/telegraf/plugins/parsers/csv"
|
||||
_ "github.com/influxdata/telegraf/plugins/parsers/xpath"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import (
|
|||
"github.com/influxdata/telegraf/plugins/parsers/prometheusremotewrite"
|
||||
"github.com/influxdata/telegraf/plugins/parsers/value"
|
||||
"github.com/influxdata/telegraf/plugins/parsers/wavefront"
|
||||
"github.com/influxdata/telegraf/plugins/parsers/xpath"
|
||||
)
|
||||
|
||||
// Creator is the function to create a new parser
|
||||
|
|
@ -184,12 +183,12 @@ type Config struct {
|
|||
ValueFieldName string `toml:"value_field_name"`
|
||||
|
||||
// XPath configuration
|
||||
XPathPrintDocument bool `toml:"xpath_print_document"`
|
||||
XPathProtobufFile string `toml:"xpath_protobuf_file"`
|
||||
XPathProtobufType string `toml:"xpath_protobuf_type"`
|
||||
XPathProtobufImportPaths []string `toml:"xpath_protobuf_import_paths"`
|
||||
XPathAllowEmptySelection bool `toml:"xpath_allow_empty_selection"`
|
||||
XPathConfig []XPathConfig
|
||||
XPathPrintDocument bool `toml:"xpath_print_document"`
|
||||
XPathProtobufFile string `toml:"xpath_protobuf_file"`
|
||||
XPathProtobufType string `toml:"xpath_protobuf_type"`
|
||||
XPathProtobufImportPaths []string `toml:"xpath_protobuf_import_paths"`
|
||||
XPathAllowEmptySelection bool `toml:"xpath_allow_empty_selection"`
|
||||
XPathConfig []XPathConfig `toml:"xpath"`
|
||||
|
||||
// JSONPath configuration
|
||||
JSONV2Config []JSONV2Config `toml:"json_v2"`
|
||||
|
|
@ -201,7 +200,29 @@ type Config struct {
|
|||
LogFmtTagKeys []string `toml:"logfmt_tag_keys"`
|
||||
}
|
||||
|
||||
type XPathConfig xpath.Config
|
||||
// XPathConfig definition for backward compatibitlity ONLY.
|
||||
// We need this here to avoid cyclic dependencies. However, we need
|
||||
// to move this to plugins/parsers/xpath once we deprecate parser
|
||||
// construction via `NewParser()`.
|
||||
type XPathConfig struct {
|
||||
MetricQuery string `toml:"metric_name"`
|
||||
Selection string `toml:"metric_selection"`
|
||||
Timestamp string `toml:"timestamp"`
|
||||
TimestampFmt string `toml:"timestamp_format"`
|
||||
Tags map[string]string `toml:"tags"`
|
||||
Fields map[string]string `toml:"fields"`
|
||||
FieldsInt map[string]string `toml:"fields_int"`
|
||||
|
||||
FieldSelection string `toml:"field_selection"`
|
||||
FieldNameQuery string `toml:"field_name"`
|
||||
FieldValueQuery string `toml:"field_value"`
|
||||
FieldNameExpand bool `toml:"field_name_expansion"`
|
||||
|
||||
TagSelection string `toml:"tag_selection"`
|
||||
TagNameQuery string `toml:"tag_name"`
|
||||
TagValueQuery string `toml:"tag_value"`
|
||||
TagNameExpand bool `toml:"tag_name_expansion"`
|
||||
}
|
||||
|
||||
type JSONV2Config struct {
|
||||
json_v2.Config
|
||||
|
|
@ -280,17 +301,6 @@ func NewParser(config *Config) (Parser, error) {
|
|||
)
|
||||
case "prometheusremotewrite":
|
||||
parser, err = NewPrometheusRemoteWriteParser(config.DefaultTags)
|
||||
case "xml", "xpath_json", "xpath_msgpack", "xpath_protobuf":
|
||||
parser = &xpath.Parser{
|
||||
Format: config.DataFormat,
|
||||
ProtobufMessageDef: config.XPathProtobufFile,
|
||||
ProtobufMessageType: config.XPathProtobufType,
|
||||
ProtobufImportPaths: config.XPathProtobufImportPaths,
|
||||
PrintDocument: config.XPathPrintDocument,
|
||||
DefaultTags: config.DefaultTags,
|
||||
AllowEmptySelection: config.XPathAllowEmptySelection,
|
||||
Configs: NewXPathParserConfigs(config.MetricName, config.XPathConfig),
|
||||
}
|
||||
case "json_v2":
|
||||
parser, err = NewJSONPathParser(config.JSONV2Config)
|
||||
default:
|
||||
|
|
@ -429,17 +439,6 @@ func NewPrometheusRemoteWriteParser(defaultTags map[string]string) (Parser, erro
|
|||
}, nil
|
||||
}
|
||||
|
||||
func NewXPathParserConfigs(metricName string, cfgs []XPathConfig) []xpath.Config {
|
||||
// Convert the config formats which is a one-to-one copy
|
||||
configs := make([]xpath.Config, 0, len(cfgs))
|
||||
for _, cfg := range cfgs {
|
||||
config := xpath.Config(cfg)
|
||||
config.MetricDefaultName = metricName
|
||||
configs = append(configs, config)
|
||||
}
|
||||
return configs
|
||||
}
|
||||
|
||||
func NewJSONPathParser(jsonv2config []JSONV2Config) (Parser, error) {
|
||||
configs := make([]json_v2.Config, len(jsonv2config))
|
||||
for i, cfg := range jsonv2config {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@ package parsers_test
|
|||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
|
|
@ -15,6 +18,8 @@ func TestRegistry_BackwardCompatibility(t *testing.T) {
|
|||
cfg := &parsers.Config{
|
||||
MetricName: "parser_compatibility_test",
|
||||
CSVHeaderRowCount: 42,
|
||||
XPathProtobufFile: "xpath/testcases/protos/addressbook.proto",
|
||||
XPathProtobufType: "addressbook.AddressBook",
|
||||
}
|
||||
|
||||
// Some parsers need certain settings to not error. Furthermore, we
|
||||
|
|
@ -29,6 +34,12 @@ func TestRegistry_BackwardCompatibility(t *testing.T) {
|
|||
},
|
||||
mask: []string{"TimeFunc"},
|
||||
},
|
||||
"xpath_protobuf": {
|
||||
param: map[string]interface{}{
|
||||
"ProtobufMessageDef": cfg.XPathProtobufFile,
|
||||
"ProtobufMessageType": cfg.XPathProtobufType,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, creator := range parsers.Parsers {
|
||||
|
|
@ -52,19 +63,23 @@ func TestRegistry_BackwardCompatibility(t *testing.T) {
|
|||
actual, err := parsers.NewParser(cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Compare with mask
|
||||
if settings, found := override[name]; found {
|
||||
a := reflect.Indirect(reflect.ValueOf(actual))
|
||||
e := reflect.Indirect(reflect.ValueOf(expected))
|
||||
for _, key := range settings.mask {
|
||||
af := a.FieldByName(key)
|
||||
ef := e.FieldByName(key)
|
||||
|
||||
v := reflect.Zero(ef.Type())
|
||||
af.Set(v)
|
||||
ef.Set(v)
|
||||
}
|
||||
// Determine the underlying type of the parser
|
||||
stype := reflect.Indirect(reflect.ValueOf(expected)).Interface()
|
||||
// Ignore all unexported fields and fields not relevant for functionality
|
||||
options := []cmp.Option{
|
||||
cmpopts.IgnoreUnexported(stype),
|
||||
cmpopts.IgnoreTypes(sync.Mutex{}),
|
||||
cmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}),
|
||||
}
|
||||
require.EqualValuesf(t, expected, actual, "format %q", name)
|
||||
|
||||
// Add overrides and masks to compare options
|
||||
if settings, found := override[name]; found {
|
||||
options = append(options, cmpopts.IgnoreFields(stype, settings.mask...))
|
||||
}
|
||||
|
||||
// Do a manual comparision as require.EqualValues will also work on unexported fields
|
||||
// that cannot be cleared or ignored.
|
||||
diff := cmp.Diff(expected, actual, options...)
|
||||
require.Emptyf(t, diff, "Difference for %q", name)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package xpath
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -11,6 +12,7 @@ import (
|
|||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/internal"
|
||||
"github.com/influxdata/telegraf/metric"
|
||||
"github.com/influxdata/telegraf/plugins/parsers"
|
||||
)
|
||||
|
||||
type dataNode interface{}
|
||||
|
|
@ -24,39 +26,25 @@ type dataDocument interface {
|
|||
}
|
||||
|
||||
type Parser struct {
|
||||
Format string
|
||||
ProtobufMessageDef string
|
||||
ProtobufMessageType string
|
||||
ProtobufImportPaths []string
|
||||
PrintDocument bool
|
||||
AllowEmptySelection bool
|
||||
Configs []Config
|
||||
DefaultTags map[string]string
|
||||
Log telegraf.Logger
|
||||
Format string `toml:"-"`
|
||||
ProtobufMessageDef string `toml:"xpath_protobuf_file"`
|
||||
ProtobufMessageType string `toml:"xpath_protobuf_type"`
|
||||
ProtobufImportPaths []string `toml:"xpath_protobuf_import_paths"`
|
||||
PrintDocument bool `toml:"xpath_print_document"`
|
||||
AllowEmptySelection bool `toml:"xpath_allow_empty_selection"`
|
||||
Configs []Config `toml:"xpath"`
|
||||
DefaultMetricName string `toml:"-"`
|
||||
DefaultTags map[string]string `toml:"-"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
document dataDocument
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
MetricDefaultName string `toml:"-"`
|
||||
MetricQuery string `toml:"metric_name"`
|
||||
Selection string `toml:"metric_selection"`
|
||||
Timestamp string `toml:"timestamp"`
|
||||
TimestampFmt string `toml:"timestamp_format"`
|
||||
Tags map[string]string `toml:"tags"`
|
||||
Fields map[string]string `toml:"fields"`
|
||||
FieldsInt map[string]string `toml:"fields_int"`
|
||||
|
||||
FieldSelection string `toml:"field_selection"`
|
||||
FieldNameQuery string `toml:"field_name"`
|
||||
FieldValueQuery string `toml:"field_value"`
|
||||
FieldNameExpand bool `toml:"field_name_expansion"`
|
||||
|
||||
TagSelection string `toml:"tag_selection"`
|
||||
TagNameQuery string `toml:"tag_name"`
|
||||
TagValueQuery string `toml:"tag_value"`
|
||||
TagNameExpand bool `toml:"tag_name_expansion"`
|
||||
}
|
||||
// Config definition
|
||||
// This should be replaced by the actual definition once
|
||||
// the compatibitlity-code is removed.
|
||||
// Please check plugins/parsers/registry.go for now.
|
||||
type Config parsers.XPathConfig
|
||||
|
||||
func (p *Parser) Init() error {
|
||||
switch p.Format {
|
||||
|
|
@ -81,6 +69,11 @@ func (p *Parser) Init() error {
|
|||
return fmt.Errorf("unknown data-format %q for xpath parser", p.Format)
|
||||
}
|
||||
|
||||
// Make sure we do have a metric name
|
||||
if p.DefaultMetricName == "" {
|
||||
return errors.New("missing default metric name")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +122,6 @@ func (p *Parser) Parse(buf []byte) ([]telegraf.Metric, error) {
|
|||
}
|
||||
|
||||
func (p *Parser) ParseLine(line string) (telegraf.Metric, error) {
|
||||
|
||||
metrics, err := p.Parse([]byte(line))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -155,7 +147,7 @@ func (p *Parser) parseQuery(starttime time.Time, doc, selected dataNode, config
|
|||
|
||||
// Determine the metric name. If a query was specified, use the result of this query and the default metric name
|
||||
// otherwise.
|
||||
metricname = config.MetricDefaultName
|
||||
metricname = p.DefaultMetricName
|
||||
if len(config.MetricQuery) > 0 {
|
||||
v, err := p.executeQuery(doc, selected, config.MetricQuery)
|
||||
if err != nil {
|
||||
|
|
@ -512,3 +504,62 @@ func (p *Parser) debugEmptyQuery(operation string, root dataNode, initialquery s
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Register all variants
|
||||
parsers.Add("xml",
|
||||
func(defaultMetricName string) telegraf.Parser {
|
||||
return &Parser{
|
||||
Format: "xml",
|
||||
DefaultMetricName: defaultMetricName,
|
||||
}
|
||||
},
|
||||
)
|
||||
parsers.Add("xpath_json",
|
||||
func(defaultMetricName string) telegraf.Parser {
|
||||
return &Parser{
|
||||
Format: "xpath_json",
|
||||
DefaultMetricName: defaultMetricName,
|
||||
}
|
||||
},
|
||||
)
|
||||
parsers.Add("xpath_msgpack",
|
||||
func(defaultMetricName string) telegraf.Parser {
|
||||
return &Parser{
|
||||
Format: "xpath_msgpack",
|
||||
DefaultMetricName: defaultMetricName,
|
||||
}
|
||||
},
|
||||
)
|
||||
parsers.Add("xpath_protobuf",
|
||||
func(defaultMetricName string) telegraf.Parser {
|
||||
return &Parser{
|
||||
Format: "xpath_protobuf",
|
||||
DefaultMetricName: defaultMetricName,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// InitFromConfig is a compatibitlity function to construct the parser the old way
|
||||
func (p *Parser) InitFromConfig(config *parsers.Config) error {
|
||||
p.Format = config.DataFormat
|
||||
if p.Format == "xpath_protobuf" {
|
||||
p.ProtobufMessageDef = config.XPathProtobufFile
|
||||
p.ProtobufMessageType = config.XPathProtobufType
|
||||
}
|
||||
p.PrintDocument = config.XPathPrintDocument
|
||||
p.DefaultMetricName = config.MetricName
|
||||
p.DefaultTags = config.DefaultTags
|
||||
|
||||
// Convert the config formats which is a one-to-one copy
|
||||
if len(config.XPathConfig) > 0 {
|
||||
p.Configs = make([]Config, 0, len(config.XPathConfig))
|
||||
for _, cfg := range config.XPathConfig {
|
||||
config := Config(cfg)
|
||||
p.Configs = append(p.Configs, config)
|
||||
}
|
||||
}
|
||||
|
||||
return p.Init()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,7 +126,12 @@ func TestParseInvalidXML(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: tt.defaultTags, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "xml",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: tt.defaultTags,
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
_, err := parser.ParseLine(tt.input)
|
||||
|
|
@ -149,8 +154,7 @@ func TestInvalidTypeQueriesFail(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
FieldsInt: map[string]string{
|
||||
"a": "/Device_1/value_string",
|
||||
},
|
||||
|
|
@ -163,7 +167,12 @@ func TestInvalidTypeQueriesFail(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: tt.defaultTags, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "xml",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: tt.defaultTags,
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
_, err := parser.ParseLine(tt.input)
|
||||
|
|
@ -186,8 +195,7 @@ func TestInvalidTypeQueries(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"a": "number(/Device_1/value_string)",
|
||||
},
|
||||
|
|
@ -208,8 +216,7 @@ func TestInvalidTypeQueries(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"a": "boolean(/Device_1/value_string)",
|
||||
},
|
||||
|
|
@ -229,7 +236,12 @@ func TestInvalidTypeQueries(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: tt.defaultTags, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "test",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: tt.defaultTags,
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
actual, err := parser.ParseLine(tt.input)
|
||||
|
|
@ -253,8 +265,7 @@ func TestParseTimestamps(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
},
|
||||
},
|
||||
defaultTags: map[string]string{},
|
||||
|
|
@ -270,9 +281,8 @@ func TestParseTimestamps(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
TimestampFmt: "unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
TimestampFmt: "unix",
|
||||
},
|
||||
},
|
||||
defaultTags: map[string]string{},
|
||||
|
|
@ -288,9 +298,8 @@ func TestParseTimestamps(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix_ms",
|
||||
TimestampFmt: "unix_ms",
|
||||
Timestamp: "/Device_1/Timestamp_unix_ms",
|
||||
TimestampFmt: "unix_ms",
|
||||
},
|
||||
},
|
||||
defaultTags: map[string]string{},
|
||||
|
|
@ -306,9 +315,8 @@ func TestParseTimestamps(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix_us",
|
||||
TimestampFmt: "unix_us",
|
||||
Timestamp: "/Device_1/Timestamp_unix_us",
|
||||
TimestampFmt: "unix_us",
|
||||
},
|
||||
},
|
||||
defaultTags: map[string]string{},
|
||||
|
|
@ -324,9 +332,8 @@ func TestParseTimestamps(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix_ns",
|
||||
TimestampFmt: "unix_ns",
|
||||
Timestamp: "/Device_1/Timestamp_unix_ns",
|
||||
TimestampFmt: "unix_ns",
|
||||
},
|
||||
},
|
||||
defaultTags: map[string]string{},
|
||||
|
|
@ -342,9 +349,8 @@ func TestParseTimestamps(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_iso",
|
||||
TimestampFmt: "2006-01-02T15:04:05Z",
|
||||
Timestamp: "/Device_1/Timestamp_iso",
|
||||
TimestampFmt: "2006-01-02T15:04:05Z",
|
||||
},
|
||||
},
|
||||
defaultTags: map[string]string{},
|
||||
|
|
@ -359,7 +365,12 @@ func TestParseTimestamps(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: tt.defaultTags, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "test",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: tt.defaultTags,
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
actual, err := parser.ParseLine(tt.input)
|
||||
|
|
@ -383,8 +394,7 @@ func TestParseSingleValues(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"a": "/Device_1/value_int",
|
||||
"b": "/Device_1/value_float",
|
||||
|
|
@ -411,8 +421,7 @@ func TestParseSingleValues(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"a": "number(Device_1/value_int)",
|
||||
"b": "number(/Device_1/value_float)",
|
||||
|
|
@ -439,8 +448,7 @@ func TestParseSingleValues(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"b": "number(/Device_1/value_float)",
|
||||
"c": "boolean(/Device_1/value_bool)",
|
||||
|
|
@ -469,8 +477,7 @@ func TestParseSingleValues(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"x": "substring-before(/Device_1/value_position, ';')",
|
||||
"y": "substring-after(/Device_1/value_position, ';')",
|
||||
|
|
@ -493,8 +500,7 @@ func TestParseSingleValues(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"x": "number(substring-before(/Device_1/value_position, ';'))",
|
||||
"y": "number(substring-after(/Device_1/value_position, ';'))",
|
||||
|
|
@ -517,8 +523,7 @@ func TestParseSingleValues(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
FieldsInt: map[string]string{
|
||||
"x": "substring-before(/Device_1/value_position, ';')",
|
||||
"y": "substring-after(/Device_1/value_position, ';')",
|
||||
|
|
@ -541,8 +546,7 @@ func TestParseSingleValues(t *testing.T) {
|
|||
input: singleMetricValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Tags: map[string]string{
|
||||
"state": "/Device_1/State",
|
||||
"name": "substring-after(/Device_1/Name, ' ')",
|
||||
|
|
@ -564,7 +568,12 @@ func TestParseSingleValues(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: tt.defaultTags, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "test",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: tt.defaultTags,
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
actual, err := parser.ParseLine(tt.input)
|
||||
|
|
@ -588,8 +597,7 @@ func TestParseSingleAttributes(t *testing.T) {
|
|||
input: singleMetricAttributesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
},
|
||||
},
|
||||
defaultTags: map[string]string{},
|
||||
|
|
@ -605,9 +613,8 @@ func TestParseSingleAttributes(t *testing.T) {
|
|||
input: singleMetricAttributesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_iso/@value",
|
||||
TimestampFmt: "2006-01-02T15:04:05Z",
|
||||
Timestamp: "/Device_1/Timestamp_iso/@value",
|
||||
TimestampFmt: "2006-01-02T15:04:05Z",
|
||||
},
|
||||
},
|
||||
defaultTags: map[string]string{},
|
||||
|
|
@ -623,8 +630,7 @@ func TestParseSingleAttributes(t *testing.T) {
|
|||
input: singleMetricAttributesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Fields: map[string]string{
|
||||
"a": "/Device_1/attr_int/@_",
|
||||
"b": "/Device_1/attr_float/@_",
|
||||
|
|
@ -651,8 +657,7 @@ func TestParseSingleAttributes(t *testing.T) {
|
|||
input: singleMetricAttributesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Fields: map[string]string{
|
||||
"a": "number(/Device_1/attr_int/@_)",
|
||||
"b": "number(/Device_1/attr_float/@_)",
|
||||
|
|
@ -679,8 +684,7 @@ func TestParseSingleAttributes(t *testing.T) {
|
|||
input: singleMetricAttributesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Fields: map[string]string{
|
||||
"b": "number(/Device_1/attr_float/@_)",
|
||||
"c": "boolean(/Device_1/attr_bool/@_)",
|
||||
|
|
@ -709,8 +713,7 @@ func TestParseSingleAttributes(t *testing.T) {
|
|||
input: singleMetricAttributesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Fields: map[string]string{
|
||||
"name": "substring-after(/Device_1/Name/@value, ' ')",
|
||||
},
|
||||
|
|
@ -731,8 +734,7 @@ func TestParseSingleAttributes(t *testing.T) {
|
|||
input: singleMetricAttributesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Tags: map[string]string{
|
||||
"state": "/Device_1/State/@_",
|
||||
"name": "substring-after(/Device_1/Name/@value, ' ')",
|
||||
|
|
@ -755,8 +757,7 @@ func TestParseSingleAttributes(t *testing.T) {
|
|||
input: singleMetricAttributesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Timestamp: "/Device_1/Timestamp_unix/@value",
|
||||
Fields: map[string]string{
|
||||
"a": "/Device_1/attr_bool_numeric/@_ = 1",
|
||||
},
|
||||
|
|
@ -776,7 +777,12 @@ func TestParseSingleAttributes(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: tt.defaultTags, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "test",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: tt.defaultTags,
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
actual, err := parser.ParseLine(tt.input)
|
||||
|
|
@ -800,8 +806,7 @@ func TestParseMultiValues(t *testing.T) {
|
|||
input: singleMetricMultiValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Timestamp/@value",
|
||||
Timestamp: "/Timestamp/@value",
|
||||
Fields: map[string]string{
|
||||
"a": "number(/Device/Value[1])",
|
||||
"b": "number(/Device/Value[2])",
|
||||
|
|
@ -832,8 +837,7 @@ func TestParseMultiValues(t *testing.T) {
|
|||
input: singleMetricMultiValuesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Timestamp: "/Timestamp/@value",
|
||||
Timestamp: "/Timestamp/@value",
|
||||
FieldsInt: map[string]string{
|
||||
"a": "/Device/Value[1]",
|
||||
"b": "/Device/Value[2]",
|
||||
|
|
@ -863,7 +867,12 @@ func TestParseMultiValues(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: tt.defaultTags, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "test",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: tt.defaultTags,
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
actual, err := parser.ParseLine(tt.input)
|
||||
|
|
@ -887,9 +896,8 @@ func TestParseMultiNodes(t *testing.T) {
|
|||
input: multipleNodesXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
Selection: "/Device",
|
||||
Timestamp: "/Timestamp/@value",
|
||||
Selection: "/Device",
|
||||
Timestamp: "/Timestamp/@value",
|
||||
Fields: map[string]string{
|
||||
"value": "number(Value)",
|
||||
"active": "Active = 1",
|
||||
|
|
@ -976,7 +984,12 @@ func TestParseMultiNodes(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: tt.defaultTags, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "test",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: tt.defaultTags,
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
actual, err := parser.Parse([]byte(tt.input))
|
||||
|
|
@ -1000,9 +1013,8 @@ func TestParseMetricQuery(t *testing.T) {
|
|||
input: metricNameQueryXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
MetricQuery: "name(/Device_1/Metric/@*[1])",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
MetricQuery: "name(/Device_1/Metric/@*[1])",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"value": "/Device_1/Metric/@*[1]",
|
||||
},
|
||||
|
|
@ -1023,9 +1035,8 @@ func TestParseMetricQuery(t *testing.T) {
|
|||
input: metricNameQueryXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
MetricQuery: "'the_metric'",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
MetricQuery: "'the_metric'",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"value": "/Device_1/Metric/@*[1]",
|
||||
},
|
||||
|
|
@ -1045,7 +1056,12 @@ func TestParseMetricQuery(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: tt.defaultTags, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "test",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: tt.defaultTags,
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
actual, err := parser.ParseLine(tt.input)
|
||||
|
|
@ -1068,9 +1084,8 @@ func TestParseErrors(t *testing.T) {
|
|||
input: metricNameQueryXML,
|
||||
configs: []Config{
|
||||
{
|
||||
MetricDefaultName: "test",
|
||||
MetricQuery: "arbitrary",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
MetricQuery: "arbitrary",
|
||||
Timestamp: "/Device_1/Timestamp_unix",
|
||||
Fields: map[string]string{
|
||||
"value": "/Device_1/Metric/@*[1]",
|
||||
},
|
||||
|
|
@ -1082,7 +1097,12 @@ func TestParseErrors(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: map[string]string{}, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "test",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: map[string]string{},
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
_, err := parser.ParseLine(tt.input)
|
||||
|
|
@ -1150,12 +1170,17 @@ func TestEmptySelection(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, DefaultTags: map[string]string{}, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "test",
|
||||
Configs: tt.configs,
|
||||
DefaultTags: map[string]string{},
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
_, err := parser.Parse([]byte(tt.input))
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "cannot parse with empty selection node", err.Error())
|
||||
require.Equal(t, err.Error(), "cannot parse with empty selection node")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1218,7 +1243,13 @@ func TestEmptySelectionAllowed(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := &Parser{Configs: tt.configs, AllowEmptySelection: true, DefaultTags: map[string]string{}, Log: testutil.Logger{Name: "parsers.xml"}}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "xml",
|
||||
Configs: tt.configs,
|
||||
AllowEmptySelection: true,
|
||||
DefaultTags: map[string]string{},
|
||||
Log: testutil.Logger{Name: "parsers.xml"},
|
||||
}
|
||||
require.NoError(t, parser.Init())
|
||||
|
||||
_, err := parser.Parse([]byte(tt.input))
|
||||
|
|
@ -1277,7 +1308,6 @@ func TestTestCases(t *testing.T) {
|
|||
filename := filepath.FromSlash(tt.filename)
|
||||
cfg, header, err := loadTestConfiguration(filename)
|
||||
require.NoError(t, err)
|
||||
cfg.MetricDefaultName = "xml"
|
||||
|
||||
// Load the xml-content
|
||||
input, err := testutil.ParseRawLinesFrom(header, "File:")
|
||||
|
|
@ -1315,7 +1345,12 @@ func TestTestCases(t *testing.T) {
|
|||
expectedErrors, _ := testutil.ParseRawLinesFrom(header, "Expected Error:")
|
||||
|
||||
// Setup the parser and run it.
|
||||
metricName := "xml"
|
||||
if fileformat != "" {
|
||||
metricName = fileformat
|
||||
}
|
||||
parser := &Parser{
|
||||
DefaultMetricName: metricName,
|
||||
Format: fileformat,
|
||||
ProtobufMessageDef: pbmsgdef,
|
||||
ProtobufMessageType: pbmsgtype,
|
||||
|
|
@ -1340,6 +1375,7 @@ func TestTestCases(t *testing.T) {
|
|||
func TestProtobufImporting(t *testing.T) {
|
||||
// Setup the parser and run it.
|
||||
parser := &Parser{
|
||||
DefaultMetricName: "xpath_protobuf",
|
||||
Format: "xpath_protobuf",
|
||||
ProtobufMessageDef: "person.proto",
|
||||
ProtobufMessageType: "importtest.Person",
|
||||
|
|
|
|||
Loading…
Reference in New Issue