JSONを使用したグラフ表示入門

グラフエディターの設定には、GUI(デフォルトの手法)とJSONの記述(より完全な手法)の2種類があります。このページではJSON形式を使用した手法について解説します。GUIでの設定については、グラフ表示入門を参照して下さい。

JSONエディターを使用したグラフ表示

JSON書式の構文

グラフを定義する言語は、JSON形式を採用し、次の4つの要素で構成されています:

  1. Requests (メトリクスの時系列データ(Series)のクエリ)
  2. Events (イベントのクエリ)
  3. Visualization (timeseries;時系列データの折れ線グラフやheatmap;ヒートマップなどグラフ形式の指定)
  4. Y Axis (Y軸の範囲やフィルタ、線形や対数などスケールの指定)

以下はこれらの要素が、1つのJSON書式で表現された例です:

{
  "requests": [
    {
      "q": "metric{scope}"
    }
  ],
  "events": [
    {
      "q": "search query"
    }
  ],
  "viz": "visualization type",
  "yaxis": {
    "yaxisoptionkey": "yaxisoptionvalue"
  }
}

JSON書式の一番外側のカッコ内に、先の要素が下記のエントリーとして記述されています:

  1. “requests” *
  2. “events”
  3. “viz” *
  4. “yaxis”

“requests”と”viz”は必ず指定する必要があります。

Requests (メトリクスの時系列データ, Series)

時系列データのクエリは、次のフォーマットになります:

"requests": [
    {
      "q": "function(aggregation method:metric{scope} [by {group}])"
    }
]

functiongroupの部分は、省略することができます。

時系列データは、バイナリー演算子(+, -, /, *)を使うことで、組み合わせて表示することができるようになります:

metric{scope} [by {group}] operator metric{scope} [by {group}]

関数

それぞれのクエリの結果に対して関数を適用することができます。

これらの関数のうち、いくつかについては具体的な設定例を用いた解説があります。こちらも併せて参照して下さい: Examples for Graphing Functions 本ドキュメントの最後にもいくつかの具体的な“設定例”があります。

Function Category Description
abs() Arithmetic absolute value
log2() Arithmetic base-2 logarithm
log10() Arithmetic base-10 logarithm
cumsum() Arithmetic cumulative sum over visible time window
integral() Arithmetic cumulative sum of ([time delta] x [value delta]) over all consecutive pairs of points in the visible time window
.fill() Interpolation choose how to interpolate missing values
hour_before() Timeshift metric values from one hour ago
day_before() Timeshift metric values from one day ago
week_before() Timeshift metric values from one week ago
month_before() Timeshift metric values from one month ago
per_second() Rate the rate at which the metric changes per second
per_minute() Rate per_second() * 60
per_hour() Rate per_second() * 3600
dt() Rate time delta between points
diff() Rate value delta between points
derivative() Rate 1st order derivative; diff() / dt()
ewma_3() Smoothing exponentially weighted moving average with a span of 3
ewma_5() Smoothing EWMA with a span of 5
ewma_10() Smoothing EWMA with a span of 10
ewma_20() Smoothing EWMA with a span of 20
median_3() Smoothing rolling median with a span of 3
median_5() Smoothing rolling median with a span of 5
median_7() Smoothing rolling median with a span of 7
median_9() Smoothing rolling median with a span of 9
.rollup() Rollup override default time aggregation type and time period; see the “Rollup” section below for details
count_nonzero() Count count all the non-zero values
count_not_null() Count count all the non-null values
top() Rank select the top series responsive to a given query, according to some ranking method; see the “Top functions” section below for more details
top_offset() Rank similar to top(), except with an additional offset parameter, which controls where in the ordered sequence of series the graphing starts. For example, an offset of 2 would start graphing at the number 3 ranked series, according to the chosen ranking metric.
robust_trend() Regression fit a robust regression trend line using Huber loss; see the “Robust regression” section below for more details
trend_line() Regression fit an ordinary least squares regression line through the metric values
piecewise_constant() Regression approximate the metric with a piecewise function composed of constant-valued segments
anomalies() Algorithms overlay a gray band showing the expected behavior of a series based on past behavior; see our guide to anomaly detection
outliers() Algorithms highlight outlier series; see our guide to outlier detection

.as_count() & .as_rate()

These functions are only intended for metrics submitted as rates or counters via statsd. These functions will have no effect for other metric types. For more on details about how to use .as_count() and .as_rate() please see our blog post.

Rollup

.rollup() is recommended for expert users only. Appending this function to the end of a query allows you to control the number of raw points rolled up into a single point plotted on the graph. The function takes two parameters, method and time: .rollup(method,time)

The method can be sum/min/max/count/avg and time is in seconds. You can use either one individually, or both together like .rollup(sum,120). We impose a limit of 350 points per time range. For example, if you’re requesting .rollup(20) for a month-long window, we will return data at a rollup far greater than 20 seconds in order to prevent returning a gigantic number of points.

Top functions

  • a metric query string with some grouping, e.g. avg:system.cpu.idle{*} by {host}
  • the number of series to be displayed, as an integer.
  • one of 'max', 'min', 'last', 'l2norm', or 'area'. 'area' is the signed area under the curve being graphed, which can be negative. 'l2norm' uses the L2 Norm of the time series, which is always positive, to rank the series.
  • either 'desc' (rank the results in descending order) or 'asc' (ascending order).

The top() method also has convenience functions of the following form, all of which take a single series list as input:

[top, bottom][5, 10, 15, 20]_[mean, min, max, last, area, l2norm]()

For example, bottom10_min() retrieves lowest-valued 10 series using the ‘min’ metric.

Robust regression

The most common type of linear regression – ordinary least squares (OLS) – can be heavily influenced by a small number of points with extreme values. Robust regression is an alternative method for fitting a regression line; it is not influenced as strongly by a small number of extreme values. As an example, see the following plot.

{{ partial “img.html” (dict “root” . “src” “robust-trend.png”) }}

The original metric is shown as a solid blue line. The purple dashed line is an OLS regression line, and the yellow dashed line is a robust regression line. The one short-lived spike in the metric leads to the OLS regression line trending upward, but the robust regression line ignores the spike and does a better job fitting the overall trend in the metric.

この他にも、クエリ結果に適用する上級者向けの関数が幾つかあります。

上級者向けの関数の一つが.rollup()です。この関数をクエリに追記することで、複数のポイントを単一ポイントにまとめることができます。この関数は、”メソッド”と”時間”の2つのパラメータを引数に指定することができます。(例: .rollup(method,time))

“メソッド”の部分には、sum/min/max/count/avgを指定することができます。”時間”は、秒単位で指定します。 “メソッド”と”時間”は、個別に指定(例: .rollup(20))したり、両方を組み合わせて(例: .rollup(sum,120))も指定できます。 この.rollup()には、チェック機構があります。 しかしDatadogのグラフでは表示する時間の範囲に基づき350のデータポイントまでしか保有していないので、期間指定を一ヶ月にした場合は、20秒間隔以上の精度でデータポイントが保有されているため、20秒でのロールアップ.rollup(20)は、機能しません。

特定の方法で提出されたメトリクスためのもう一つの上級者向け関数が、.as_count().as_rate() です。 現状、DogStatsDの”rate”, “counter”を使って送信したメトリクスには、.as_count().as_rate()を使うことができますが、”gauges”などのそれ以外のメトリクスでは機能しません。

as_count()に関する詳しい情報は、“Visualize StatsD metrics with Counts Graphing”のブログを参照してください。

データポイントの集計

多くの場合、利用可能なデータポイントの数は画面に表示可能なデータポイントの数を上回ります。これに対応するため、データポイントは4つの集計方法{average, max, min, sum}の1つにより集計されています。

メトリクスの確認

メトリクスはグラフ表示の要です。現在利用可能なメトリクスは Metrics Summary にてリスト表示することができます。各メトリクスをクリックしてそのメトリクスがどのようなデータを取得しているか、あるいはタグやホストなどの関連する詳しい情報を確認します。

対象範囲の指定(Scope, スコープ)

スコープを指定することで時系列データの対象範囲を限定することができます。スコープでは、ホスト名やホスト上のデバイス、更に英数文字列 ([a-zA-Z1-9:_]+)のタグが付与された情報を指定することができます。

範囲指定の例 (カッコ内は、対象範囲の解説):

host:my_host                      (指定されたホスト名に関連した情報)
host:my_host, device:my_device    (指定されたホスト名の指定されたデバイスに関連した情報)
source:my_source                  (指定された情報ソースに関連した情報)
my_tag                            (my_tagで指定されたグループに関連する情報)
my:tag                            (同上)
*                                 (ワイルドカード)

グループの指定

どのメトリクスにおいても、複数のホストからのデータによって構成され得ています。そうしたデータは通常、時間間隔ごとにすべてのホストからのデータが単一の値に集計されますが、あらゆるタグによってデータを分離して取得することができます。あるメトリクスに対してホストごとにデータポイントを分けて見たい場合、{host}グループの指定を行います。

演算子の利用

時系列データには、簡単な演算( +, -, *, / )を適用することができます。 次の例では、5分間のload averageの値とその倍の数値をグラフ表示することにします:

{
  "viz": "timeseries",
  "requests": [
    {
      "q": "system.load.5{intake} * 2"
    },
    {
      "q": "system.load.5{intake}"
    }
  ]
}

時系列データ同士を、加算 減算 乗算 除算することもできます。 Datadogでは、ここでは一貫性を強制していないので、*異なるものの除算をすることもできます*。

{
    "viz": "timeseries",
    "requests": [
      {
        "q": "metric{apples} / metric{oranges}"
      }
    ]
}

イベントの表示

Datadogに保存したイベント情報は、次の書式で記述することでグラフにオーバーレイすることができます:

"events": [
  {
    "q": "search query"
  }
]

例えば、ホスト”X”のタグ”Y”が付いたイベントをオーバーレイする場合は:

"events": [
  {
    "q": "host:X tags:Y"
  }
]

エラーにステータスをオーバーレイする場合は:

"events": [
  {
    "q": "status:error"
  }
]

グラフによる可視化

データポイントを可視化するグラフ形式にはいくつかの種類があります:

  1. Time Series (時系列データのグラフ)
  2. Heatmap (ヒートマップ, 指定したスコープ内でのメトリクスの時系列分布)
  3. Distribution (分布図, 指定したスコープ内での特定の時間枠のメトリクスの分布)
  4. Toplist (トップリスト, 指定したスコープ内でのメトリクスのランキング)
  5. Change (チェンジグラフ, 一定時間前とのメトリクスの変化量を示すグラフ)
  6. Hostmap (ホストマップ)

さらに、Time Series (時系列データのグラフ)では下記のグラフ形式が選択できます:

  1. 折れ線グラフ
  2. 積み上げグラフ
  3. slice-n-stackグラフ
  4. 棒グラフ

折れ線グラフ

このグラフ表現は、requests部に複数の検索クエリを有する場合に自動的に設定されます。

"requests": [
    {
      "q": "metric1{scope}"
    },
    {
      "q": "metric2{scope}"
    },
    {
      "q": "metric3{scope}"
    }
  ]

これにより、複数の時系列データのグラフを重ね合わせて表示することができます。

積み上げグラフ

関連している時系列データの場合は、次の構文を記述し積み上げグラフを表示することができます:

"requests": [
    {
      "q": "metric1{scope}, metric2{scope}, metric3{scope}"
    }
]

チャート毎に1つのクエリを表示する代わりに”,“ですべてのクエリを連結することによって、全てのクエリを1つのグラフに積み上げて表示することができます。

Slice-n-Stack

異なるホストにまたがるメトリクスを積み上げた結果のグラフが有益な場合もあります。例えば、複数のホストに共通して付されているタグを選択し、それらのホストのネットワークトラフィックの出入りをホスト毎に積み上げたグラフを見てみたいとします。このようなグラフは、ネットワークトラフィックの中で異常が発生していることを発見するのに便利です。

この例は、次のように記述します:

"requests" [
  {
     "q": "system.net.bytes_rcvd{some_tag, device:eth0} by {host}"
  }
]

このケースでは、クエリは1つしか発行できないことに注目してください。 しかしながら、デバイス単位やホストとデバイスの組み合わせを基準としてスライスすることもできます:

"requests" [
  {
     "q": "system.net.bytes_rcvd{some_tag} by {host,device}"
  }
]

全てのタグ付けされたホストから、ホストとネットワークデバイスでスライスし、積み上げたグラフを表示します。

Y軸の操作

グラフエディターからJSONを編集することで次のようなY軸の制御ができます:

  • Y軸の表示範囲の指定
  • パーセンテージか絶対値のいずれかを指定することより時系列データをフィルタ
  • Y軸の目盛りを線形スケールから対数スケールや指数スケールへ変更

Y軸を設定するために次の3のオプションがあります:

  • min (オプション): Y軸に表示する最小値を指定します。 ここでは、数値か”auto”を指定することができます。デフォルト値は、”auto”です。
  • max (オプション): Y軸に表示する最大値を指定します。 ここでは、数値か”auto”を指定することができます。デフォルト値は、”auto”です。
  • scale (オプション): Y軸の目盛りのタイプを指定します。 指定できる値は、”linear”, “log”, “sqrt”, “pow##”(例. pow2, pow0.5)です。デフォルト値は、”linear”です。

Examples:

"yaxis": {
    "min": "auto",
    "max": 200,
    "scale": "log"
}

"yaxis": {
    "min": 200,
    "scale": "sqrt"
}

"yaxis": {
    "min": 9000,
    "max": 10000
}

"yaxis": {
    "scale": "pow0.1"
}

"yaxis": {
    "scale": "pow3"
}

"yaxis": {
    "units": "true"
}

Y軸のフィルタリング

Y軸にフィルタリングの閾値を定義することにより、Y軸の上下限を自動的に変更することができます。 閾値には、パーセンテージまたは絶対値を指定することができます。 この閾値は、グラフの上限と下限の両方に設定することができます。

Y軸のフィルタリングの定義には、2つの設定方法があります。

1つは、絶対値を指定しその値を超えているメトリクスの値をフィルタして除去する方法です。もう一方は、パーセンテージを指定し、トップから指定したパーセンテージまでの値をフィルタして除去する方法です。

Examples:

"yaxis": {
    "filter": 30 // 値が30以上のデータポイントは除去され、表示されません
}

"yaxis": {
    "filter": "5%" // 上位5%の値をもったデータポイントは除去され、表示されません
}

高度な設定も、シンプルな設定ど同じような概念で進めることができます。 高度な設定では、グラフの下限,上限,その両方の設定がより柔軟にコントロールできるようになっています。 例えば、次のグラフ設定では、下限10%以上で、上限30%以下のデータポイントのみグラフ表示されるようにフィルタしています。

"yaxis": {
    "filter": {
        "top": "30%",
        "bottom": "10%"
    }
}

次は、値が15以上のデータポイント除去します:

"yaxis": {
    "filter": {
        "above": 15
    }
}

次は、値が2以下のデータポイント除去します:

"yaxis": {
    "filter": {
        "below": 2
    }
}

すべての要素を含んだJSON表記の例です:

{
  "viz": "timeseries",
  "requests": [
    {
      "q": "system.cpu.idle{host:hostname}",
      "stacked": false
    }
  ],
  "events": [],
  "yaxis": {
    "scale": "log"
    "filter": {
         "top": "5%",
         "below": 15
     }
  },
}

設定例

パラメーターに1つのメトリクスを指定したrate()関数を使った例です。top()top_offset()以外の関数では、このrate()と同様のシンタックス表記を利用することできます。

{
  "viz": "timeseries",
  "requests": [
    {
      "q": "rate(sum:system.load.5{role:intake-backend2} by {host})",
      "stacked": false
    }
  ]
}

top() 関数を使用した例:

{
  "viz": "timeseries",
  "requests": [
    {
      "q": "top(avg:system.cpu.iowait{*} by {host}, 5, 'max', 'desc')",
      "stacked": false
    }
  ]
}

この例では、system.cpu.iowaitのピーク値の上位5位をグラフに表示します。

system.cpu.iowaitのピーク値ランキングの第6位から10位のホストを表示するためには、top_offsetを使います:

{
  "viz": "timeseries",
  "requests": [
    {
      "q": "top_offset(avg:system.cpu.iowait{*} by {host}, 5, 'max', 'desc', 5)",
      "stacked": false
    }
  ]
}

week_before()関数を使用した例:

{
  "viz": "timeseries",
  "requests": [
    {
      "q": "sum:haproxy.count_per_status{status:available} - week_before(sum:haproxy.count_per_status{status:available})"
    }
  ]
}