2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Cloudflare GraphQL API からトラフィック量を過去1年に遡って集計する

Last updated at Posted at 2022-10-13

Cloudflare の Analytics データ

Cloudflare Analytics では、以下のようにダッシュボードで確認できるデータを提供しています。

そのデータは GraphQL Analytics API を使って取り出すことができます。

利用可能な Datasets の中には、ダッシュボードで確認することができない(UI 未実装や Beta の)ものもあり、活用できるデータの宝庫になっています。

image-20221014011807952

ログとの違い

では Cloudflare Logs との違いはどこにあるのでしょうか。

Analytics データは

  • Sampling される可能性があります。Adaptive と名の付くデータセットは動的にサンプリングレートが調整され、サンプルデータから全体を推測する倍率をかけたデータとなります。一方でログはユーザ自身でサンプリングを制御でき、すべてのデータにアクセスが可能です。
  • 集計データが提供されます。Groups と名の付くデータセットは、すでに集計された形でデータ提供されるため、ログから集計する手間が省ける点で便利なことがあります。

Analytics データ保持期間

Limits · Cloudflare Analytics docs」にある通り、データセットやプランによってデータ保持期間が変わってきます。

Cloudflare GraphQL データセットの保管期間を確認する - Qiita
以前はこのような保管期間がドキュメントで公開されていましたが、現時点ではドキュメントで確認できないため、自身で該当データを取得し、確認する必要があります。

その中でも、特に httpRequests1dGroups は過去1年に遡って確認できる集計データとして活用の余地があります。

また、データセットとして対応していても、ダッシュボードで遡れるデータ範囲も限られている(+ UI であまり遡ると取得に時間がかかることもある)ため、GraphQL API を使ってデータを取得することで最大限の活用が可能です。

image-20221014013347556

httpRequests1dGroups の取得例

以下の変数をセットし

export GQL_ENDPOINT='https://api.cloudflare.com/client/v4/graphql'
export ACCOUNT_ID='YOUR_ACCOUNT_ID'
export ACCOUNT_ID2='YOUR_ACCOUNT_ID2'
export ZONE_ID='YOUR_ZONE_ID'

GraphQL API をコールすることで Analytics データを取得できます。

スキーマの探索は「Explore the Analytics schema with GraphiQL」が参考になります。

アカウントを対象とする場合
http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    accounts(filter: {accountTag: "'${ACCOUNT_ID}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"2022-09-01",date_lt:"2022-10-01"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '.data.viewer.accounts[].httpRequests1dGroups[]'
ゾーンを対象とする場合
http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    zones(filter: {zoneTag: "'${ZONE_ID}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"2022-09-01",date_lt:"2022-10-01"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '.data.viewer.zones[].httpRequests1dGroups[]'

2022 年 9 月を対象として、1日ごとに集計されたデータのリストが確認できます。

result.json
{
  "dimensions": {
    "date": "2022-09-01"
  },
  "sum": {
    "bytes": 60514334,
    "cachedBytes": 60447958,
    "cachedRequests": 15161,
    "encryptedBytes": 60466295,
    "encryptedRequests": 15165,
    "pageViews": 12,
    "requests": 15205,
    "threats": 1
  }
}
{
  "dimensions": {
    "date": "2022-09-02"
  },
  "sum": {
    "bytes": 1622933,
    "cachedBytes": 987969,
    "cachedRequests": 447,
    "encryptedBytes": 1297520,
    "encryptedRequests": 568,
    "pageViews": 123,
    "requests": 827,
    "threats": 82
  }
}
...
{
  "dimensions": {
    "date": "2022-09-30"
  },
  "sum": {
    "bytes": 715675,
    "cachedBytes": 300188,
    "cachedRequests": 121,
    "encryptedBytes": 547365,
    "encryptedRequests": 146,
    "pageViews": 44,
    "requests": 247,
    "threats": 2
  }
}

前月(N-1 月)の集計

月間トラフィック量を把握するためにさらに整理して集計します。

% date -v -1m +"%Y-%m-01"
2022-09-01
% date +"%Y-%m-01"
2022-10-01
アカウントを対象とする場合
http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    accounts(filter: {accountTag: "'${ACCOUNT_ID}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"'$(date -v -1m +"%Y-%m-01")'",date_lt:"'$(date +"%Y-%m-01")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '[.data.viewer.accounts[].httpRequests1dGroups[].sum | to_entries[] ] | group_by(.key) | map({key: .[0].key,value: map(.value) | add}) | from_entries'
複数アカウントまとめて対象とする場合
http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    account1:accounts(filter: {accountTag: "'${ACCOUNT_ID}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"'$(date -v -1m +"%Y-%m-01")'",date_lt:"'$(date +"%Y-%m-01")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    },
    account2:accounts(filter: {accountTag: "'${ACCOUNT_ID2}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"'$(date -v -1m +"%Y-%m-01")'",date_lt:"'$(date +"%Y-%m-01")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '[.data.viewer[][].httpRequests1dGroups[].sum | to_entries[] ] | group_by(.key) | map({key: .[0].key,value: map(.value) | add}) | from_entries'
ゾーンを対象とする場合
http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    zones(filter: {zoneTag: "'${ZONE_ID}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"'$(date -v -1m +"%Y-%m-01")'",date_lt:"'$(date +"%Y-%m-01")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '[.data.viewer.zones[].httpRequests1dGroups[].sum | to_entries[] ] | group_by(.key) | map({key: .[0].key,value: map(.value) | add}) | from_entries'

前月の月間トラフィック量は 138 MB とすぐに把握できます。

result.json
{
  "bytes": 138328396, # 138 MB
  "cachedBytes": 94041494,
  "cachedRequests": 24703,
  "encryptedBytes": 97772563,
  "encryptedRequests": 23677,
  "pageViews": 1203,
  "requests": 56092,
  "threats": 335
}

過去11ヶ月分の月間トラフィック量(bytes

過去11ヶ月分の月間トラフィック量について、データを取得します。

アカウントを対象とする場合
for ((i=0; i<11; i++)); do echo -n "$(date -v -$(expr ${i} + 1)m +"%Y年%m月") (MB) : " && http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    accounts(filter: {accountTag: "'${ACCOUNT_ID}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"'$(date -v -$(expr ${i} + 1)m +"%Y-%m-01")'",date_lt:"'$(date -v -${i}m +"%Y-%m-01")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '[.data.viewer.accounts[].httpRequests1dGroups[].sum | to_entries[] ] | group_by(.key) | map({key: .[0].key,value: map(.value) | add}) | from_entries | (.bytes/1000000)' ; done
ゾーンを対象とする場合
for ((i=0; i<11; i++)); do echo -n "$(date -v -$(expr ${i} + 1)m +"%Y年%m月") (MB) : " && http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    zones(filter: {zoneTag: "'${ZONE_ID}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"'$(date -v -$(expr ${i} + 1)m +"%Y-%m-01")'",date_lt:"'$(date -v -${i}m +"%Y-%m-01")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '[.data.viewer.zones[].httpRequests1dGroups[].sum | to_entries[] ] | group_by(.key) | map({key: .[0].key,value: map(.value) | add}) | from_entries | (.bytes/1000000)' ; done

年間の計画やレポートに活用できるかと思います。

2022年09月 (MB) : 138.328396
2022年08月 (MB) : 133.454489
2022年07月 (MB) : 19.204661
2022年06月 (MB) : 27.104583
2022年05月 (MB) : 463.646896
2022年04月 (MB) : 472.347435
2022年03月 (MB) : 339.184971
2022年02月 (MB) : 67.263986
2022年01月 (MB) : 469.10907
2021年12月 (MB) : 21.728387
2021年11月 (MB) : 15.443249

過去11ヶ月分の月間リクエスト数(requests

アカウントを対象とする場合
for ((i=0; i<11; i++)); do echo -n "$(date -v -$(expr ${i} + 1)m +"%Y年%m月") (リクエスト数) : " && http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    accounts(filter: {accountTag: "'${ACCOUNT_ID}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"'$(date -v -$(expr ${i} + 1)m +"%Y-%m-01")'",date_lt:"'$(date -v -${i}m +"%Y-%m-01")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '[.data.viewer.accounts[].httpRequests1dGroups[].sum | to_entries[] ] | group_by(.key) | map({key: .[0].key,value: map(.value) | add}) | from_entries | (.requests)' ; done 
ゾーンを対象とする場合
for ((i=0; i<11; i++)); do echo -n "$(date -v -$(expr ${i} + 1)m +"%Y年%m月") (リクエスト数) : " && http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    zones(filter: {zoneTag: "'${ZONE_ID}'"}) {
      httpRequests1dGroups (limit:32,filter:{date_geq:"'$(date -v -$(expr ${i} + 1)m +"%Y-%m-01")'",date_lt:"'$(date -v -${i}m +"%Y-%m-01")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '[.data.viewer.zones[].httpRequests1dGroups[].sum | to_entries[] ] | group_by(.key) | map({key: .[0].key,value: map(.value) | add}) | from_entries | (.requests)' ; done 
2022年09月 (リクエスト数) : 56092
2022年08月 (リクエスト数) : 26505
2022年07月 (リクエスト数) : 8530
2022年06月 (リクエスト数) : 12554
2022年05月 (リクエスト数) : 359617
2022年04月 (リクエスト数) : 25629
2022年03月 (リクエスト数) : 41212
2022年02月 (リクエスト数) : 12793
2022年01月 (リクエスト数) : 66101
2021年12月 (リクエスト数) : 9344
2021年11月 (リクエスト数) : 6159

過去 365 日間の集計

過去1年分について、データを取得します。

% date -v -365d +"%Y-%m-%d"
2021-10-14
% date +"%Y-%m-%d"
2022-10-14
アカウントを対象とする場合
http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    accounts(filter: {accountTag: "'${ACCOUNT_ID}'"}) {
      httpRequests1dGroups (limit:365,filter:{date_geq:"'$(date -v -364d +"%Y-%m-%d")'",date_leq:"'$(date +"%Y-%m-%d")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '[.data.viewer.accounts[].httpRequests1dGroups[].sum | to_entries[] ] | group_by(.key) | map({key: .[0].key,value: map(.value) | add}) | from_entries'
ゾーンを対象とする場合
http -A creds $GQL_ENDPOINT query='query
{
  viewer {
    zones(filter: {zoneTag: "'${ZONE_ID}'"}) {
      httpRequests1dGroups (limit:365,filter:{date_geq:"'$(date -v -364d +"%Y-%m-%d")'",date_leq:"'$(date +"%Y-%m-%d")'"},orderBy:[date_ASC]) {
        sum {
          bytes,
          cachedBytes,
          cachedRequests,
          encryptedBytes,
          encryptedRequests,
          pageViews,
          requests,
          threats
        }
        dimensions {
          date
        }
      }
    }
  }
}
' | jq -r '[.data.viewer.zones[].httpRequests1dGroups[].sum | to_entries[] ] | group_by(.key) | map({key: .[0].key,value: map(.value) | add}) | from_entries'

こちらも年間の計画やレポートに活用できるかと思います。

result.json
{
  "bytes": 2289883831, # 2.2 GB
  "cachedBytes": 1531715556,
  "cachedRequests": 441301,
  "encryptedBytes": 2204593863,
  "encryptedRequests": 583508,
  "pageViews": 154492,
  "requests": 643433,
  "threats": 282210
}

まとめ

GraphQL API で取得できるデータには、まだまだ活用の余地があると思います。

今回はその一部を確認しましたが、次はチャートを作って見ること等にトライしたいと思います。

Grafana (無料アカウント)で可視化できたので、以下 GitHub リンク内の「HTTP-Requests.json」をご活用ください。

参考

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?