diff --git a/plugins/inputs/gnmi/README.md b/plugins/inputs/gnmi/README.md index bf6f214a44137..174c4733f3ecd 100644 --- a/plugins/inputs/gnmi/README.md +++ b/plugins/inputs/gnmi/README.md @@ -88,6 +88,9 @@ details on how to use them. ## subscription -- use the subscription path # path_guessing_strategy = "none" + ## Prefix tags from path keys with the path element + # prefix_tag_key_with_path = false + ## enable client-side TLS and define CA to authenticate the device # enable_tls = false # tls_ca = "/etc/telegraf/ca.pem" diff --git a/plugins/inputs/gnmi/gnmi.go b/plugins/inputs/gnmi/gnmi.go index a45d3987df5c7..8945c9ce5c5b2 100644 --- a/plugins/inputs/gnmi/gnmi.go +++ b/plugins/inputs/gnmi/gnmi.go @@ -38,29 +38,30 @@ var supportedExtensions = []string{"juniper_header"} // gNMI plugin instance type GNMI struct { - Addresses []string `toml:"addresses"` - Subscriptions []Subscription `toml:"subscription"` - TagSubscriptions []TagSubscription `toml:"tag_subscription"` - Aliases map[string]string `toml:"aliases"` - Encoding string `toml:"encoding"` - Origin string `toml:"origin"` - Prefix string `toml:"prefix"` - Target string `toml:"target"` - UpdatesOnly bool `toml:"updates_only"` - VendorSpecific []string `toml:"vendor_specific"` - Username config.Secret `toml:"username"` - Password config.Secret `toml:"password"` - Redial config.Duration `toml:"redial"` - MaxMsgSize config.Size `toml:"max_msg_size"` - Trace bool `toml:"dump_responses"` - CanonicalFieldNames bool `toml:"canonical_field_names"` - TrimFieldNames bool `toml:"trim_field_names"` - GuessPathTag bool `toml:"guess_path_tag" deprecated:"1.30.0;use 'path_guessing_strategy' instead"` - GuessPathStrategy string `toml:"path_guessing_strategy"` - EnableTLS bool `toml:"enable_tls" deprecated:"1.27.0;use 'tls_enable' instead"` - KeepaliveTime config.Duration `toml:"keepalive_time"` - KeepaliveTimeout config.Duration `toml:"keepalive_timeout"` - Log telegraf.Logger `toml:"-"` + Addresses []string `toml:"addresses"` + Subscriptions []Subscription `toml:"subscription"` + TagSubscriptions []TagSubscription `toml:"tag_subscription"` + Aliases map[string]string `toml:"aliases"` + Encoding string `toml:"encoding"` + Origin string `toml:"origin"` + Prefix string `toml:"prefix"` + Target string `toml:"target"` + UpdatesOnly bool `toml:"updates_only"` + VendorSpecific []string `toml:"vendor_specific"` + Username config.Secret `toml:"username"` + Password config.Secret `toml:"password"` + Redial config.Duration `toml:"redial"` + MaxMsgSize config.Size `toml:"max_msg_size"` + Trace bool `toml:"dump_responses"` + CanonicalFieldNames bool `toml:"canonical_field_names"` + TrimFieldNames bool `toml:"trim_field_names"` + PrefixTagKeyWithPath bool `toml:"prefix_tag_key_with_path"` + GuessPathTag bool `toml:"guess_path_tag" deprecated:"1.30.0;use 'path_guessing_strategy' instead"` + GuessPathStrategy string `toml:"path_guessing_strategy"` + EnableTLS bool `toml:"enable_tls" deprecated:"1.27.0;use 'tls_enable' instead"` + KeepaliveTime config.Duration `toml:"keepalive_time"` + KeepaliveTimeout config.Duration `toml:"keepalive_timeout"` + Log telegraf.Logger `toml:"-"` internaltls.ClientConfig // Internal state @@ -249,6 +250,7 @@ func (c *GNMI) Start(acc telegraf.Accumulator) error { trace: c.Trace, canonicalFieldNames: c.CanonicalFieldNames, trimSlash: c.TrimFieldNames, + tagPathPrefix: c.PrefixTagKeyWithPath, guessPathStrategy: c.GuessPathStrategy, log: c.Log, ClientParameters: keepalive.ClientParameters{ diff --git a/plugins/inputs/gnmi/handler.go b/plugins/inputs/gnmi/handler.go index 988f76136739d..ac8da7e47bea8 100644 --- a/plugins/inputs/gnmi/handler.go +++ b/plugins/inputs/gnmi/handler.go @@ -41,6 +41,7 @@ type handler struct { trace bool canonicalFieldNames bool trimSlash bool + tagPathPrefix bool guessPathStrategy string log telegraf.Logger keepalive.ClientParameters @@ -180,7 +181,7 @@ func (h *handler) handleSubscribeResponseUpdate(acc telegraf.Accumulator, respon for key, val := range headerTags { tags[key] = val } - for key, val := range fullPath.Tags() { + for key, val := range fullPath.Tags(h.tagPathPrefix) { tags[key] = val } @@ -213,7 +214,7 @@ func (h *handler) handleSubscribeResponseUpdate(acc telegraf.Accumulator, respon // Parse individual update message and create measurements for _, field := range valueFields { // Prepare tags from prefix - fieldTags := field.path.Tags() + fieldTags := field.path.Tags(h.tagPathPrefix) tags := make(map[string]string, len(headerTags)+len(fieldTags)) for key, val := range headerTags { tags[key] = val diff --git a/plugins/inputs/gnmi/path.go b/plugins/inputs/gnmi/path.go index cc63814cd5085..027a328a92889 100644 --- a/plugins/inputs/gnmi/path.go +++ b/plugins/inputs/gnmi/path.go @@ -279,11 +279,15 @@ func (pi *pathInfo) String() string { return out } -func (pi *pathInfo) Tags() map[string]string { +func (pi *pathInfo) Tags(pathPrefix bool) map[string]string { tags := make(map[string]string, len(pi.keyValues)) for _, s := range pi.keyValues { + var prefix string + if pathPrefix && s.name != "" { + prefix = s.name + "_" + } for k, v := range s.kv { - key := strings.ReplaceAll(k, "-", "_") + key := strings.ReplaceAll(prefix+k, "-", "_") // Use short-form of key if possible if _, exists := tags[key]; !exists { diff --git a/plugins/inputs/gnmi/sample.conf b/plugins/inputs/gnmi/sample.conf index 4d473139d24d3..30795898dfc27 100644 --- a/plugins/inputs/gnmi/sample.conf +++ b/plugins/inputs/gnmi/sample.conf @@ -41,6 +41,9 @@ ## subscription -- use the subscription path # path_guessing_strategy = "none" + ## Prefix tags from path keys with the path element + # prefix_tag_key_with_path = false + ## enable client-side TLS and define CA to authenticate the device # enable_tls = false # tls_ca = "/etc/telegraf/ca.pem" diff --git a/plugins/inputs/gnmi/testcases/issue_12831/expected.out b/plugins/inputs/gnmi/testcases/issue_12831/expected.out new file mode 100644 index 0000000000000..1f01a7971e0a6 --- /dev/null +++ b/plugins/inputs/gnmi/testcases/issue_12831/expected.out @@ -0,0 +1,7 @@ +optical_channel,component_name=CM-1,source=127.0.0.1 cpu/openconfig_platform_cpu:utilization/state/avg=13u,cpu/openconfig_platform_cpu:utilization/state/instant=16u,cpu/openconfig_platform_cpu:utilization/state/interval=3600000000000u,cpu/openconfig_platform_cpu:utilization/state/max=17u,cpu/openconfig_platform_cpu:utilization/state/min=8u,name="CM-1",state/memory/available=5041100000u,state/memory/utilized=3099808000u,state/temperature/avg=20.5,state/temperature/instant=20.399999618530273,state/temperature/interval=3600000000000u,state/temperature/max=20.700000762939453,state/temperature/min=20.399999618530273 1714598222912553000 +optical_channel,component_name=AP-1,source=127.0.0.1 name="AP-1",state/temperature/avg=34.099998474121094,state/temperature/instant=34.29999923706055,state/temperature/interval=3600000000000u,state/temperature/max=34.599998474121094,state/temperature/min=33.599998474121094 1714598222912553000 +optical_channel,component_name=LM-1,source=127.0.0.1 name="LM-1",state/temperature/avg=40.79999923706055,state/temperature/instant=40.599998474121094,state/temperature/interval=3600000000000u,state/temperature/max=41.400001525878906,state/temperature/min=40.400001525878906 1714598222912553000 +optical_channel,component_name=LM-1,source=127.0.0.1,subcomponent_name=PORT-1-1 subcomponents/subcomponent/config/name="PORT-1-1",subcomponents/subcomponent/name="PORT-1-1",subcomponents/subcomponent/state/name="PORT-1-1" 1714598222912553000 +optical_channel,component_name=LM-1,source=127.0.0.1,subcomponent_name=PORT-1-2 subcomponents/subcomponent/config/name="PORT-1-2",subcomponents/subcomponent/name="PORT-1-2",subcomponents/subcomponent/state/name="PORT-1-2" 1714598222912553000 +optical_channel,component_name=LM-1,source=127.0.0.1,subcomponent_name=PORT-1-4 subcomponents/subcomponent/config/name="PORT-1-4",subcomponents/subcomponent/name="PORT-1-4",subcomponents/subcomponent/state/name="PORT-1-4" 1714598222912553000 +optical_channel,component_name=LM-1,source=127.0.0.1,subcomponent_name=PORT-1-12 subcomponents/subcomponent/config/name="PORT-1-12",subcomponents/subcomponent/name="PORT-1-12",subcomponents/subcomponent/state/name="PORT-1-12" 1714598222912553000 diff --git a/plugins/inputs/gnmi/testcases/issue_12831/responses.json b/plugins/inputs/gnmi/testcases/issue_12831/responses.json new file mode 100644 index 0000000000000..d93ebc879aa05 --- /dev/null +++ b/plugins/inputs/gnmi/testcases/issue_12831/responses.json @@ -0,0 +1,1101 @@ +[ + { + "update": { + "timestamp": "1714598222912553000", + "update": [ + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "CM-1" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "instant" + } + ] + }, + "val": { + "decimalVal": { + "digits": 204, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "avg" + } + ] + }, + "val": { + "decimalVal": { + "digits": 205, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "min" + } + ] + }, + "val": { + "decimalVal": { + "digits": 204, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "max" + } + ] + }, + "val": { + "decimalVal": { + "digits": 207, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "interval" + } + ] + }, + "val": { + "uintVal": "3600000000000" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "state" + }, + { + "name": "memory" + }, + { + "name": "available" + } + ] + }, + "val": { + "uintVal": "5041100000" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "state" + }, + { + "name": "memory" + }, + { + "name": "utilized" + } + ] + }, + "val": { + "uintVal": "3099808000" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "cpu" + }, + { + "name": "openconfig-platform-cpu:utilization" + }, + { + "name": "state" + }, + { + "name": "instant" + } + ] + }, + "val": { + "uintVal": "16" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "cpu" + }, + { + "name": "openconfig-platform-cpu:utilization" + }, + { + "name": "state" + }, + { + "name": "avg" + } + ] + }, + "val": { + "uintVal": "13" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "cpu" + }, + { + "name": "openconfig-platform-cpu:utilization" + }, + { + "name": "state" + }, + { + "name": "min" + } + ] + }, + "val": { + "uintVal": "8" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "cpu" + }, + { + "name": "openconfig-platform-cpu:utilization" + }, + { + "name": "state" + }, + { + "name": "max" + } + ] + }, + "val": { + "uintVal": "17" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "CM-1" + } + }, + { + "name": "cpu" + }, + { + "name": "openconfig-platform-cpu:utilization" + }, + { + "name": "state" + }, + { + "name": "interval" + } + ] + }, + "val": { + "uintVal": "3600000000000" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "AP-1" + } + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "AP-1" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "AP-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "instant" + } + ] + }, + "val": { + "decimalVal": { + "digits": 343, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "AP-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "avg" + } + ] + }, + "val": { + "decimalVal": { + "digits": 341, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "AP-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "min" + } + ] + }, + "val": { + "decimalVal": { + "digits": 336, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "AP-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "max" + } + ] + }, + "val": { + "decimalVal": { + "digits": 346, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "AP-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "interval" + } + ] + }, + "val": { + "uintVal": "3600000000000" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "LM-1" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "instant" + } + ] + }, + "val": { + "decimalVal": { + "digits": 406, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "avg" + } + ] + }, + "val": { + "decimalVal": { + "digits": 408, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "min" + } + ] + }, + "val": { + "decimalVal": { + "digits": 404, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "max" + } + ] + }, + "val": { + "decimalVal": { + "digits": 414, + "precision": 1 + } + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "state" + }, + { + "name": "temperature" + }, + { + "name": "interval" + } + ] + }, + "val": { + "uintVal": "3600000000000" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-1" + } + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-1" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-1" + } + }, + { + "name": "config" + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-1" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-1" + } + }, + { + "name": "state" + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-1" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-2" + } + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-2" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-2" + } + }, + { + "name": "config" + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-2" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-2" + } + }, + { + "name": "state" + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-2" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-4" + } + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-4" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-4" + } + }, + { + "name": "config" + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-4" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-4" + } + }, + { + "name": "state" + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-4" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-12" + } + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-12" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-12" + } + }, + { + "name": "config" + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-12" + } + }, + { + "path": { + "elem": [ + { + "name": "openconfig-platform:components" + }, + { + "name": "component", + "key": { + "name": "LM-1" + } + }, + { + "name": "subcomponents" + }, + { + "name": "subcomponent", + "key": { + "name": "PORT-1-12" + } + }, + { + "name": "state" + }, + { + "name": "name" + } + ] + }, + "val": { + "stringVal": "PORT-1-12" + } + } + ] + } + } +] \ No newline at end of file diff --git a/plugins/inputs/gnmi/testcases/issue_12831/telegraf.conf b/plugins/inputs/gnmi/testcases/issue_12831/telegraf.conf new file mode 100644 index 0000000000000..06bd4ff81766b --- /dev/null +++ b/plugins/inputs/gnmi/testcases/issue_12831/telegraf.conf @@ -0,0 +1,10 @@ +[[inputs.gnmi]] + addresses = ["dummy"] + prefix_tag_key_with_path = true + + [[inputs.gnmi.subscription]] + name = "optical_channel" + path = "/components/component[name=*]" + subscription_mode = "sample" + origin = "openconfig-platform" + sample_interval = "10s" \ No newline at end of file