TelegrafでDial-Out方式のTelemetryデータを収集する(UDP)

TelemetryのコレクタとしてTelegrafを利用し、Prometheus・Grafanaを利用し可視化を行った際のメモ
(ネットワークシュミレータで実施)
# Telemetryとは
ざっくり
- トラフィックや機器状態など情報を出力するネットワーク監視のための技術
- 従来のSNMPと比較して「柔軟性が高い」「リアルタイム性が高い」などのメリットがある
- 接続方式・メッセージ形式・通信形式が複数種類ある
    - 接続方式：Dial-In / Dial-Out
    - メッセージ形式：GPB、JSON など
    - 通信形式：UDP、gRPCなど

今回は、JuniperのDial-Out(UDP)で確認しました

# 構成とアウトプットのイメージ
- Telemetryを出すネットワーク機器としてvJunos-EVOを利用
- ネットワークシュミレータ上にUbuntuを設置してTelemetryコレクタとして利用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/8a696e71-a679-02ed-7685-06c555514d59.png)

- 各ソフトウェアの役割は以下のイメージです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/0601d828-8fa2-55d1-dc00-65f1c911afb6.png)
- 今回には Grafanaで以下のような簡単なグラフで可視化することを目標にしてます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/c2030b5a-ff4b-97f7-dd5f-f5c6320217c2.png)

# サーバ側の準備
## Ubuntuの準備
ネットワークシュミレータ内のUbuntuは以下を参考に準備(今回はUbuntu 24.04を利用)

https://qiita.com/k-maki/items/20c4039db1636c8ad6a9#-2-%E3%82%B5%E3%83%BC%E3%83%90ubuntu%E3%81%AE%E6%BA%96%E5%82%99


## Telegrafのインストール
root ユーザで、以下を実施
```:Telegrafのインストールのインストール
curl -fsSL https://repos.influxdata.com/influxdata-archive_compat.key -o /etc/apt/keyrings/influxdata-archive_compat.key
echo "deb [signed-by=/etc/apt/keyrings/influxdata-archive_compat.key] https://repos.influxdata.com/ubuntu stable main" | tee /etc/apt/sources.list.d/influxdata.list

apt update
apt -y install telegraf
```
以下のサイトを参考にしてます

https://www.server-world.info/query?os=Ubuntu_24.04&p=influxdb&f=7

## Junos-EVOのprotoファイルのダウンロード
受け取ったTelemetryデータはバイナリのデータでそのままでは内容が不明なため、それを翻訳するために、Junos-EVOのprotoファイルをダウンロードしprotoファイル保存用のディレクトリを作成し保存する

```:Telegrafのインストールのインストール
# GitHubからJunosのtelemetry用protoファイルをダウンロード
git clone --depth 1 https://github.com/Juniper/telemetry.git

# protoファイル保存用のディレクトリを作成
mkdir -p /usr/include/protos/junos-evo

# Junos-EVOの24.2R1のファイルをコピー
cp telemetry/24.2/24.2R1-EVO/protos/* /usr/include/protos/junos-evo/
```

GitHubからダウンロードすると複数バージョンかつJunosとJunos-EVOそれぞれのprotoファイルがダウンロードされます。今回はルータにvJunosEvoのルータを利用しているので「24.2R1-EVO」を利用してます。

# ルータ側の準備
以下の内容でコンフィグ設定
- JunosのTelemetryの設定は「set services analytics・・」で始まる箇所となります
    - Telemetryの送信先は「10.99.0.1」でポート番号は「20000」
    - 10秒おきに送信 (reporting-rateの部分)
    - 送信はUDPでフォーマットはgpd
        - UDP以外にもgRPCが選択できます
    - Telemetryとして送る内容について今回は「in-octets」の入力バイト数のカウンタ

コンフィグは以下となります
(rootパスワードは仮で「root123」にしてます)
```: vJunosEvolvedのコンフィグ
set version 23.4R2-S2.1-EVO
set system host-name vJunosEvolved
set system root-authentication encrypted-password "$6$MmGV7bPW$AuqgoIhnFiZQD9eLmmhS.Fwywh63knLvg96p9VLQXP5jSxMk3QXSBFph4Z3W1Hcvf34xdlIh0QRlHrh/j8rr5/"
set system syslog file interactive-commands interactive-commands any
set system syslog file messages any notice
set system syslog file messages authorization info
set services analytics streaming-server TELEMETRY_SV remote-address 10.99.0.1
set services analytics streaming-server TELEMETRY_SV remote-port 20000
set services analytics export-profile TELEMETRY_PROFILE local-address 10.99.0.2
set services analytics export-profile TELEMETRY_PROFILE local-port 21111
set services analytics export-profile TELEMETRY_PROFILE reporting-rate 10
set services analytics export-profile TELEMETRY_PROFILE format gpb
set services analytics export-profile TELEMETRY_PROFILE transport udp
set services analytics sensor TELEMETRY_SENSOR_IN_OCTETS server-name TELEMETRY_SV
set services analytics sensor TELEMETRY_SENSOR_IN_OCTETS export-name TELEMETRY_PROFILE
set services analytics sensor TELEMETRY_SENSOR_IN_OCTETS resource /interfaces/interface/state/counters/in-octets/
set services analytics sensor TELEMETRY_SENSOR_IN_OCTETS resource-filter et-*
set interfaces et-0/0/1 unit 0 family inet address 10.0.1.1/24
set interfaces et-0/0/2 unit 0 family inet address 10.0.2.1/24
set interfaces et-0/0/9 unit 0 family inet address 10.99.0.2/24

```

# Telemetry受信データの確認と整形
## Telegrafの設定
Telegrafの設定は「/etc/telegraf/telegraf.conf」になるため、こちらを以下の内容で編集
- UDP:20000ポートで待ち、受信の際はProtocol Buffersで処理
- 受信したデータについては、Junos-EVO用のprotoファイルを利用し内容をバイナリから変換
- 受信した内容を「/var/log/telegraf/metrics.json」に出力


<details><summary>telegraf.conf 設定内容はコチラ (データ受信確認用)</summary>
<div>

```:telegraf.conf 設定内容 (データ受信確認用)
[agent]

  interval = "10s"		# データを収集する間隔
  round_interval = true		# [true] の場合 収集時間は :00, :10, :20 ...
  metric_batch_size = 1000	# バッチ処理で Outoput に送信する際のメトリクスサイズ
  metric_buffer_limit = 10000	# 使用するメモリーの上限値
  collection_jitter = "0s"	# メトリクス収集の遅延時間 - 各プラグインがメトリクス収集の際に設定値の範囲内でスリープ
  flush_interval = "10s"	# Output データを出力する間隔
  flush_jitter = "0s"		# データを出力する際の遅延時間
  precision = "0s"

  logfile = "/var/log/telegraf/telegraf.log"	# ログファイルのパス
  logtarget = "file"		# 出力先: "file", "stderr", "stdout"

  # デバッグ時に有効にする
  #debug = true

# ------------------------------------------------------------------------------------------------------------------------
#
# Telemetry (JUNOS-EVO)
#
# ------------------------------------------------------------------------------------------------------------------------

[[inputs.socket_listener]]
  service_address = "udp://:20000"

  data_format = "xpath_protobuf"
  xpath_protobuf_files = ["telemetry_top.proto",
                          "aftman-cos-oc_ifl_render.proto",
                          #"aftman-cos-oc_render.proto",
                          "aftman-npu-mem-oc_render.proto",
                          "aftman-npu-util-oc_render.proto",
                          "aftman-qos-voqmon-stats-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-ingress-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-ingress-udp-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-transit-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-transit-udp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-lsp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-lsp-udp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-egress-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-egress-udp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-ingress-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-ingress-udp-oc_render.proto",
                          #"aftman-sensor-lsp-ni-oc_render.proto",
                          #"aftman-sensor-lsp-oc_render.proto",
                          #"aftman-sensor-lsp-udp-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv4-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv4-udp-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv6-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv6-udp-oc_render.proto",
                          #"aftman-sensor-sr-egress-interface-openconfig_oc_render.proto",
                          #"aftman-sensor-sr-egress-interface_oc_render.proto",
                          #"aftman-sensor-sr-ingress-interface-openconfig_oc_render.proto",
                          #"aftman-sensor-sr-ingress-interface_oc_render.proto",
                          #"aftman-sensor-sr-sid_egress_oc_render.proto",
                          #"aftman-sensor-sr-sid_ingress_oc_render.proto",
                          #"aftman-sensor-sr-sid_ingress_openconfig_oc_render.proto",
                          #"aftman-sensor-srte-bsid-oc_render.proto",
                          #"aftman-sensor-srte-bsid-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-bsid-udp-oc_render.proto",
                          #"aftman-sensor-srte-ingress-tunnel-oc_render.proto",
                          #"aftman-sensor-srte-ingress-tunnel-udp-oc_render.proto",
                          #"aftman-sensor-srte-ip-oc_render.proto",
                          #"aftman-sensor-srte-ip-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-ip-udp-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-ingress-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-ingress-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-ingress-udp-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-transit-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-transit-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-transit-udp-oc_render.proto",
                          #"aftman-sensor-srte-transit-tunnel-oc_render.proto",
                          #"aftman-sensor-srte-transit-tunnel-udp-oc_render.proto",
                          "aftsysinfo-oc_render.proto",
                          "agent.proto",
                          "alarmd_oc_render.proto",
                          "am-cos-egress-qstat-oc_render.proto",
                          #"am-cos-egress-qstat-udp-oc_render.proto",
                          "am-cos-interfaceset-stats_render.proto",
                          "am-cos-intf-qstat-ext-oc_render.proto",
                          "am-ddos-oc_render.proto",
                          "am-dfw-oc-render.proto",
                          "am-ic-pfe-oc_render.proto",
                          "am-if-oc_render.proto",
                          "am-if-udp-oc_render.proto",
                          "am-ifl-udp-oc_render.proto",
                          #"am-ifl-v4-udp-oc_render.proto",
                          #"am-ifl-v6-udp-oc_render.proto",
                          "am-intf-exp-udp-oc_render.proto",
                          "am-jflowui-udp-oc_render.proto",
                          "am-pfe-oc_render.proto",
                          "bfdd-junos-openconfig-bfd-render.proto",
                          #"brcm-cos-qstat-oc_render.proto",
                          #"brcm-host-interface-pipestats-oc_render.proto",
                          #"brcm-if-oc_render.proto",
                          #"brcm-interface-pipestats-oc_render.proto",
                          #"brcm-pfe-oc_render.proto",
                          #"brcm-pfe-udp_render.proto",
                          "cda-btchip-ic-npu-util-oc_render.proto",
                          #"cda-btchip-npu-util-oc_render.proto",
                          "cda-bxchip-npu-util-oc_render.proto",
                          "cda-bxchip-stats-oc_render.proto",
                          "cda-drop-lookup-pipestats-oc_render.proto",
                          "cda-drop-state-pipestats-oc_render.proto",
                          "cda-expr_pipestats-oc_render.proto",
                          "cda-pkt-lookup-pipestats-oc_render.proto",
                          #"cda-zephyr-stats-oc_render.proto",
                          "cda-zxchip-npu-util-oc_render.proto",
                          "cda-zxchip-stats-oc_render.proto",
                          "cfmd-junos-state-oam-cfm-render.proto",
                          #"cmevod-fpcenv-oc_render.proto",
                          "cosd_oc_evo.proto",
                          "ddosd-junos-state-ddos-protection-render.proto",
                          "dot1xd-junos-openconfig-if-8021x-render.proto",
                          "dot1xd-junos-state-dot1x-render.proto",
                          "dot1xd_oc.proto",
                          "ehmd_comp_oc.proto",
                          "ehmd_oc.proto",
                          "ehmd_system_chassis_native.proto",
                          "ehmd_system_oc.proto",
                          "evo-if-oc_render.proto",
                          "evo-interface-pipestats-oc_render.proto",
                          "evo-pkt-host-interface-pipestats-oc_render.proto",
                          "fabricHub_oc.proto",
                          "fabspoked-fchip-junos-openconfig-platform-render.proto",
                          "fabspoked-pfe-junos-openconfig-platform-pipeline-counters-render.proto",
                          "fibtd-junos-state-anomalies-fib-render.proto",
                          "fibtd-telemetry_oc.proto",
                          "fwstatsd_oc_evo_state.proto",
                          "fwstatsd_oc_ni.proto",
                          "gnmi.proto",
                          "GnmiJuniperTelemetryHeader.proto",
                          "GnmiJuniperTelemetryHeaderExtension.proto",
                          "gnmi_dialout.proto",
                          "gnmi_ext.proto",
                          "hwdfpc_oc.proto",
                          "hwdre-evo-openconfig-system-render.proto",
                          "hwdre-healthz-oc_render.proto",
                          "hwdre-junos-state-health-render.proto",
                          "hwdre_fpc_env.proto",
                          "hwdre_oc.proto",
                          "jexpr-drop-host-interface-pipestats-oc_render.proto",
                          "jexpr-ic-npu-mem-oc_render.proto",
                          "jexpr-junos-integrated_circuit-oc_render.proto",
                          "jexpr-junos-npu-pipeline-resource-util-oc_render.proto",
                          "jexpr-npu-mem-oc_render.proto",
                          "jexpr-pkt-lookup-pipestats-oc_render.proto",
                          "jsd-junos-state-grpc.proto",
                          "jsd_health_oc.proto",
                          "junos-pfe-npu-render.proto",
                          "junos-xmlproxyd_junos-rsvp-interface.proto",
                          "junos-xmlproxyd_junos-rtg-task-memory.proto",
                          "junos_state_interface_render.proto",
                          "l2ald_bd_render.proto",
                          "l2ald_evpn_render.proto",
                          "l2ald_fdb_render.proto",
                          "l2ald_oc.proto",
                          "l2ald_oc_intf.proto",
                          "l2cpd-junos-state-lldp-render.proto",
                          "l2cpd_oc.proto",
                          "l2cpd_stp_oc.proto",
                          "lacpd_oc.proto",
                          "license-check-features-oc.proto",
                          "master-eventd-state-system-syslog.proto",
                          "master-eventd_oc.proto",
                          "mgmt-ethd_oc_evo_intf_stats.proto",
                          "mib2d_native_evo_intf_state.proto",
                          "mib2d_oc_evo_intf_state.proto",
                          "na-grpcd-junos-state-gnmi.proto",
                          "na-grpcd_stats_oc.proto",
                          "oc_component_render.proto",
                          #"oc_interface_render.proto",
                          "oc_optics_render.proto",
                          "pfe_page_drop_oc.proto",
                          "picd_oc_component_render.proto",
                          "platformd-fabric-oc_render.proto",
                          "resiliencyd-cmerror_cfg-oc_render.proto",
                          "resiliencyd-cmerror_cfg-udp-oc_render.proto",
                          #"resiliencyd-cmerror_stats-oc_render.proto",
                          "resiliencyd-cmerror_stats-udp-oc_render.proto",
                          "resiliencyd-comp_ic_pipeline_errcnt-oc_render.proto",
                          "rmopd_native_sensors_render.proto",
                          "rmopd_probe_oc_render.proto",
                          "rpd-junos-openconfig-ospfv2-render.proto",
                          "rpd_bgp_junos_route_validation.proto",
                          "rpd_bgp_junos_state.proto",
                          "rpd_bgp_rib_oc.proto",
                          "rpd_evpn_global_render.proto",
                          "rpd_evpn_instance_junos_state.proto",
                          "rpd_evpn_rib_oc.proto",
                          "rpd_gribi_stats_oc.proto",
                          "rpd_if_ipv6_ra_oc.proto",
                          "rpd_igmp_oc.proto",
                          "rpd_ipv6_ra_oc.proto",
                          "rpd_isis_oc.proto",
                          "rpd_ldp_oc.proto",
                          "rpd_ni_bgp_oc.proto",
                          "rpd_ni_evpn_render.proto",
                          "rpd_ni_oc.proto",
                          "rpd_pim_oc.proto",
                          "rpd_policy_oc.proto",
                          "rpd_resiliency_interface.proto",
                          "rpd_rsvp_oc.proto",
                          "rpd_srte_policy_oc.proto",
                          "rpd_te_oc.proto",
                          "svcsd_sflow_oc.proto",
                          "svcsd_sflow_openconfig.proto",
                          "sysd-evo-openconfig-system-render.proto",
                          "vrrpd_oc.proto",
                          "xmlproxyd-junos-commit-entries-render.proto",
                          "xmlproxyd-junos-openconfig-system-commit-render.proto",
                          "xmlproxyd-junos-openconfig-system-render.proto"]

  xpath_protobuf_type = "TelemetryStream"
  xpath_protobuf_import_paths = ["/usr/include/protos/junos-evo"]
  xpath_native_types = true

  [[inputs.socket_listener.xpath]]
    field_selection = "//*"
    field_name_expansion = false
    timestamp = "//timestamp"
    timestamp_format = "unix_ns"

    metric_name = "string('telemetry_junos_evo')"

#-------------------------------------------------------------------------------------


[[outputs.file]]
  files = ["/var/log/telegraf/metrics.json"]
  data_format = "json"
  namepass = ["telemetry_junos_evo"]  # メトリック名でフィルタリング


```
</div></details>

(参考)
protoファイルについてはいくつかコメントアウトしてます、他のprotoファイルの内容を重複しているものもあるみたいですべて指定してtelegrafを実行しようとするとエラーで起動できませんでした

```:telegrafの起動時のエラーメッセージ
# /usr/bin/telegraf -config /etc/telegraf/telegraf.conf
2025-XX-XXTXX:XX:23Z I! Loading config: /etc/telegraf/telegraf.conf
2025-XX-XXTXX:XX:23Z E! loading config file /etc/telegraf/telegraf.conf failed: error parsing socket_listener, adding parser failed: parsing protocol-buffer definition failed: brcm-pfe-oc_render.proto:9:9: symbol "components_counters" already defined at brcm-pfe-udp_render.proto:9:9

```
## 受信データの確認
ここまで設定して「/var/log/telegraf/metrics.json」を見るといくつかのTelemetryデータを定期的に受信しますが、「in-octets」は以下のように1行で複数IFの情報を受信します。

```:Telemetryの受信データの確認
# tail -f /var/log/telegraf/metrics.json
{"fields":{"component_id":0,"in_octets":14348,"in_octets_1":14488,"in_octets_2":14389,"name":"et-0/0/2","name_1":"et-0/0/1","name_2":"et-0/0/9","sensor_name":"TELEMETRY_SENSOR_IN_OCTETS:/interfaces/interface/state/counters/in-octets/:/interfaces/interface/state/counters/in-octets/:evo-aftmand-bt","sequence_number":12,"sub_component_id":0,"system_id":"vJunosEvolved:10.99.0.2","timestamp":XXXXXXXXXXXXX,"version_major":1,"version_minor":0},"name":"telemetry_junos_evo","tags":{"host":"ubuntu-24"},"timestamp":XXXX}

```

## データの整形
1行で複数IFを「_*」で表現されておりこのままだとPrometheusと連携しにくいため、1行を複数行に分解する

```:変更前
# 1行で「_*」で複数IFを出力
"in_octets":14348,"in_octets_1":14488,"in_octets_2":14389, "name":"et-0/0/2","name_1":"et-0/0/1","name_2":"et-0/0/9"・・・
```

```:変更後のイメージ
# IFごとに複数行に分ける
"in_octets":14348,"name":"et-0/0/2"
"in_octets":14488,"name":"et-0/0/1"
"in_octets":14389,"name":"et-0/0/9"
```

整形については、telegraf.conf 内で Starlarkプロセッサを使って編集、Pythonに近い文法で編集ができます
(ただし、Pythonと完全に一致するわけではなく、一部の文法は使用できないという制限がありました)

<details><summary>Starlarkの内容</summary>
<div>

```:Starlarkの内容
# Starlarkプロセッサでメトリクスを編集
[[processors.starlark]]

namepass = ["telemetry_junos_evo"] # 「telemetry_junos_evo」のみ処理させる

source = '''

fieldpass = ["system_id", "name*", "in_octets*"]

def apply(metric):

    ## デバッグ用
    #return metric

    # ホストネームとIPを取得
    SYSTEM_ID = metric.fields["system_id"]
      #string = "vJunosEvolved:10.99.0.2"

    PARTS = SYSTEM_ID.split(":")
    NUM_ELEMENTS = len(PARTS)

    if NUM_ELEMENTS == 2:
        HOST_NAME = PARTS[0]
        HOST_IP = PARTS[1]

    elif NUM_ELEMENTS == 1:
        HOST_NAME = PARTS[0]
        HOST_IP = ""
    else:
        HOST_NAME = ""
        HOST_IP = ""

    # 新しいメトリクスを保存するリスト
    RETURN_METRICS = []
    MAX_INDEX = 10000  # 最大インデックスの設定

    #-------------------------------------------------------------------------------------
    # 必要なフィールドがあるかチェックし、複数IFの1行をIF毎に1行に分解する
    FIELDS_NAME = "in_octets"
    HAS_BASE_FIELDS = FIELDS_NAME in metric.fields

    # 基本フィールド (index がない場合) の処理
    if HAS_BASE_FIELDS:
        ADD_METRIC = []
        ADD_METRIC = Metric("telemetry_junos_evo")
        ADD_METRIC.tags["name"] = metric.fields["name"]
        ADD_METRIC.tags["hostip"] = HOST_IP
        ADD_METRIC.tags["hostname"] = HOST_NAME
        ADD_METRIC.fields[FIELDS_NAME] = metric.fields[FIELDS_NAME]
        RETURN_METRICS.append(ADD_METRIC)

    # インデックス付きフィールドを処理
    for INDEX in range(MAX_INDEX):  # MAX_INDEX までのループ
        IF_INDEX = INDEX + 1
        CHECK_IF_NAME = "name_" + str(IF_INDEX)
        CHECK_IF_DATA = FIELDS_NAME + "_" + str(IF_INDEX)

        # 必要なフィールドがあるかチェック
        HAS_BASE_FIELDS = CHECK_IF_DATA in metric.fields

        if HAS_BASE_FIELDS:
            ADD_METRIC = []
            ADD_METRIC = Metric("telemetry_junos_evo")
            ADD_METRIC.tags["name"] = metric.fields[CHECK_IF_NAME]
            ADD_METRIC.tags["hostip"] = HOST_IP
            ADD_METRIC.tags["hostname"] = HOST_NAME
            ADD_METRIC.fields[FIELDS_NAME] = metric.fields[CHECK_IF_DATA]
            RETURN_METRICS.append(ADD_METRIC)
        else:
            # フィールドが無ければforのloopを終了
            break

    #-------------------------------------------------------------------------------------

    # 生成されたメトリクスを返す
    return RETURN_METRICS

'''
```
</div></details>


上記を反映したtelegraf.confはこちら ↓ になります

<details><summary>telegraf.conf 設定内容はコチラ (データ整形後の受信確認用)</summary>
<div>

```:telegraf.conf 設定内容 (データ整形後の受信確認用)

[agent]

  interval = "10s"		# データを収集する間隔
  round_interval = true		# [true] の場合 収集時間は :00, :10, :20 ...
  metric_batch_size = 1000	# バッチ処理で Outoput に送信する際のメトリクスサイズ
  metric_buffer_limit = 10000	# 使用するメモリーの上限値
  collection_jitter = "0s"	# メトリクス収集の遅延時間 - 各プラグインがメトリクス収集の際に設定値の範囲内でスリープ
  flush_interval = "10s"	# Output データを出力する間隔
  flush_jitter = "0s"		# データを出力する際の遅延時間
  precision = "0s"

  logfile = "/var/log/telegraf/telegraf.log"	# ログファイルのパス
  logtarget = "file"		# 出力先: "file", "stderr", "stdout"

  # デバッグ時に有効にする
  #debug = true

# ------------------------------------------------------------------------------------------------------------------------
#
# Telemetry (JUNOS-EVO)
#
# ------------------------------------------------------------------------------------------------------------------------

[[inputs.socket_listener]]
  service_address = "udp://:20000"

  data_format = "xpath_protobuf"
  xpath_protobuf_files = ["telemetry_top.proto",
                          "aftman-cos-oc_ifl_render.proto",
                          #"aftman-cos-oc_render.proto",
                          "aftman-npu-mem-oc_render.proto",
                          "aftman-npu-util-oc_render.proto",
                          "aftman-qos-voqmon-stats-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-ingress-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-ingress-udp-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-transit-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-transit-udp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-lsp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-lsp-udp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-egress-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-egress-udp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-ingress-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-ingress-udp-oc_render.proto",
                          #"aftman-sensor-lsp-ni-oc_render.proto",
                          #"aftman-sensor-lsp-oc_render.proto",
                          #"aftman-sensor-lsp-udp-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv4-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv4-udp-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv6-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv6-udp-oc_render.proto",
                          #"aftman-sensor-sr-egress-interface-openconfig_oc_render.proto",
                          #"aftman-sensor-sr-egress-interface_oc_render.proto",
                          #"aftman-sensor-sr-ingress-interface-openconfig_oc_render.proto",
                          #"aftman-sensor-sr-ingress-interface_oc_render.proto",
                          #"aftman-sensor-sr-sid_egress_oc_render.proto",
                          #"aftman-sensor-sr-sid_ingress_oc_render.proto",
                          #"aftman-sensor-sr-sid_ingress_openconfig_oc_render.proto",
                          #"aftman-sensor-srte-bsid-oc_render.proto",
                          #"aftman-sensor-srte-bsid-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-bsid-udp-oc_render.proto",
                          #"aftman-sensor-srte-ingress-tunnel-oc_render.proto",
                          #"aftman-sensor-srte-ingress-tunnel-udp-oc_render.proto",
                          #"aftman-sensor-srte-ip-oc_render.proto",
                          #"aftman-sensor-srte-ip-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-ip-udp-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-ingress-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-ingress-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-ingress-udp-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-transit-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-transit-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-transit-udp-oc_render.proto",
                          #"aftman-sensor-srte-transit-tunnel-oc_render.proto",
                          #"aftman-sensor-srte-transit-tunnel-udp-oc_render.proto",
                          "aftsysinfo-oc_render.proto",
                          "agent.proto",
                          "alarmd_oc_render.proto",
                          "am-cos-egress-qstat-oc_render.proto",
                          #"am-cos-egress-qstat-udp-oc_render.proto",
                          "am-cos-interfaceset-stats_render.proto",
                          "am-cos-intf-qstat-ext-oc_render.proto",
                          "am-ddos-oc_render.proto",
                          "am-dfw-oc-render.proto",
                          "am-ic-pfe-oc_render.proto",
                          "am-if-oc_render.proto",
                          "am-if-udp-oc_render.proto",
                          "am-ifl-udp-oc_render.proto",
                          #"am-ifl-v4-udp-oc_render.proto",
                          #"am-ifl-v6-udp-oc_render.proto",
                          "am-intf-exp-udp-oc_render.proto",
                          "am-jflowui-udp-oc_render.proto",
                          "am-pfe-oc_render.proto",
                          "bfdd-junos-openconfig-bfd-render.proto",
                          #"brcm-cos-qstat-oc_render.proto",
                          #"brcm-host-interface-pipestats-oc_render.proto",
                          #"brcm-if-oc_render.proto",
                          #"brcm-interface-pipestats-oc_render.proto",
                          #"brcm-pfe-oc_render.proto",
                          #"brcm-pfe-udp_render.proto",
                          "cda-btchip-ic-npu-util-oc_render.proto",
                          #"cda-btchip-npu-util-oc_render.proto",
                          "cda-bxchip-npu-util-oc_render.proto",
                          "cda-bxchip-stats-oc_render.proto",
                          "cda-drop-lookup-pipestats-oc_render.proto",
                          "cda-drop-state-pipestats-oc_render.proto",
                          "cda-expr_pipestats-oc_render.proto",
                          "cda-pkt-lookup-pipestats-oc_render.proto",
                          #"cda-zephyr-stats-oc_render.proto",
                          "cda-zxchip-npu-util-oc_render.proto",
                          "cda-zxchip-stats-oc_render.proto",
                          "cfmd-junos-state-oam-cfm-render.proto",
                          #"cmevod-fpcenv-oc_render.proto",
                          "cosd_oc_evo.proto",
                          "ddosd-junos-state-ddos-protection-render.proto",
                          "dot1xd-junos-openconfig-if-8021x-render.proto",
                          "dot1xd-junos-state-dot1x-render.proto",
                          "dot1xd_oc.proto",
                          "ehmd_comp_oc.proto",
                          "ehmd_oc.proto",
                          "ehmd_system_chassis_native.proto",
                          "ehmd_system_oc.proto",
                          "evo-if-oc_render.proto",
                          "evo-interface-pipestats-oc_render.proto",
                          "evo-pkt-host-interface-pipestats-oc_render.proto",
                          "fabricHub_oc.proto",
                          "fabspoked-fchip-junos-openconfig-platform-render.proto",
                          "fabspoked-pfe-junos-openconfig-platform-pipeline-counters-render.proto",
                          "fibtd-junos-state-anomalies-fib-render.proto",
                          "fibtd-telemetry_oc.proto",
                          "fwstatsd_oc_evo_state.proto",
                          "fwstatsd_oc_ni.proto",
                          "gnmi.proto",
                          "GnmiJuniperTelemetryHeader.proto",
                          "GnmiJuniperTelemetryHeaderExtension.proto",
                          "gnmi_dialout.proto",
                          "gnmi_ext.proto",
                          "hwdfpc_oc.proto",
                          "hwdre-evo-openconfig-system-render.proto",
                          "hwdre-healthz-oc_render.proto",
                          "hwdre-junos-state-health-render.proto",
                          "hwdre_fpc_env.proto",
                          "hwdre_oc.proto",
                          "jexpr-drop-host-interface-pipestats-oc_render.proto",
                          "jexpr-ic-npu-mem-oc_render.proto",
                          "jexpr-junos-integrated_circuit-oc_render.proto",
                          "jexpr-junos-npu-pipeline-resource-util-oc_render.proto",
                          "jexpr-npu-mem-oc_render.proto",
                          "jexpr-pkt-lookup-pipestats-oc_render.proto",
                          "jsd-junos-state-grpc.proto",
                          "jsd_health_oc.proto",
                          "junos-pfe-npu-render.proto",
                          "junos-xmlproxyd_junos-rsvp-interface.proto",
                          "junos-xmlproxyd_junos-rtg-task-memory.proto",
                          "junos_state_interface_render.proto",
                          "l2ald_bd_render.proto",
                          "l2ald_evpn_render.proto",
                          "l2ald_fdb_render.proto",
                          "l2ald_oc.proto",
                          "l2ald_oc_intf.proto",
                          "l2cpd-junos-state-lldp-render.proto",
                          "l2cpd_oc.proto",
                          "l2cpd_stp_oc.proto",
                          "lacpd_oc.proto",
                          "license-check-features-oc.proto",
                          "master-eventd-state-system-syslog.proto",
                          "master-eventd_oc.proto",
                          "mgmt-ethd_oc_evo_intf_stats.proto",
                          "mib2d_native_evo_intf_state.proto",
                          "mib2d_oc_evo_intf_state.proto",
                          "na-grpcd-junos-state-gnmi.proto",
                          "na-grpcd_stats_oc.proto",
                          "oc_component_render.proto",
                          #"oc_interface_render.proto",
                          "oc_optics_render.proto",
                          "pfe_page_drop_oc.proto",
                          "picd_oc_component_render.proto",
                          "platformd-fabric-oc_render.proto",
                          "resiliencyd-cmerror_cfg-oc_render.proto",
                          "resiliencyd-cmerror_cfg-udp-oc_render.proto",
                          #"resiliencyd-cmerror_stats-oc_render.proto",
                          "resiliencyd-cmerror_stats-udp-oc_render.proto",
                          "resiliencyd-comp_ic_pipeline_errcnt-oc_render.proto",
                          "rmopd_native_sensors_render.proto",
                          "rmopd_probe_oc_render.proto",
                          "rpd-junos-openconfig-ospfv2-render.proto",
                          "rpd_bgp_junos_route_validation.proto",
                          "rpd_bgp_junos_state.proto",
                          "rpd_bgp_rib_oc.proto",
                          "rpd_evpn_global_render.proto",
                          "rpd_evpn_instance_junos_state.proto",
                          "rpd_evpn_rib_oc.proto",
                          "rpd_gribi_stats_oc.proto",
                          "rpd_if_ipv6_ra_oc.proto",
                          "rpd_igmp_oc.proto",
                          "rpd_ipv6_ra_oc.proto",
                          "rpd_isis_oc.proto",
                          "rpd_ldp_oc.proto",
                          "rpd_ni_bgp_oc.proto",
                          "rpd_ni_evpn_render.proto",
                          "rpd_ni_oc.proto",
                          "rpd_pim_oc.proto",
                          "rpd_policy_oc.proto",
                          "rpd_resiliency_interface.proto",
                          "rpd_rsvp_oc.proto",
                          "rpd_srte_policy_oc.proto",
                          "rpd_te_oc.proto",
                          "svcsd_sflow_oc.proto",
                          "svcsd_sflow_openconfig.proto",
                          "sysd-evo-openconfig-system-render.proto",
                          "vrrpd_oc.proto",
                          "xmlproxyd-junos-commit-entries-render.proto",
                          "xmlproxyd-junos-openconfig-system-commit-render.proto",
                          "xmlproxyd-junos-openconfig-system-render.proto"]

  xpath_protobuf_type = "TelemetryStream"
  xpath_protobuf_import_paths = ["/usr/include/protos/junos-evo"]
  xpath_native_types = true

  [[inputs.socket_listener.xpath]]
    field_selection = "//*"
    field_name_expansion = false
    timestamp = "//timestamp"
    timestamp_format = "unix_ns"

    metric_name = "string('telemetry_junos_evo')"


#-------------------------------------------------------------------------------------

# Starlarkプロセッサでメトリクスを編集 ('telemetry_junos_evo')
[[processors.starlark]]

namepass = ["telemetry_junos_evo"] # 「telemetry_junos_evo」のみ処理させる

source = '''

fieldpass = ["system_id", "name*", "in_octets*"]

def apply(metric):

    ## デバッグ用
    #return metric

    # ホストネームとIPを取得
    SYSTEM_ID = metric.fields["system_id"]
      #string = "vJunosEvolved:10.99.0.2"

    PARTS = SYSTEM_ID.split(":")
    NUM_ELEMENTS = len(PARTS)

    if NUM_ELEMENTS == 2:
        HOST_NAME = PARTS[0]
        HOST_IP = PARTS[1]

    elif NUM_ELEMENTS == 1:
        HOST_NAME = PARTS[0]
        HOST_IP = ""
    else:
        HOST_NAME = ""
        HOST_IP = ""

    # 新しいメトリクスを保存するリスト
    RETURN_METRICS = []
    MAX_INDEX = 10000  # 最大インデックスの設定

    #-------------------------------------------------------------------------------------
    # 必要なフィールドがあるかチェックし、複数IFの1行をIF毎に1行に分解する
    FIELDS_NAME = "in_octets"
    HAS_BASE_FIELDS = FIELDS_NAME in metric.fields

    # 基本フィールド (index がない場合) の処理
    if HAS_BASE_FIELDS:
        ADD_METRIC = []
        ADD_METRIC = Metric("telemetry_junos_evo")
        ADD_METRIC.tags["name"] = metric.fields["name"]
        ADD_METRIC.tags["hostip"] = HOST_IP
        ADD_METRIC.tags["hostname"] = HOST_NAME
        ADD_METRIC.fields[FIELDS_NAME] = metric.fields[FIELDS_NAME]
        RETURN_METRICS.append(ADD_METRIC)

    # インデックス付きフィールドを処理
    for INDEX in range(MAX_INDEX):  # MAX_INDEX までのループ
        IF_INDEX = INDEX + 1
        CHECK_IF_NAME = "name_" + str(IF_INDEX)
        CHECK_IF_DATA = FIELDS_NAME + "_" + str(IF_INDEX)

        # 必要なフィールドがあるかチェック
        HAS_BASE_FIELDS = CHECK_IF_DATA in metric.fields

        if HAS_BASE_FIELDS:
            ADD_METRIC = []
            ADD_METRIC = Metric("telemetry_junos_evo")
            ADD_METRIC.tags["name"] = metric.fields[CHECK_IF_NAME]
            ADD_METRIC.tags["hostip"] = HOST_IP
            ADD_METRIC.tags["hostname"] = HOST_NAME
            ADD_METRIC.fields[FIELDS_NAME] = metric.fields[CHECK_IF_DATA]
            RETURN_METRICS.append(ADD_METRIC)
        else:
            # フィールドが無ければforのloopを終了
            break

    #-------------------------------------------------------------------------------------

    # 生成されたメトリクスを返す
    return RETURN_METRICS

'''

#-------------------------------------------------------------------------------------


[[outputs.file]]
  files = ["/var/log/telegraf/metrics.json"]
  data_format = "json"
  namepass = ["telemetry_junos_evo"]  # メトリック名でフィルタリング

```
</div></details>

- 設定内容を反映させるため Telegraf をリスタート
    - systemctl restart telegraf.service

# Prometheusと連携
## Prometheusのインストール

- Prometheusのインストール
  - root ユーザで、以下を実施
```:Prometheusのインストール
apt -y install prometheus
systemctl enable prometheus

```
- 以下のサイトを参考にしてます

https://www.server-world.info/query?os=Ubuntu_24.04&p=prometheus&f=1

## Prometheus側の設定
- 「/etc/prometheus/prometheus.yml」を編集する
- 事前にオリジナルのデータをコピーしておく
    - cp -p /etc/prometheus/prometheus.yml /etc/prometheus/prometheus.yml.org
- 「/etc/prometheus/prometheus.ymlを編集
    - 9273ポートでtelegrafのデータを取得する

```:prometheus.yml 設定内容
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.

scrape_configs:
  - job_name: telegraf
    static_configs:
      - targets:
        - localhost:9273

```

- 設定内容を反映させるため Prometheus をリスタート
    - systemctl restart prometheus.service

## Telegraf側の設定
- telegraf.conf に以下の設定をすることでPrometheusと連携できる

```:telegraf.conf 設定内容
[[outputs.prometheus_client]]
  listen = ":9273" # 9237ポートでprometheusと連携
  collectors_exclude = ["gocollector", "process"]  # デフォルトで利用される"gocollector", "process"は除外
  namepass = ["telemetry_junos_evo"]  # メトリック名でフィルタリング
```

- 設定内容を反映させるため Telegraf をリスタート
    - systemctl restart telegraf.service


## Prometheusで確認を行う
- ブラウザで「http://[サーバのアドレス]:9090/」にログインして Prometheusの管理画面を開く
- 「Graph」を選択し、Telegrafで設定した Telemetryデータが選択できることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/ccb73369-424f-d7dd-fa15-bace4d69989b.png)

- 「Graph」で定期的に取得したデータからグラフ表示されることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/37ad6db9-dd40-022e-d7b1-8bfce7204784.png)

## Grafana で Prometheus のデータを表示する
- Grafanaのインストールと設定は以下を参考にしてください

https://qiita.com/k-maki/items/20c4039db1636c8ad6a9#grafana%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

- ブラウザで「http://[サーバのアドレス]:3000/」にログインして Grafana の管理画面を開く
    - 初期ユーザとパスワードはともに「admin」です
- Grafana と Prometheus の連携は他のサイトでもたくさん紹介されているため省略します。。。
- 最終的には以下のようなグラフ表示が出せます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/c2030b5a-ff4b-97f7-dd5f-f5c6320217c2.png)

# 最終的な設定ファイル
最終的な設定ファイルは以下となります
## Telegraf
/etc/telegraf/telegraf.conf

<details><summary>telegraf.conf</summary>
<div>

```:telegraf.conf 設定内容
[agent]

  interval = "10s"		# データを収集する間隔
  round_interval = true		# [true] の場合 収集時間は :00, :10, :20 ...
  metric_batch_size = 1000	# バッチ処理で Outoput に送信する際のメトリクスサイズ
  metric_buffer_limit = 10000	# 使用するメモリーの上限値
  collection_jitter = "0s"	# メトリクス収集の遅延時間 - 各プラグインがメトリクス収集の際に設定値の範囲内でスリープ
  flush_interval = "10s"	# Output データを出力する間隔
  flush_jitter = "0s"		# データを出力する際の遅延時間
  precision = "0s"

  logfile = "/var/log/telegraf/telegraf.log"	# ログファイルのパス
  logtarget = "file"		# 出力先: "file", "stderr", "stdout"

  # デバッグ時に有効にする
  #debug = true

# ------------------------------------------------------------------------------------------------------------------------
#
# Telemetry (JUNOS-EVO)
#
# ------------------------------------------------------------------------------------------------------------------------

[[inputs.socket_listener]]
  service_address = "udp://:20000"

  data_format = "xpath_protobuf"
  xpath_protobuf_files = ["telemetry_top.proto",
                          "aftman-cos-oc_ifl_render.proto",
                          #"aftman-cos-oc_render.proto",
                          "aftman-npu-mem-oc_render.proto",
                          "aftman-npu-util-oc_render.proto",
                          "aftman-qos-voqmon-stats-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-ingress-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-ingress-udp-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-transit-oc_render.proto",
                          #"aftman-sensor-ldp-lsp-transit-udp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-lsp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-lsp-udp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-egress-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-egress-udp-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-ingress-oc_render.proto",
                          #"aftman-sensor-ldp-p2mp-per-if-ingress-udp-oc_render.proto",
                          #"aftman-sensor-lsp-ni-oc_render.proto",
                          #"aftman-sensor-lsp-oc_render.proto",
                          #"aftman-sensor-lsp-udp-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv4-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv4-udp-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv6-oc_render.proto",
                          #"aftman-sensor-per-prefix-ipv6-udp-oc_render.proto",
                          #"aftman-sensor-sr-egress-interface-openconfig_oc_render.proto",
                          #"aftman-sensor-sr-egress-interface_oc_render.proto",
                          #"aftman-sensor-sr-ingress-interface-openconfig_oc_render.proto",
                          #"aftman-sensor-sr-ingress-interface_oc_render.proto",
                          #"aftman-sensor-sr-sid_egress_oc_render.proto",
                          #"aftman-sensor-sr-sid_ingress_oc_render.proto",
                          #"aftman-sensor-sr-sid_ingress_openconfig_oc_render.proto",
                          #"aftman-sensor-srte-bsid-oc_render.proto",
                          #"aftman-sensor-srte-bsid-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-bsid-udp-oc_render.proto",
                          #"aftman-sensor-srte-ingress-tunnel-oc_render.proto",
                          #"aftman-sensor-srte-ingress-tunnel-udp-oc_render.proto",
                          #"aftman-sensor-srte-ip-oc_render.proto",
                          #"aftman-sensor-srte-ip-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-ip-udp-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-ingress-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-ingress-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-ingress-udp-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-transit-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-transit-openconfig-oc_render.proto",
                          #"aftman-sensor-srte-per-lsp-transit-udp-oc_render.proto",
                          #"aftman-sensor-srte-transit-tunnel-oc_render.proto",
                          #"aftman-sensor-srte-transit-tunnel-udp-oc_render.proto",
                          "aftsysinfo-oc_render.proto",
                          "agent.proto",
                          "alarmd_oc_render.proto",
                          "am-cos-egress-qstat-oc_render.proto",
                          #"am-cos-egress-qstat-udp-oc_render.proto",
                          "am-cos-interfaceset-stats_render.proto",
                          "am-cos-intf-qstat-ext-oc_render.proto",
                          "am-ddos-oc_render.proto",
                          "am-dfw-oc-render.proto",
                          "am-ic-pfe-oc_render.proto",
                          "am-if-oc_render.proto",
                          "am-if-udp-oc_render.proto",
                          "am-ifl-udp-oc_render.proto",
                          #"am-ifl-v4-udp-oc_render.proto",
                          #"am-ifl-v6-udp-oc_render.proto",
                          "am-intf-exp-udp-oc_render.proto",
                          "am-jflowui-udp-oc_render.proto",
                          "am-pfe-oc_render.proto",
                          "bfdd-junos-openconfig-bfd-render.proto",
                          #"brcm-cos-qstat-oc_render.proto",
                          #"brcm-host-interface-pipestats-oc_render.proto",
                          #"brcm-if-oc_render.proto",
                          #"brcm-interface-pipestats-oc_render.proto",
                          #"brcm-pfe-oc_render.proto",
                          #"brcm-pfe-udp_render.proto",
                          "cda-btchip-ic-npu-util-oc_render.proto",
                          #"cda-btchip-npu-util-oc_render.proto",
                          "cda-bxchip-npu-util-oc_render.proto",
                          "cda-bxchip-stats-oc_render.proto",
                          "cda-drop-lookup-pipestats-oc_render.proto",
                          "cda-drop-state-pipestats-oc_render.proto",
                          "cda-expr_pipestats-oc_render.proto",
                          "cda-pkt-lookup-pipestats-oc_render.proto",
                          #"cda-zephyr-stats-oc_render.proto",
                          "cda-zxchip-npu-util-oc_render.proto",
                          "cda-zxchip-stats-oc_render.proto",
                          "cfmd-junos-state-oam-cfm-render.proto",
                          #"cmevod-fpcenv-oc_render.proto",
                          "cosd_oc_evo.proto",
                          "ddosd-junos-state-ddos-protection-render.proto",
                          "dot1xd-junos-openconfig-if-8021x-render.proto",
                          "dot1xd-junos-state-dot1x-render.proto",
                          "dot1xd_oc.proto",
                          "ehmd_comp_oc.proto",
                          "ehmd_oc.proto",
                          "ehmd_system_chassis_native.proto",
                          "ehmd_system_oc.proto",
                          "evo-if-oc_render.proto",
                          "evo-interface-pipestats-oc_render.proto",
                          "evo-pkt-host-interface-pipestats-oc_render.proto",
                          "fabricHub_oc.proto",
                          "fabspoked-fchip-junos-openconfig-platform-render.proto",
                          "fabspoked-pfe-junos-openconfig-platform-pipeline-counters-render.proto",
                          "fibtd-junos-state-anomalies-fib-render.proto",
                          "fibtd-telemetry_oc.proto",
                          "fwstatsd_oc_evo_state.proto",
                          "fwstatsd_oc_ni.proto",
                          "gnmi.proto",
                          "GnmiJuniperTelemetryHeader.proto",
                          "GnmiJuniperTelemetryHeaderExtension.proto",
                          "gnmi_dialout.proto",
                          "gnmi_ext.proto",
                          "hwdfpc_oc.proto",
                          "hwdre-evo-openconfig-system-render.proto",
                          "hwdre-healthz-oc_render.proto",
                          "hwdre-junos-state-health-render.proto",
                          "hwdre_fpc_env.proto",
                          "hwdre_oc.proto",
                          "jexpr-drop-host-interface-pipestats-oc_render.proto",
                          "jexpr-ic-npu-mem-oc_render.proto",
                          "jexpr-junos-integrated_circuit-oc_render.proto",
                          "jexpr-junos-npu-pipeline-resource-util-oc_render.proto",
                          "jexpr-npu-mem-oc_render.proto",
                          "jexpr-pkt-lookup-pipestats-oc_render.proto",
                          "jsd-junos-state-grpc.proto",
                          "jsd_health_oc.proto",
                          "junos-pfe-npu-render.proto",
                          "junos-xmlproxyd_junos-rsvp-interface.proto",
                          "junos-xmlproxyd_junos-rtg-task-memory.proto",
                          "junos_state_interface_render.proto",
                          "l2ald_bd_render.proto",
                          "l2ald_evpn_render.proto",
                          "l2ald_fdb_render.proto",
                          "l2ald_oc.proto",
                          "l2ald_oc_intf.proto",
                          "l2cpd-junos-state-lldp-render.proto",
                          "l2cpd_oc.proto",
                          "l2cpd_stp_oc.proto",
                          "lacpd_oc.proto",
                          "license-check-features-oc.proto",
                          "master-eventd-state-system-syslog.proto",
                          "master-eventd_oc.proto",
                          "mgmt-ethd_oc_evo_intf_stats.proto",
                          "mib2d_native_evo_intf_state.proto",
                          "mib2d_oc_evo_intf_state.proto",
                          "na-grpcd-junos-state-gnmi.proto",
                          "na-grpcd_stats_oc.proto",
                          "oc_component_render.proto",
                          #"oc_interface_render.proto",
                          "oc_optics_render.proto",
                          "pfe_page_drop_oc.proto",
                          "picd_oc_component_render.proto",
                          "platformd-fabric-oc_render.proto",
                          "resiliencyd-cmerror_cfg-oc_render.proto",
                          "resiliencyd-cmerror_cfg-udp-oc_render.proto",
                          #"resiliencyd-cmerror_stats-oc_render.proto",
                          "resiliencyd-cmerror_stats-udp-oc_render.proto",
                          "resiliencyd-comp_ic_pipeline_errcnt-oc_render.proto",
                          "rmopd_native_sensors_render.proto",
                          "rmopd_probe_oc_render.proto",
                          "rpd-junos-openconfig-ospfv2-render.proto",
                          "rpd_bgp_junos_route_validation.proto",
                          "rpd_bgp_junos_state.proto",
                          "rpd_bgp_rib_oc.proto",
                          "rpd_evpn_global_render.proto",
                          "rpd_evpn_instance_junos_state.proto",
                          "rpd_evpn_rib_oc.proto",
                          "rpd_gribi_stats_oc.proto",
                          "rpd_if_ipv6_ra_oc.proto",
                          "rpd_igmp_oc.proto",
                          "rpd_ipv6_ra_oc.proto",
                          "rpd_isis_oc.proto",
                          "rpd_ldp_oc.proto",
                          "rpd_ni_bgp_oc.proto",
                          "rpd_ni_evpn_render.proto",
                          "rpd_ni_oc.proto",
                          "rpd_pim_oc.proto",
                          "rpd_policy_oc.proto",
                          "rpd_resiliency_interface.proto",
                          "rpd_rsvp_oc.proto",
                          "rpd_srte_policy_oc.proto",
                          "rpd_te_oc.proto",
                          "svcsd_sflow_oc.proto",
                          "svcsd_sflow_openconfig.proto",
                          "sysd-evo-openconfig-system-render.proto",
                          "vrrpd_oc.proto",
                          "xmlproxyd-junos-commit-entries-render.proto",
                          "xmlproxyd-junos-openconfig-system-commit-render.proto",
                          "xmlproxyd-junos-openconfig-system-render.proto"]

  xpath_protobuf_type = "TelemetryStream"
  xpath_protobuf_import_paths = ["/usr/include/protos/junos-evo"]
  xpath_native_types = true

  [[inputs.socket_listener.xpath]]
    field_selection = "//*"
    field_name_expansion = false
    timestamp = "//timestamp"
    timestamp_format = "unix_ns"

    metric_name = "string('telemetry_junos_evo')"


#-------------------------------------------------------------------------------------

# Starlarkプロセッサでメトリクスを編集 ('telemetry_junos_evo')
[[processors.starlark]]

namepass = ["telemetry_junos_evo"] # 「telemetry_junos_evo」のみ処理させる

source = '''

fieldpass = ["system_id", "name*", "in_octets*"]

def apply(metric):

    ## デバッグ用
    #return metric

    # ホストネームとIPを取得
    SYSTEM_ID = metric.fields["system_id"]
      #string = "vJunosEvolved:10.99.0.2"

    PARTS = SYSTEM_ID.split(":")
    NUM_ELEMENTS = len(PARTS)

    if NUM_ELEMENTS == 2:
        HOST_NAME = PARTS[0]
        HOST_IP = PARTS[1]

    elif NUM_ELEMENTS == 1:
        HOST_NAME = PARTS[0]
        HOST_IP = ""
    else:
        HOST_NAME = ""
        HOST_IP = ""

    # 新しいメトリクスを保存するリスト
    RETURN_METRICS = []
    MAX_INDEX = 10000  # 最大インデックスの設定

    #-------------------------------------------------------------------------------------
    # 必要なフィールドがあるかチェックし、複数IFの1行をIF毎に1行に分解する
    FIELDS_NAME = "in_octets"
    HAS_BASE_FIELDS = FIELDS_NAME in metric.fields

    # 基本フィールド (index がない場合) の処理
    if HAS_BASE_FIELDS:
        ADD_METRIC = []
        ADD_METRIC = Metric("telemetry_junos_evo")
        ADD_METRIC.tags["name"] = metric.fields["name"]
        ADD_METRIC.tags["hostip"] = HOST_IP
        ADD_METRIC.tags["hostname"] = HOST_NAME
        ADD_METRIC.fields[FIELDS_NAME] = metric.fields[FIELDS_NAME]
        RETURN_METRICS.append(ADD_METRIC)

    # インデックス付きフィールドを処理
    for INDEX in range(MAX_INDEX):  # MAX_INDEX までのループ
        IF_INDEX = INDEX + 1
        CHECK_IF_NAME = "name_" + str(IF_INDEX)
        CHECK_IF_DATA = FIELDS_NAME + "_" + str(IF_INDEX)

        # 必要なフィールドがあるかチェック
        HAS_BASE_FIELDS = CHECK_IF_DATA in metric.fields

        if HAS_BASE_FIELDS:
            ADD_METRIC = []
            ADD_METRIC = Metric("telemetry_junos_evo")
            ADD_METRIC.tags["name"] = metric.fields[CHECK_IF_NAME]
            ADD_METRIC.tags["hostip"] = HOST_IP
            ADD_METRIC.tags["hostname"] = HOST_NAME
            ADD_METRIC.fields[FIELDS_NAME] = metric.fields[CHECK_IF_DATA]
            RETURN_METRICS.append(ADD_METRIC)
        else:
            # フィールドが無ければforのloopを終了
            break

    #-------------------------------------------------------------------------------------

    # 生成されたメトリクスを返す
    return RETURN_METRICS

'''

#-------------------------------------------------------------------------------------


## デバッグ用
#[[outputs.file]]
#  files = ["/var/log/telegraf/metrics.json"]
#  data_format = "json"
#  namepass = ["telemetry_junos_evo"]  # メトリック名でフィルタリング


#===================================================================================


# ------------------------------------------------------------------------------------------------------------------------
#
# Prometheusへの出力
#
# ------------------------------------------------------------------------------------------------------------------------

[[outputs.prometheus_client]]
  listen = ":9273" # 9237ポートでprometheusと連携
  collectors_exclude = ["gocollector", "process"]  # デフォルトで利用される"gocollector", "process"は除外
  namepass = ["telemetry_junos_evo"]  # メトリック名でフィルタリング


```
</div></details>


## Prometheus
/etc/prometheus/prometheus.yml

<details><summary>prometheus.yml</summary>
<div>

```:prometheus.yml 設定内容
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.

scrape_configs:
  - job_name: telegraf
    static_configs:
      - targets:
        - localhost:9273

```
</div></details>


# 最後に
Telegrafを利用して、JuniperのJUNOS-EVOの Dial-OutのTelemetryデータの収集・可視化まで確認できました。
今回はUDPでのTelemetryで確認しましたが、UDP以外にgRPCにもJUNOSは対応していて他社もgRPCの実装も多いみたいなので、次はgRPCのDial-OutなTelemetryもやってみたい

(2025/04/06 追記)
gRPCのDial-OutなTelemetryもやってみました

https://qiita.com/k-maki/items/19c6b383fb1eb8f0690d