New Relicのダッシュボードはterraformを使ってコードとして管理できるため、Dashboards as Codeを実現できます。またアラートポリシーもterraformで管理でき、Observability as codeを目指しています。そこでダッシュボードをterraformで管理する例として「Dashboards as Code: How to Create a Syslog Dashboard Using New Relic and Terraform」の抄訳をお届けします。

ダッシュボードは、スタック全体のパフォーマンスを可視化して状況を把握し、問題を迅速に解決するための重要なツールです。また、「問題はいつから発生したのか?」、「この問題の影響は?」などの質問に答えるのにも役立ちます。

しかし、ダッシュボードを手動で維持することはエラーが発生しやすく、効率とセキュリティの面で最適ではありません。また、ダッシュボードの手動更新では、修正履歴やロールバックの仕組み、ピアレビューなど、CI/CDパイプラインに通常期待されるメリットが得られません。そのためエンジニアはダッシュボードをコードとして作成することで、他の重要なリソースと同様に扱い始めています。

例えば、TerraformとNew Relic Oneに新しく組み込まれたSyslog RFC-5424用のログパーサールールを使えば、Syslog RFC-5424の構造化されていないメッセージを属性と値のペアに整理し、ログデータのサブセットに基づいてアラートを出すことができるダッシュボードをコードとして作成し、オブザーバビリティ(可観測性)を実装できます。syslogデータを投入するための新しいエージェント不要な選択肢により、データをインジェストする際もしくはNew Relic UIから直接データを適切に解析する際に適切にデータをパースする限り、データのインジェストには様々な選択肢があります。このブログ記事では、Syslog RFC-5424 ダッシュボードをコードとして作成する方法をご案内します。

Syslogフォーマットを理解する

ダッシュボードを構築するには、まずSyslog RFC-5424形式でログの重大度がどのように定義されているかを理解する必要があります。syslogのPRI部分は計算された優先度の値ですが、ログやイベントメッセージのファシリティと重大度の両方を表すために使用されます。PRIは、まずファシリティの数値を8倍し、次に重大値の数値を加えて値を計算します。たとえば、security/authorization(ファシリティ値4)で重大性(重大度2)の場合、PRI値は 34((4*8)+2)となります。この理解に基づき、次の式(pri-((floor(pri)/8)*8))を使用して PRI ログ属性からログの深刻度を抽出することができます。

ステップ1:Terraformプロジェクトの作成

あらゆる種類のインフラやサービスのプロビジョニングに使用できるInfrastructure as a Codeツールとして、TerraformはHCLと呼ばれる設定言語を使用します。HCLの主な目的は、インフラ・オブジェクトを表現するためのリソースを記述することです。リソースは、プロバイダーと呼ばれる特定のプラグインによって処理されます。

New Relic には公式の Terraform プロバイダーがあります。ダッシュボード、アラートチャンネル、アラートポリシーなど、さまざまな種類のリソースを管理することができます。Terraformプロバイダの詳細については、プロバイダのドキュメントと、ここで紹介するクイックティップビデオをご覧ください。

プロジェクトフォルダの作成から始めましょう。Terraformは非常に柔軟で、プロジェクトの要件(複数の環境、複数のアカウントなど)に応じて適応できるため、Terraformワークスペースを整理する方法もさまざまです。ここでは簡単のために、フラットな構造を採用します。

1. プロジェクト用のディレクトリを作成します。

mkdir newrelic-syslog-monitoring

2. 作業ディレクトリにversions.tfというファイルを作成します。Terraformはこのファイルを使ってTerraformクライアントを設定し、現在のモジュールに必要なすべてのプロバイダーを指定します(ここではnewrelicプロバイダーを指定します)。

terraform {
  required_version = ">= 0.13"
   required_providers {
      newrelic = {
         source  = "newrelic/newrelic"
         version = ">= 2.12.0"
      }
   }
}

3. 入力変数(input variables)を用意します。New Relic Terraform プロバイダーは、アカウントとの統合やリソースの管理を行うために、Account ID、Personal Key、Region (US or EU) を必要とします。設定方法は、環境変数を使用する方法と、プロバイダーブロックを使用する方法の2種類をサポートしています。ここでは、プロバイダーブロックを使用し、必要な情報はすべて入力変数で受け取るようにしています。次の内容でvariables.tf</code<というファイルを作成します。

variable "NEWRELIC_ACCOUNT_ID" {
  type    = number
}

variable "NEWRELIC_API_KEY" {
  type    = string
}

variable "NEWRELIC_REGION" {
  type    = string
}

4. Terraformの主要なエントリーポイントとなるmain.tfというファイルを作成します。New Relic Terraformプロバイダの設定もこのファイルで行い、あらかじめvariables.tfファイルで宣言した入力変数を使用します。

provider "newrelic" {
  account_id = var.NEWRELIC_ACCOUNT_ID
  api_key    = var.NEWRELIC_API_KEY
  region     = var.NEWRELIC_REGION
}

ステップ 2: Syslog ダッシュボードの作成

ダッシュボードのデータはすべて、NRQL クエリ言語を使用して Log データタイプから取得します。クエリを簡素化し、繰り返しを避けるために、Terraform localsを使用してSyslog重大度の式とlogTypeフィルター値を表現することにします。

1. dashboards.tfという名前のファイルを作成します。このファイルは、ダッシュボードリソースとそのウィジェット/ビジュアライゼーションを記述するために使用します。

locals {
  syslog   = "syslog-rfc5424"
  severity = "(numeric(pri) - (floor(numeric(pri)/8) * 8))"
}

resource "newrelic_dashboard" "syslog_dashboard" {
  title             = "Syslog Dashboard"
  grid_column_count = 12
}

2. ウィジェットとビジュアライゼーションの追加

ダッシュボードをデザインする最初のステップは、何を実現したいのか、それを可能にするためにどのビジュアライゼーションが最も重要なのかを定義することです。この例では、ダッシュボードはアプリケーションの健全性の概要を示します。

注:すべてのウィジェットコードは、"syslog_dashboard" {...}ブロックの中に入ります。

ウィジェット1:重大度別ビルボードカウンター

ログの重大度は、Syslogフォーマットで利用可能な最も重要なフィールドの1つであり、このダッシュボードの視覚化に広く使用されています。ビルボードチャートは重大度別にログカウンターを表示し、threshold_yellowthreshold_redの値に応じて黄色や赤に着色します。このチャートにより、アプリケーションで何が起こっているかを簡単に確認することができ、問題のあるログが到着した場合には注意を引くことができます。

これらのビルボードチャートはほぼ同じコードを共有しているので、Terrafromのダイナミックブロックを利用し、コードを再利用してseverity_billboardsマップを反復して各ウィジェットを設定することができます。そのためには、locals{...}ブロックの中にseverity_billboardsマップを次のような内容で追加します。

locals {
  syslog   = "syslog-rfc5424"
  severity = "(numeric(pri) - (floor(numeric(pri)/8) * 8))"

  severity_billboards = tomap({
    "emergency"     = { severity =  0, row = 1, column = 1, threshold_red = 1 },
    "alert"         = { severity =  1, row = 2, column = 1, threshold_red = 1 },
    "critical"      = { severity =  2, row = 1, column = 2, threshold_red = 1 },
    "error"         = { severity =  3, row = 2, column = 2, threshold_yellow = 1 },
    "warning"       = { severity =  4, row = 1, column = 3 },
    "notice"        = { severity =  5, row = 2, column = 3 },
    "informational" = { severity =  6, row = 1, column = 4 },
    "debug"         = { severity =  7, row = 2, column = 4 }
  })
}

次に、"syslog_dashboard" {...}ブロックの中に、ウィジェットのための一般的なコードを追加します。

  dynamic "widget" {
    for_each = local.severity_billboards
    content {
      title            = ""
      nrql             = <<-EOF
        SELECT
          count(*) as '${title(widget.key)} (${widget.value.severity})'
        FROM Log
        WHERE logType = '${local.syslog}' AND ${local.severity} = ${widget.value.severity}
      EOF
      visualization    = "billboard"
      width            = 1
      height           = 1
      row              = widget.value.row
      column           = widget.value.column
      threshold_yellow = try(widget.value.threshold_yellow, null)
      threshold_red    = try(widget.value.threshold_red, null)
    }
  }

最終的には以下のようになります。

ウィジェット2:ログスループットのビルボード

このグラフは、ログの総数とアプリケーションがログを送信している1分あたりのレートを示しています。

  widget {
    title         = "Throughput"
    nrql          = <<-EOF
      SELECT
        rate(count(*), 1 minute) as 'Logs /min',
        count(*) as 'Total'
      FROM Log
      WHERE logType = '${local.syslog}' SINCE 1 hour ago
    EOF
    visualization = "attribute_sheet"
    width         = 2
    height        = 2
    row           = 1
    column        = 5
  }

最終的には以下のようになります。

ウィジェット 3: 問題が疑われる傾向を時系列で表示するラインチャート

このグラフは、重大度がError(3)Critical(2)Alert(1)Emergency(0)のいずれかのログをカウントし、その結果を時系列で表示します。このグラフでのスパイクは、アプリケーションに問題があり、その解決のためにアクションを起こす必要があることを示しています。

  widget {
    title         = "Logs (Emergency + Alert + Critical + Error)"
    nrql          = <<-EOF
      SELECT
        count(*)
      FROM Log
      WHERE logType = '${local.syslog}' AND ${local.severity} < 4
      TIMESERIES AUTO
    EOF
    visualization = "line_chart"
    width         = 6
    height        = 3
    row           = 3
    column        = 1
  }

最終的な結果は以下のようになります。

ウィジェット 4: アプリケーションおよびノード別の棒グラフ

アプリケーション別、ホスト名別にログ数を表示するグラフです。アプリケーションやホスト名のバーをクリックするだけで、現在のダッシュボードをフィルタリングするように設定することもできます。

  widget {
    title         = "Top Applications"
    nrql          = <<-EOF
      SELECT
        count(*)
      FROM Log
      WHERE logType = '${local.syslog}'
      FACET app.name
    EOF
    visualization = "facet_bar_chart"
    width         = 2
    height        = 5
    row           = 1
    column        = 7
  }

  widget {
    title         = "Top Nodes"
    nrql          = <<-EOF
      SELECT
        count(*) as 'Logs'
      FROM Log
      WHERE logType = '${local.syslog}'
      FACET hostname
    EOF
    visualization = "facet_bar_chart"
    width         = 2
    height        = 5
    row           = 1
    column        = 9
  }

最終的には以下のようになります。

ウィジェット 5: 重大度と機能別のログカウンターを時系列で表示するラインチャート

これらのチャートの背景にあるアイデアは、アプリケーションが送信している重大度および機能別のログ数を時系列で表示することです。これにより、任意の深刻度や機能のスパイクを簡単に検出し、それらがいつ始まり、いつ止まったかを特定することができます。

  widget {
    title         = "Logs by Severity"
    nrql          = <<-EOF
      SELECT
        count(*)
      FROM Log
      WHERE logType = '${local.syslog}'
      FACET string(${local.severity}) as 'Severity'
      TIMESERIES AUTO
    EOF
    visualization = "faceted_line_chart"
    width         = 3
    height        = 3
    row           = 6
    column        = 1
  }

  widget {
    title         = "Logs by Facility"
    nrql          = <<-EOF
      SELECT
        count(*)
      FROM Log
      WHERE logType = '${local.syslog}'
      FACET floor(numeric(pri)/8) as 'Facility'
      TIMESERIES AUTO
    EOF
    visualization = "faceted_line_chart"
    width         = 3
    height        = 3
    row           = 6
    column        = 4
  }

最終的な結果は以下のようになります。

ウィジェット6:上位100個のログを表示するイベント表

この表は、最も重要な100個のログを重要度別に優先的に表示します。

  widget {
    title         = "Top 100 Logs"
    nrql          = <<-EOF
      SELECT
        ${local.severity} as 'Severity',
        app.name as 'Application',
        message
      FROM Log
      WHERE logType = '${local.syslog}' LIMIT 100
    EOF
    column        = 7
    row           = 6
    visualization = "event_table"
    width         = 6
    height        = 3
  }

最終的には以下のようになります。

ウィジェット 7: SyslogファシリティのMarkdown要約

このチャートは、ダッシュボード上のsyslogファシリティの名前を簡単に参照できるように一覧表示します。

widget {
    title         = ""
    width         = 2
    height        = 5
    row           = 1
    column        = 11
    source        = <<-EOF
    ### Facilities
    1. kernel messages
    2. user-level messages
    3. mail system
    4. system daemons
    5. security/authorization messages (note 1)
    6. messages generated internally by syslogd
    7. line printer subsystem
    8. network news subsystem
    9. UUCP subsystem
    10. clock daemon (note 2)
    11. security/authorization messages (note 1)
    12. FTP daemon
    13. NTP subsystem
    14. log audit (note 1)
    15. log alert (note 1)
    16. clock daemon (note 2)
    to 23. local uses 0 to 7 (local n)
    EOF
    visualization = "markdown"
  }

最終的なダッシュボードはこのようになるはずです。

ステップ3:コードの適用

Terraformクライアントをインストールするには、www.terraform.io/downloads.html からバイナリをダウンロードするか、オペレーティングシステムのパッケージマネージャを使用します。これ以外の環境でのTerraformのインストール方法については、こちらを参照してください。

Terraformクライアントをインストールしたら、作業ディレクトリで以下のコマンドを実行します。

terraform plan -var NEWRELIC_ACCOUNT_ID=<YOUR-ACCOUNT-ID> -var NEWRELIC_API_KEY=<YOUR-API-KEY> \
-var NEWRELIC_REGION=<US or EU>

terraform planコマンドは、実行計画を作成し、構成ファイルで指定された目的の状態を達成するために必要なアクションを決定します。ここでは、ダッシュボードのリソースが追加されます。

最後に、以下のコマンドを実行して、保留されていたアクションをすべて適用し、New Relic One プラットフォームにリソースを作成します。

terraform apply -var NEWRELIC_ACCOUNT_ID=<YOUR-ACCOUNT-ID> -var NEWRELIC_API_KEY=<YOUR-API-KEY> \
-var NEWRELIC_REGION=<US or EU>

Terraformでは、ローカルリソースを実世界にマッピングするためにステートを使用します。ファイル内にresource "newrelic_dashboard"のように宣言されたリソースがある場合、Terraformはマップを使用して、New Relic Dashboard ID 1234がそのリソースで表現されていることを知ります。とはいえ、このプロジェクトを状態を共有せずに異なるマシンで適用した場合、Terraformはすべてのリソースを更新せずに再作成してしまいます。リモートステートを設定することで、このような事態を防ぐことができます。

HashiCorpでは、Terraformのワークフローを自動化するTerraform Cloudソリューションを提供しています。また、プルリクエストによってTerraformを自動化するツールであるAtlantisを利用することも可能で、コードとしてのオブザーバビリティ(Observability as code)を次のレベルに引き上げることができます。

ステップ4: アラートを追加してリアルタイムに通知

ダッシュボードは問題の検出やトラブルシューティングに欠かせないツールですが、24時間体制で監視していないと重要なログを見逃してしまうことがあります。アラートを設定することで重要なメトリクスがしきい値に達したときにすぐに通知を受けることができます。

New Relicのアラートはアプリケーションの問題が重大なインシデントに発展する前に、より早く、より少ないノイズで解決するのに活用できます。PagerDutySlackなど、New Relicのサードパーティとの統合により、通知プロセスが非常に効率的になり、チームのニーズにも適応できるようになります。

New RelicのTerraformプロバイダは、syslogアプリケーションを監視するために必要なすべてのアラートリソースをサポートしています。例えば、チーム、責任者、ノード、アプリケーションごとに異なるアラートチャンネルを作成し、アプリケーションがエラーを報告しているときにさまざまな方法で異なる人に通知することができます。

今回の例では、ダッシュボード・クエリを再利用して、以下のNRQLアラート条件を定義することができます。

  • クリティカルな重大度Error(3)、Critical(2)、Alert(1)、Emergency(0)に対する静的な閾値アラート 。
  • 異常な不健全性のスパイクを検出するための重大度4未満のログカウンターに対する上方向ベースラインアラート
  • 環境やシステムの特性に応じた追加のアラート。例えば、重大度<4でファシリティがsecurity/authorization messages(4)に等しいログに対しては、全社ではなく、例えば#security-teamのSlackチャンネルに適切に通知メッセージを送信するような静的なアラートを設定することができます。

(Terraformを使ったNew Relicのアラートについては、こちらのブログ記事をご覧ください)

Syslogダッシュボードを作成する準備はできましたか?

この例で使われているすべてのコードは、このGitHubリポジトリにあります。Terraformを使いたくないけど、ダッシュボードを試してみたいという方は、このJSONファイルの内容をコピーし、<YOUR_ACCOUNT_ID>のプレースホルダーをお客様のアカウントIDに置き換えて、UI([Dashboard] > [Import dashboard] アイコン)を使ってNew Relicにインポートすることができます。

New Relicを初めてご利用になる方で、New Relic Terraformプロバイダーをお試しになりたい方は、100GB/月の無料インジェスト機能付きの新規アカウントにサインアップしてください。

ソフトウェアエンジニア、インフラエンジニアなど自社開発や自社運用の現場で経験を積んだのち外資系ソフトウェアベンダーでのテクニカルサポートを経て現職。New Relicユーザーだった経験あり。コミュニティでの登壇活動も多く、Microsoft MVPを7年連続受賞中。Microsoft Certified Azure Solutions Architect Expert。得意分野はC#をはじめとするソフトウェア開発、Kubernetes関連技術およびパブリッククラウド。 View posts by .