The following article presents a deep dive into the contents of the default Telegraf TOML configuration. Drilling down into this is not necessary to use the default Telemetry Collector configuration “out of the box” (just use the above described Telemetry Collector configuration), but is useful if you want to change the Telemetry Collector to ingest telemetry that is not available in the "out of the box" configuration.
Deep Dive Into the Default Telegraf TOML
Unencoded Telegraf TOML Configuration For Default Cisco Telemetry Objects.
Pay attention to the inputs.cisco_telemetry_mdt
plugin at the top of the configuration, if you are replacing the transformation plugins with your own mappings, you will need to ensure that you keep this input plugin. This plugin is what allows telemetry from the routers to be ingested.
[[inputs.cisco_telemetry_mdt]]
## Telemetry transport can be "tcp" or "grpc". TLS is only supported when
## using the grpc transport.
transport = "tcp"
## Address and port to host telemetry listener
service_address = ":57000"
## Grpc Maximum Message Size, default is 4MB, increase the size.
max_msg_size = 104857600 # 100 MB in bytes
## Enable TLS; grpc transport only.
# tls_cert = "/etc/telegraf/cert.pem"
# tls_key = "/etc/telegraf/key.pem"
## Enable TLS client authentication and define allowed CA certificates; grpc
## transport only.
# tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"]
## Define (for certain nested telemetry measurements with embedded tags) which fields are tags
embedded_tags = [
"Cisco-IOS-XR-man-ipsla-oper:ipsla/operation-data/operations/operation/statistics/latest/target/specific-stats/op-type",
"Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/input/service-policy-names/service-policy-instance/statistics/class-stats/class-name",
"Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/input/service-policy-names/service-policy-instance/statistics/class-stats/child-policy/policy-name",
"Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/input/service-policy-names/service-policy-instance/statistics/class-stats/child-policy/class-stats/class-name",
"Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/output/service-policy-names/service-policy-instance/statistics/class-stats/class-name",
"Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/output/service-policy-names/service-policy-instance/statistics/class-stats/child-policy/policy-name",
"Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/output/service-policy-names/service-policy-instance/statistics/class-stats/child-policy/class-stats/class-name",
]
## Define aliases to map telemetry encoding paths to simple measurement names
[inputs.cisco_telemetry_mdt.aliases]
if_stats = "Cisco-IOS-XR-pfi-im-cmd-oper:interfaces/interface-xr/interface"
policy_out_stats = "Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/output/service-policy-names/service-policy-instance/statistics"
policy_in_stats = "Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/input/service-policy-names/service-policy-instance/statistics"
sla_stats = "Cisco-IOS-XR-infra-sla-oper:sla/protocols/Cisco-IOS-XR-ethernet-cfm-oper:ethernet/statistics-historicals/statistics-historical"
cpu_util = "Cisco-IOS-XR-wdsysmon-fd-oper:system-monitoring/cpu-utilization"
node_summary = "Cisco-IOS-XR-nto-misc-oper:memory-summary/nodes/node/summary"
channel_stats = "Cisco-IOS-XR-telemetry-model-driven-oper:telemetry-model-driven/channel-statistics"
twamp_lite = "Cisco-IOS-XR-perf-meas-oper:performance-measurement/nodes/node/interfaces/interface-details/interface-detail"
ipsla = "Cisco-IOS-XR-man-ipsla-oper:ipsla/operation-data/operations/operation/statistics/latest/target"
[[processors.template]]
order = 1
namepass = ["if_stats*"]
tag = "sessionName"
template = '{{ .Tag "source" }}_{{ .Tag "interface_name" }}'
[[processors.template]]
order = 2
namepass = ["if_stats*"]
tag = "sessionId"
template = '{{ .Tag "source" }}_{{ .Tag "interface_name" }}'
[[processors.template]]
order = 3
namepass = ["if_stats*"]
tag = "objectType"
template = 'cisco_mdt_interface'
[[processors.template]]
order = 3
namepass = ["if_stats*"]
tag = "direction"
template = "0"
[[processors.starlark]]
order = 4
namepass = ["if_stats*"]
source = '''
def apply(metric):
if metric.fields.get("state") == "im-state-up":
metric.fields["availability_percent"] = 100
else:
metric.fields["availability_percent"] = 0
if metric.fields.get("interface_statistics/stats_type") == "basic":
metric.fields["interface_statistics/basic_interface_stats/bytes_received_rate"] = metric.fields.get("interface_statistics/basic_interface_stats/bytes_received")
metric.fields["interface_statistics/basic_interface_stats/bytes_received_delta"] = metric.fields.get("interface_statistics/basic_interface_stats/bytes_received")
metric.fields["interface_statistics/basic_interface_stats/bytes_sent_rate"] = metric.fields.get("interface_statistics/basic_interface_stats/bytes_sent")
metric.fields["interface_statistics/basic_interface_stats/bytes_sent_delta"] = metric.fields.get("interface_statistics/basic_interface_stats/bytes_sent")
elif metric.fields.get("interface_statistics/stats_type") == "full":
metric.fields["interface_statistics/full_interface_stats/bytes_received_rate"] = metric.fields.get("interface_statistics/full_interface_stats/bytes_received")
metric.fields["interface_statistics/full_interface_stats/bytes_received_delta"] = metric.fields.get("interface_statistics/full_interface_stats/bytes_received")
metric.fields["interface_statistics/full_interface_stats/bytes_sent_rate"] = metric.fields.get("interface_statistics/full_interface_stats/bytes_sent")
metric.fields["interface_statistics/full_interface_stats/bytes_sent_delta"] = metric.fields.get("interface_statistics/full_interface_stats/bytes_sent")
return metric
'''
# Template config pertaining to Environment Objects
# Template for constructing object ID for node environmentals
[[processors.template]]
namepass = ["cpu_util*", "node_summary*"]
tag = "sessionName"
template = '{{ .Tag "source" }}_{{ .Tag "node_name" }}'
[[processors.template]]
namepass = ["cpu_util*", "node_summary*"]
tag = "sessionId"
template = '{{ .Tag "source" }}_{{ .Tag "node_name" }}'
[[processors.template]]
namepass = ["cpu_util*", "node_summary*"]
tag = "objectType"
template = 'cisco_mdt_environment'
[[processors.template]]
namepass = ["cpu_util*", "node_summary*"]
tag = "direction"
template = '-1'
[[processors.rename]]
order = 5
namepass = ["if_stats"]
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/input_errors"
dest = "interface_statistics/full_interface_stats/input_errors"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/output_errors"
dest = "interface_statistics/full_interface_stats/output_errors"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/packets_received"
dest = "interface_statistics/full_interface_stats/packets_received"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/packets_sent"
dest = "interface_statistics/full_interface_stats/packets_sent"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/input_drops"
dest = "interface_statistics/full_interface_stats/input_drops"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/output_drops"
dest = "interface_statistics/full_interface_stats/output_drops"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/bytes_received_rate"
dest = "interface_statistics/full_interface_stats/bytes_received_rate"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/bytes_received_delta"
dest = "interface_statistics/full_interface_stats/bytes_received_delta"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/bytes_sent"
dest = "interface_statistics/full_interface_stats/bytes_sent"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/bytes_sent_rate"
dest = "interface_statistics/full_interface_stats/bytes_sent_rate"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/bytes_sent_delta"
dest = "interface_statistics/full_interface_stats/bytes_sent_delta"
[[processors.rename.replace]]
field = "interface_statistics/basic_interface_stats/bytes_received"
dest = "interface_statistics/full_interface_stats/bytes_received"
# Restricts the number of tags that can pass through this filter and chooses which tags to preserve when over the limit.
[[processors.tag_limit]]
order = 6
## Maximum number of tags to preserve
limit = 4
## List of tags to preferentially preserve
keep = ["sessionId", "sessionName", "objectType","direction"]
Breakdown of Key Items in Default Telegraf TOML
This section will breakdown the key items in default telegraf TOML, using the following key items:
- Set Variable Names to Encoding Paths
- Set up MonitoredObjectName and MonitoredObjectID
- Standard Object Types
- Set Metric Names to Desired Values
- Select Metrics to be Ingested by Provider Connectivity Assurance
Set Variable Names to Encoding Paths.
[inputs.cisco_telemetry_mdt.aliases]
if_stats = "Cisco-IOS-XR-pfi-im-cmd-oper:interfaces/interface-xr/interface"
policy_out_stats = "Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/output/service-policy-names/service-policy-instance/statistics"
policy_in_stats = "Cisco-IOS-XR-qos-ma-oper:qos/interface-table/interface/input/service-policy-names/service-policy-instance/statistics"
cpu_util = "Cisco-IOS-XR-wdsysmon-fd-oper:system-monitoring/cpu-utilization"
node_summary = "Cisco-IOS-XR-nto-misc-oper:memory-summary/nodes/node/summary"
ipsla = "Cisco-IOS-XR-man-ipsla-oper:ipsla/operation-data/operations/operation/statistics/latest/target"
As a rule, these aliases correspond to each sensor-path
or xpath
you are sending from your devices, and they will correspond 1-to-1 to new Object Types within Provider Connectivity Assurance (formerly Accedian Skylight analytics). There are exceptions, and some can be regrouped when needed.
Following the example above, you would expect to have get the following types of objects: cisco_mdt_interface, cisco_mdt_policy_stats (in & out), cisco_mdt_environment (node_summary & cpu_util), ipsla.
Set up MonitoredObjectName and MonitoredObjectID
The monitored object names and IDs are the unique mandatory identifiers in Provider Connectivity Assurance for each object in the Inventory. You will also need to set up the object type which contains all the metrics from the sensor path. This is repeated for each object type you are ingesting.
Within the Telegraph based Telemetry Collector solution, sessionName and sessionId are used in place of MonitoredObjectName and MonitoredObjectID to satisfy Sensor Collector value requirements.
An object instance will contain all the relevant metrics for an instance.
For example, an “interface” object (ex: router1_gigabitEthernet0/0/1 ) will show metrics like packets in/out, bytes in/out, errors in/out, etc. from that specific instance.
The nomenclature used to identify each instance should be precise, specific and meaningful to allow end-users to easily pinpoint the object of their choice in a table shown in a dashboard (top-down) AND allow them to search for it in the inventory easily (bottom-up).
The object name is usually formed from a concatenation of existing values. In the example below we picked “source” and “interface_name” which appends the name of a router along with the interface. The recipe for building the object name will depend on the object type you are working with and the data offered by the router.
Standard Object Types
To construct Interface objects, see below:
# Template for constructing object ID for Interface Stats
[[processors.template]]
namepass = ["if_stats*"]
tag = "sessionName"
template = '{{ .Tag "source" }}_{{ .Tag "interface_name" }}'
[[processors.template]]
namepass = ["if_stats*"]
tag = "sessionId"
template = '{{ .Tag "source" }}_{{ .Tag "interface_name" }}'
[[processors.template]]
namepass = ["if_stats*"]
tag = "objectType"
template = "cisco_mdt_interface"
Set Metric Names to Desired Values
By default, metric names are kept as is from the MDT source with the addition of the sensor-path alias to differentiate metrics of the same name from different paths. If you must rename or clarify the naming of the metrics, it will be done within the Telegraph configuration.
When it comes to processing metrics, simple business logic can be added to the Telegraf configuration to either consolidate metrics into fewer entries or perform simple math. For example, by renaming a metrics path into another one when you get either “A or B” but never “A and B”, you can ask Telegraf to convert A into B and save half the metric entries that would remain zeros.
Select Metrics to be Ingested by Provider Connectivity Assurance
Once all metric names have been set to desired values and metrics have been processed as required, you must pick the metrics you would like to ingest in Provider Connectivity Assurance.
Once you visualize exactly what Telegraf is receiving, the Telemetry Collector will help by allowing a quick and easy translation from MDT to JSON.
The configuration snippet below will tell Telegraf to write the MDT data received by the Telemetry Collector as raw JSON in the docker logs
.
Then you can easily copy and paste the data into a file to identify the metrics of interest and their field names. You can also skip the copy and paste step and configure your file output plugin to write directly to a file instead of stdout.
Note: You can limit the data written to the logs using the namedrop
option. For example, if you have already configured the interface statistics (if_stats
) then you can tell telegraf NOT to write this in the logs so as to only focus on those types you have not configured yet.
[[outputs.file]]
files = ["stdout"]
data_format = "json"
namedrop = ["if_stats*","sr_pm*"]
Once you confirmed the metrics you want to ingest in Provider Connectivity Assurance, a processor section is required to enforce the limit on what is outputted. If you do not enforce this limit, all of the metrics broadcasted by a sensor path will be sent to Provider Connectivity Assurance.
[[processors.tag_limit]]
namepass = ["if_stats*"]
fieldinclude = [
"state",
"bandwidth",
"data_rates/bandwidth",
"data_rates/input_data_rate",
"data_rates/output_data_rate",
"interface_statistics/full_interface_stats/input_errors",
"interface_statistics/full_interface_stats/output_errors",
"interface_statistics/full_interface_stats/crc_errors",
"interface_statistics/full_interface_stats/runt_packets_received",
"interface_statistics/full_interface_stats/bytes_received",
"interface_statistics/full_interface_stats/packets_received",
"interface_statistics/full_interface_stats/packets_sent",
"interface_statistics/full_interface_stats/input_drops",
"interface_statistics/full_interface_stats/output_drops",
"interface_statistics/full_interface_stats/bytes_received_rate",
"interface_statistics/full_interface_stats/bytes_received_delta",
"interface_statistics/full_interface_stats/bytes_sent",
"interface_statistics/full_interface_stats/bytes_sent_rate",
"interface_statistics/full_interface_stats/bytes_sent_delta",
"availability_percent",
]
## Maximum number of tags to preserve
limit = 4
## List of tags to preferentially preserve
keep = ["sessionId", "sessionName", "objectType","direction"]