Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
214
plugins/parsers/xpath/protocolbuffer_document.go
Normal file
214
plugins/parsers/xpath/protocolbuffer_document.go
Normal file
|
@ -0,0 +1,214 @@
|
|||
package xpath
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
path "github.com/antchfx/xpath"
|
||||
"github.com/bufbuild/protocompile"
|
||||
"github.com/srebhan/protobufquery"
|
||||
"google.golang.org/protobuf/encoding/protowire"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
"google.golang.org/protobuf/types/dynamicpb"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
)
|
||||
|
||||
type protobufDocument struct {
|
||||
MessageFiles []string
|
||||
MessageType string
|
||||
ImportPaths []string
|
||||
SkipBytes int64
|
||||
Log telegraf.Logger
|
||||
|
||||
msg *dynamicpb.Message
|
||||
unmarshaller proto.UnmarshalOptions
|
||||
}
|
||||
|
||||
func (d *protobufDocument) Init() error {
|
||||
// Check the message definition and type
|
||||
if len(d.MessageFiles) == 0 {
|
||||
return errors.New("protocol-buffer files not set")
|
||||
}
|
||||
if d.MessageType == "" {
|
||||
return errors.New("protocol-buffer message-type not set")
|
||||
}
|
||||
|
||||
// Load the file descriptors from the given protocol-buffer definition
|
||||
ctx := context.Background()
|
||||
resolver := &protocompile.SourceResolver{ImportPaths: d.ImportPaths}
|
||||
compiler := &protocompile.Compiler{
|
||||
Resolver: protocompile.WithStandardImports(resolver),
|
||||
}
|
||||
files, err := compiler.Compile(ctx, d.MessageFiles...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing protocol-buffer definition failed: %w", err)
|
||||
}
|
||||
if len(files) < 1 {
|
||||
return errors.New("files do not contain a file descriptor")
|
||||
}
|
||||
|
||||
// Register all definitions in the file in the global registry
|
||||
var registry protoregistry.Files
|
||||
for _, f := range files {
|
||||
if err := registry.RegisterFile(f); err != nil {
|
||||
return fmt.Errorf("adding file %q to registry failed: %w", f.Path(), err)
|
||||
}
|
||||
}
|
||||
|
||||
d.unmarshaller = proto.UnmarshalOptions{
|
||||
RecursionLimit: protowire.DefaultRecursionLimit,
|
||||
Resolver: dynamicpb.NewTypes(®istry),
|
||||
}
|
||||
|
||||
// Lookup given type in the loaded file descriptors
|
||||
msgFullName := protoreflect.FullName(d.MessageType)
|
||||
descriptor, err := registry.FindDescriptorByName(msgFullName)
|
||||
if err != nil {
|
||||
d.Log.Infof("Could not find %q... Known messages:", msgFullName)
|
||||
|
||||
var known []string
|
||||
registry.RangeFiles(func(fd protoreflect.FileDescriptor) bool {
|
||||
name := strings.TrimSpace(string(fd.FullName()))
|
||||
if name != "" {
|
||||
known = append(known, name)
|
||||
}
|
||||
return true
|
||||
})
|
||||
sort.Strings(known)
|
||||
for _, name := range known {
|
||||
d.Log.Infof(" %s", name)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Get a prototypical message for later use
|
||||
msgDesc, ok := descriptor.(protoreflect.MessageDescriptor)
|
||||
if !ok {
|
||||
return fmt.Errorf("%q is not a message descriptor (%T)", msgFullName, descriptor)
|
||||
}
|
||||
|
||||
d.msg = dynamicpb.NewMessage(msgDesc)
|
||||
if d.msg == nil {
|
||||
return fmt.Errorf("creating message template for %q failed", msgDesc.FullName())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *protobufDocument) Parse(buf []byte) (dataNode, error) {
|
||||
msg := d.msg.New()
|
||||
|
||||
// Unmarshal the received buffer
|
||||
if err := d.unmarshaller.Unmarshal(buf[d.SkipBytes:], msg.Interface()); err != nil {
|
||||
hexbuf := hex.EncodeToString(buf)
|
||||
d.Log.Debugf("raw data (hex): %q (skip %d bytes)", hexbuf, d.SkipBytes)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return protobufquery.Parse(msg)
|
||||
}
|
||||
|
||||
func (*protobufDocument) QueryAll(node dataNode, expr string) ([]dataNode, error) {
|
||||
// If this panics it's a programming error as we changed the document type while processing
|
||||
native, err := protobufquery.QueryAll(node.(*protobufquery.Node), expr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nodes := make([]dataNode, 0, len(native))
|
||||
for _, n := range native {
|
||||
nodes = append(nodes, n)
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (*protobufDocument) CreateXPathNavigator(node dataNode) path.NodeNavigator {
|
||||
// If this panics it's a programming error as we changed the document type while processing
|
||||
return protobufquery.CreateXPathNavigator(node.(*protobufquery.Node))
|
||||
}
|
||||
|
||||
func (d *protobufDocument) GetNodePath(node, relativeTo dataNode, sep string) string {
|
||||
names := make([]string, 0)
|
||||
|
||||
// If these panic it's a programming error as we changed the document type while processing
|
||||
nativeNode := node.(*protobufquery.Node)
|
||||
nativeRelativeTo := relativeTo.(*protobufquery.Node)
|
||||
|
||||
// Climb up the tree and collect the node names
|
||||
n := nativeNode.Parent
|
||||
for n != nil && n != nativeRelativeTo {
|
||||
kind := reflect.Invalid
|
||||
if n.Parent != nil && n.Parent.Value() != nil {
|
||||
kind = reflect.TypeOf(n.Parent.Value()).Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
// Determine the index for array elements
|
||||
names = append(names, d.index(n))
|
||||
default:
|
||||
// Use the name if not an array
|
||||
names = append(names, n.Name)
|
||||
}
|
||||
n = n.Parent
|
||||
}
|
||||
|
||||
if len(names) < 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Construct the nodes
|
||||
nodepath := ""
|
||||
for _, name := range names {
|
||||
nodepath = name + sep + nodepath
|
||||
}
|
||||
|
||||
return nodepath[:len(nodepath)-1]
|
||||
}
|
||||
|
||||
func (d *protobufDocument) GetNodeName(node dataNode, sep string, withParent bool) string {
|
||||
// If this panics it's a programming error as we changed the document type while processing
|
||||
nativeNode := node.(*protobufquery.Node)
|
||||
|
||||
name := nativeNode.Name
|
||||
|
||||
// Check if the node is part of an array. If so, determine the index and
|
||||
// concatenate the parent name and the index.
|
||||
kind := reflect.Invalid
|
||||
if nativeNode.Parent != nil && nativeNode.Parent.Value() != nil {
|
||||
kind = reflect.TypeOf(nativeNode.Parent.Value()).Kind()
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
if name == "" && nativeNode.Parent != nil && withParent {
|
||||
name = nativeNode.Parent.Name + sep
|
||||
}
|
||||
return name + d.index(nativeNode)
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func (*protobufDocument) OutputXML(node dataNode) string {
|
||||
native := node.(*protobufquery.Node)
|
||||
return native.OutputXML()
|
||||
}
|
||||
|
||||
func (*protobufDocument) index(node *protobufquery.Node) string {
|
||||
idx := 0
|
||||
|
||||
for n := node; n.PrevSibling != nil; n = n.PrevSibling {
|
||||
idx++
|
||||
}
|
||||
|
||||
return strconv.Itoa(idx)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue