パネルのサンプルコード

このページには Grafonnet で定義する Grafana 用のパネルのサンプルコードについて書いてあります。

Prometheus Node Exporter 用パネル #

グラフ #

CPU 使用率 #

CPU usage

local cpuUsage = 
    grafana.graphPanel.new(
        title='CPU usage',
        format='percent',
        fill=7,
        max=100,
        min=0,
        stack=true,
    )
    .addTarget(
        grafana.prometheus.target('sum(rate(node_cpu_seconds_total{mode!="idle"}[$__interval])) by (mode) * 100'),
    );

CPU 使用率は、次の項目ごとに取得されます。すべてを合計すると 100% になるため、上記は idle 以外を表示する例です。

  • ユーザー (user)
  • システム (system)
  • 優先度付きプロセス (nice)
  • ハードウェア割込み (irq)
  • ソフトウェア割込み (softirq)
  • IO 待ちプロセス (iowait)
  • steal 時間 (steal)
  • アイドル時間 (idle)

メモリー容量使用率 #

memory usage

local memoryUsage = 
    grafana.graphPanel.new(
        title='Memory usage',
        format='bytes',
        fill=2,
        fillGradient=4,
        linewidth=3,
        min=0,
        legend_values=true,
        legend_current=true,
    )
    .addTargets([
        grafana.prometheus.target('node_memory_MemTotal_bytes', legendFormat='Available'),
        grafana.prometheus.target('node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes', legendFormat='Used'),
    ]);

ディスク容量使用率 #

disk usage

local diskUsage = 
    grafana.graphPanel.new(
        title='Disk usage',
        format='bytes',
        fill=2,
        fillGradient=4,
        linewidth=3,
        min=0,
        legend_values=true,
        legend_current=true,
    )
    .addTargets([
        grafana.prometheus.target('max(node_filesystem_avail_bytes{fstype=~"ext.?|xfs"} + node_filesystem_size_bytes{fstype=~"ext.?|xfs"} - node_filesystem_free_bytes{fstype=~"ext.?|xfs"})', legendFormat='Available'),
        grafana.prometheus.target('max(node_filesystem_size_bytes{fstype=~"ext.?|xfs"} - node_filesystem_free_bytes{fstype=~"ext.?|xfs"})', legendFormat='Used'),
    ]);

1つのノードに複数のディスクデバイスや、複数のマウントポイントがあることもあります。 この例ではそのうちのディスク容量が最大のもののみを対象としています。 次以降のディスク関連のメトリックスはすべて同様に最大のもののみを対象にしています。

ディスク処理リクエスト発行時間 (await) #

disk await

local diskAwait = 
    grafana.graphPanel.new(
        title='Disk await',
        format='s',
        nullPointMode='null as zero',
        legend_values=true,
        legend_current=true,
        legend_max=true,
        legend_min=true,
        legend_avg=true,
        legend_alignAsTable=true,
        labelY1='Read (-) / Write (+)'
    )
    .addSeriesOverride({"alias": "Read", "transform": "negative-Y"})
    .addTargets([
        grafana.prometheus.target('max(rate(node_disk_write_time_seconds_total[$__interval]) / rate(node_disk_writes_completed_total[$__interval]))', legendFormat='Write'),
        grafana.prometheus.target('max(rate(node_disk_read_time_seconds_total[$__interval]) / rate(node_disk_reads_completed_total[$__interval]))', legendFormat='Read'),
    ]);

iostat の r_wait と w_await に相当するメトリクスです。 メトリックスの計算方法は こちら の記事参考にしているだけで、確からしさの検証はしておりません。

次以降の iostat に相当するメトリクスも同様上記サイトを参考にしております。

ディスクビジー率 (%util) #

disk util

local diskUtil = 
    grafana.graphPanel.new(
        title='Disk Util',
        format='percent',
        fill=2,
        fillGradient=4,
        linewidth=1,
        min=0,
        legend_values=true,
        legend_current=true,
        legend_max=true,
        legend_min=true,
        legend_avg=true,
        legend_alignAsTable=true,
    )
    .addTargets([
        grafana.prometheus.target('max(rate(node_disk_io_time_seconds_total[$__interval])) * 100', legendFormat='Disk util'),
    ]);

iostat の %util に相当するメトリクスです。

ディスク IOPS #

disk IOPS

local diskIOPS = 
    grafana.graphPanel.new(
        title='Disk I/O per second',
        fill=2,
        fillGradient=4,
        linewidth=1,
        min=0,
        legend_values=true,
        legend_current=true,
        legend_max=true,
        legend_min=true,
        legend_avg=true,
        legend_alignAsTable=true,
    )
    .addTargets([
        grafana.prometheus.target('max(rate(node_disk_reads_completed_total[$__interval]) + rate(node_disk_writes_completed_total[$__interval]))', legendFormat='IOPS'),
    ]);

iostat の tps (transfers per second、I/O per second) に相当するメトリクスです。

ネットワークトラフィック #

network traffic

local networkTraffic = 
    grafana.graphPanel.new(
        title='Network traffic',
        format='bps',
        fill=2,
        fillGradient=4,
        linewidth=1,
        nullPointMode='null as zero',
        legend_values=true,
        legend_current=true,
        legend_max=true,
        legend_min=true,
        legend_avg=true,
        legend_alignAsTable=true,
        labelY1='Receive (-) / Transmit (+)'
    )
    .addSeriesOverride({"alias": "Receive", "transform": "negative-Y"})
    .addTargets([
        grafana.prometheus.target('max(rate(node_network_transmit_bytes_total{device=~"^(eth|en|wlan|ww).*"}[$__interval])*8)', legendFormat='Transmit'),
        grafana.prometheus.target('max(rate(node_network_receive_bytes_total{device=~"^(eth|en|wlan|ww).*"}[$__interval])*8)', legendFormat='Receive'),
    ]);  

表示するネットワークインターフェースはインターフェース名が eth/en/wlan/ww で始まるもののうち最大のものとしています。 上記のインターフェース名は一般的に Debian 系の OS で使われる物理インターフェース名です。

テーブル #

ノード状態の一覧表 #

Prometheus に登録されているすべてのインスタンスに対して、これまでに紹介した上記のメトリクスなどの瞬時値を一覧表示したテーブルの例です。

overview

local overviewTable = 
    grafana.tablePanel.new(
        title='Overview',
        styles=[
            {
                alias: 'IP address',
                pattern: 'instance',
            },
            {
                alias: 'Hostname',
                pattern: 'nodename',
            },
            {
                alias: '# of cores',
                pattern: 'Value #B',
            },
            {
                alias: 'Memory',
                pattern: 'Value #C',
                type: 'number',
                unit: 'bytes',
            },
            {
                alias: 'Disk size',
                pattern: 'Value #D',
                type: 'number',
                unit: 'bytes',
            },              
            {
                alias: 'Uptime',
                pattern: 'Value #E',
                type: 'number',
                unit: 's',
            },
            {
                alias: 'Load',
                pattern: 'Value #F',
            },
            {
                alias: 'CPU usage',
                pattern: 'Value #G',
                type: 'number',
                unit: 'percent',
                colorMode: 'cell',
                colors: [
                    "rgba(50, 172, 45, 0.97)",
                    "rgba(237, 129, 40, 0.89)",
                    "rgba(245, 54, 54, 0.9)",
                ],
                thresholds: ["50", "80"],
            },
            {
                alias: 'Mem usage',
                pattern: 'Value #H',
                type: 'number',
                unit: 'percent',
                colorMode: 'cell',
                colors: [
                    "rgba(50, 172, 45, 0.97)",
                    "rgba(237, 129, 40, 0.89)",
                    "rgba(245, 54, 54, 0.9)",
                ],
                thresholds: ["50", "80"],
            },
            {
                alias: 'Disk usage',
                pattern: 'Value #I',
                type: 'number',
                unit: 'percent',
                colorMode: 'cell',
                colors: [
                    "rgba(50, 172, 45, 0.97)",
                    "rgba(237, 129, 40, 0.89)",
                    "rgba(245, 54, 54, 0.9)",
                ],
                thresholds: ["50", "80"],
            },              
            {
                alias: 'Disk read await ',
                pattern: 'Value #J',
                type: 'number',
                unit: 's',
                colorMode: 'cell',
                colors: [
                    "rgba(50, 172, 45, 0.97)",
                    "rgba(237, 129, 40, 0.89)",
                    "rgba(245, 54, 54, 0.9)",
                ],
                thresholds: ["10", "100"],
            },              
            {
                alias: 'Disk write await',
                pattern: 'Value #K',
                type: 'number',
                unit: 's',
                colorMode: 'cell',
                colors: [
                    "rgba(50, 172, 45, 0.97)",
                    "rgba(237, 129, 40, 0.89)",
                    "rgba(245, 54, 54, 0.9)",
                ],
                thresholds: ["10", "100"],
            },              
            {
                alias: 'Disk util',
                pattern: 'Value #L',
                type: 'number',
                unit: 'percent',
                colorMode: 'cell',
                colors: [
                    "rgba(50, 172, 45, 0.97)",
                    "rgba(237, 129, 40, 0.89)",
                    "rgba(245, 54, 54, 0.9)",
                ],
                thresholds: ["50", "80"],
            },              
            {
                alias: 'Rx traffic',
                pattern: 'Value #M',
                type: 'number',
                unit: 'bps',
                colorMode: 'cell',
                colors: [
                    "rgba(50, 172, 45, 0.97)",
                    "rgba(237, 129, 40, 0.89)",
                    "rgba(245, 54, 54, 0.9)",
                ],
                thresholds: ["10000000", "50000000"],
            },              
            {
                alias: 'Tx traffic',
                pattern: 'Value #N',
                type: 'number',
                unit: 'bps',
                colorMode: 'cell',
                colors: [
                    "rgba(50, 172, 45, 0.97)",
                    "rgba(237, 129, 40, 0.89)",
                    "rgba(245, 54, 54, 0.9)",
                ],
                thresholds: ["10000000", "50000000"],
            },              
        ],
    )
    .addTargets([
        grafana.prometheus.target(
            // Value #A
            expr='node_uname_info',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #B: Number of CPU cores
            expr='count(node_cpu_seconds_total{mode="system"}) by (instance)',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #C: Memory size
            expr='node_memory_MemTotal_bytes - 0',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #D: Disk size
            expr='max(node_filesystem_size_bytes) by (instance)',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #E: Uptime
            expr='sum(time() - node_boot_time_seconds) by (instance)',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #F: 5-min. Load
            expr='node_load5 - 0',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #G: CPU usage
            expr='sum(rate(node_cpu_seconds_total{mode=~"(user|system|nice|irq|softirq)"}[$__interval])) by (instance) * 100 / count(node_cpu_seconds_total{mode="user"}) by (instance)',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #H: Memory usage
            expr='(1 - (node_memory_MemAvailable_bytes / (node_memory_MemTotal_bytes))) * 100',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #I: Disk usage
            expr='max((node_filesystem_size_bytes{fstype=~"ext.?|xfs"} - node_filesystem_free_bytes{fstype=~"ext.?|xfs"}) * 100 / (node_filesystem_avail_bytes{fstype=~"ext.?|xfs"} + (node_filesystem_size_bytes{fstype=~"ext.?|xfs"} - node_filesystem_free_bytes{fstype=~"ext.?|xfs"}))) by (instance)',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #J: Disk await (read)
            expr='max(rate(node_disk_read_time_seconds_total[$__interval]) / rate(node_disk_reads_completed_total[$__interval])) by (instance)',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #K: Disk await (write)
            expr='max(rate(node_disk_write_time_seconds_total[$__interval]) / rate(node_disk_writes_completed_total[$__interval])) by (instance)',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #L: Disk util
            expr='max(rate(node_disk_io_time_seconds_total[$__interval]) * 100) by (instance)',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #M: Rx traffic (only physical NICs)
            expr='max(rate(node_network_receive_bytes_total{device=~"^(eth|en|wlan|ww).*"}[$__interval])*8) by (instance)',
            format='table',
            instant=true,
        ),
        grafana.prometheus.target(
            // Value #N: Tx traffic
            expr='max(rate(node_network_transmit_bytes_total{device=~"^(eth|en|wlan|ww).*"}[$__interval])*8) by (instance)',
            format='table',
            instant=true,
        ),
    ])
    .hideColumn('Time')
    .hideColumn('__name__')
    .hideColumn('domainname')
    .hideColumn('job')
    .hideColumn('machine')
    .hideColumn('release')
    .hideColumn('sysname')
    .hideColumn('version')
    .hideColumn('Value #A');

パネルのテンプレートととなる関数を作る #

同じフォーマットのパネルであれば、共通部分を関数として定義しておけば、少ないコードでパネルを定義できます。

たとえば、上で定義した Prometheus 用のメモリー容量使用率とディスク容量使用率のパネルのフォーマットは同じです。 これを共通関数として次のように定義できます。

local usageGraphTemplate(title, format, avail_query, used_query) = 
    grafana.graphPanel.new(
        title='%s' % title, 
        format='%s' % format,
        fill=2,
        fillGradient=4,
        linewidth=3,
        min=0,
        legend_values=true,
        legend_current=true,
    )
    .addTargets([
        grafana.prometheus.target('%s' % avail_query, legendFormat='Available'),
        grafana.prometheus.target('%s' % used_query, legendFormat='Used'),
    ]);

この関数を用いるとメモリー容量使用率とディスク容量使用率はそれぞれ次のように定義できます。

local memoryUsage = usageGraphTemplate(
    'Memoty usage', 
    'bytes', 
    'node_memory_MemTotal_bytes{instance="$instance"}',
    'node_memory_MemTotal_bytes{instance="$instance"} - node_memory_MemAvailable_bytes{instance="$instance"}');

local diskUsage = usageGraphTemplate(
    'Disk usage', 
    'bytes', 
    'max(node_filesystem_avail_bytes{fstype=~"ext.?|xfs", instance="$instance"} + node_filesystem_size_bytes{fstype=~"ext.?|xfs", instance="$instance"} - node_filesystem_free_bytes{fstype=~"ext.?|xfs", instance="$instance"})',
    'max(node_filesystem_size_bytes{fstype=~"ext.?|xfs", instance="$instance"} - node_filesystem_free_bytes{fstype=~"ext.?|xfs", instance="$instance"})');