1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

記事投稿キャンペーン 「2024年!初アウトプットをしよう」

AWS SDK for Rubyを使ってCloudWatch Logs Insightsの分析内容を取得する

Posted at

はじめに

CloudWatchのログの内容が膨大なときはCloudWatch Logs Insightsを使って必要なログのみを取得し分析していたのですが、AWS SDK for Rubyを使ってCSV形式で出力する機会があったのでその方法についてまとめてみました。

CloudWatch Logs Insightsをあまり使ったことがない方、CloudWatchのログデータをCSV形式で取得する方法について興味がある方のお役に立つかと思います!

CloudWatch Logs Insightsとは?

独自のクエリ構文を使いCloudWatch Logsのログデータをインタラクティブに検索、分析できるAWSが提供するサービスの一つです。

CloudWatch Logsとは?
CloudWatchの機能の一つで、AWSのリソースやアプリケーションから生成されるログデータを収集、監視、保存する

CloudWatchのサイドバーから「ログのインサイト」に進むと操作画面に移ります。

image.png

ざっくりですが操作手順は以下の通りです。

  1. 検索、分析を行うロググループを選択
  2. クエリ構文を作成し実行
  3. 実行したクエリの内容に応じて取得したクエリが表示される

基本的な操作方法やクエリ構文については本記事では割愛するので、下記の記事を参考にしてみてください。

AWS SDK for Rubyとは

Ruby言語を使用してAWSのリソースやサービスをプログラム的に操作するためのツールキットです。
AWS SDK for Ruby のバージョン3からは サービス固有のgem (例: aws-sdk-s3、aws-sdk-dynamodb など) にモジュール化されたので、必要なSDKのみを個別のgemで選択できるようになりました。

事前準備

Ruby on Railsを使ってCloudWatch Logs Insightsの分析内容をCSV形式で取得するスクリプトを作りますが、その前に必要な準備します。

開発環境: Mac M2

認証情報の設定

AWS SDKを使ってAWSサービスに接続するためには認証情報をあらかじめ指定しておく必要があります。

  1. AWS IAMコンソールからIAMユーザを作成し、アクセスキーIDとシークレットアクセスキーを取得
  2. ローカル環境で~/.aws/credentialsを作成し、取得した認証情報を設定したのちに保存
[default]
aws_access_key_id='取得したアクセスキーID'
aws_secret_access_key='シークレットアクセスキー'
aws_session_token='セッショントークン(一時的なアクセス権限をとする場合に必要)'

認証情報の設定について:

SDKのインストール

cloudwatch用のgemをGmefileに追加し、bundle installを実行

gem 'aws-sdk-cloudwatchlogs'

RailsコンソールでCloudWatchに接続しログを取得する

Railsコンソールを使って実際にログを取得してみることで、どうすればログを取得できるかを見てみます。

CloudWatchへの接続

はじめに先述で設定した認証情報を使ってCloudWatchに接続してみましょう。

client = Aws::CloudWatchLogs::Client.new(region: 'ap-northeast-1')

Aws::CloudWatchLogs::Client.newはCloudWatch Logsの操作をサポートするクライアントです。呼び出される際に、~/.aws/credentialsから認証情報を自動で読み込みます。regionでAWSリージョンを指定する必要があります。

query_idを取得

接続がうまくいったら、StartQueryを使用してCloudWatch Logs Insightsのクエリを指定し、query_idを取得できるか確認しましょう。

query_response = client.start_query({
  log_group_name: '/log_group_path',
  start_time: (Time.zone.now - 3600).to_i * 1000,
  end_time: Time.zone.now.to_i * 1000,
  query_string: 'fields @message | limit 20'
})

start_queryは、CloudWatch Logsのログデータに対して指定したクエリを実行し、ログデータの検索を実行します。

リクエストパラメータについては以下の通りです。

  • log_group_name
    クエリを実行するロググループを指定

  • start_time
    クエリする時間範囲の開始時刻

  • end_time
    クエリする時間範囲の終了時刻

  • query_string
    使用するクエリ文字列
    ここで指定したクエリが実際に実行される

start_queryについて:

実行後、query_idが取得できれば成功です

query_response
=> <struct Aws::CloudWatchLogs::Types::StartQueryResponse query_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx">

ログを取得

取得したquery_idを使ってログを取得します。

response = client.get_query_results(query_id: query_response[:query_id])

get_query_resultsは、指定したクエリの結果を返します。

get_query_resultsについて:

返却された結果からログが確認できたら成功です。

response[:results]
=>
[
   [#<struct Aws::CloudWatchLogs::Types::ResultField field="@message", value="I, [2024-01-01T13:56:10.298884 #1]  INFO -- : [xxx-xxx-xxx-xxx-xxx] Started GET \"/_health\" for 10.0.10.196 at 2024-01-01 13:56:10 +0900\n">,
     #<struct Aws::CloudWatchLogs::Types::ResultField field="@ptr", value="">],
    [#<struct Aws::CloudWatchLogs::Types::ResultField field="@message", value="I, [2024-01-01T13:56:09.749941 #1]  INFO -- : [xxx-xxx-xxx-xxx-xxx]  Started GET \"/_health\" for 10.0.11.161 at 2024-01-01 13:56:09 +0900\n">,
     #<struct Aws::CloudWatchLogs::Types::ResultField field="@ptr", value="">],
    [#<struct Aws::CloudWatchLogs::Types::ResultField field="@message", value="I, [2024-01-01T13:56:09.576021 #1]  INFO -- : [xxx-xxx-xxx-xxx-xxx]  Started GET \"/_health\" for 10.0.12.74 at 2024-01-01 13:56:09 +0900\n">,
     #<struct Aws::CloudWatchLogs::Types::ResultField field="@ptr", value="">],
    [#<struct Aws::CloudWatchLogs::Types::ResultField field="@message", value="I, [2024-01-01T13:55:40.268645 #1]  INFO -- : [xxx-xxx-xxx-xxx-xxx]  Started GET \"/_health\" for 10.0.10.196 at 2024-01-01 13:55:40 +0900\n">,
     #<struct Aws::CloudWatchLogs::Types::ResultField field="@ptr", value="">]
]

ログをCSV形式で出力するスクリプトを作成

記事のアクセス数順で、記事IDとアクセス数をCSV形式で出力するサービスクラスを作成します。

コード

class Aws::CloudwatchLogsService
  require 'aws-sdk-cloudwatchlogs'

  LOGGER = ActiveSupport::Logger.new($stdout)

  def call
    client = Aws::CloudWatchLogs::Client.new(region: 'ap-northeast-1')
    
    columns = ['articlue_id', 'accessCount']
    query_string =  'filter @message like /articlues\/.*\?include_comments/
                    | parse @message "articlues/*?" as articlue_id
                    | stats count(articlue_id) as accessCount by articlue_id
                    | sort accessCount desc
                    | limit 10000'

    params = {
      log_group_name: '/articlue',
      start_time: Time.zone.now.beginning_of_day.to_i * 1000,
      end_time: Time.zone.now.end_of_day.to_i * 1000,
      query_string: query_string
    }

    query_response = client.start_query(params)
    response = nil

    # 再試行回数は20回まで
    20.times do
      sleep 1
      response = client.get_query_results(query_id: query_response[:query_id])
      break if response[:status] != 'Running'
    end

    unless response[:status] == 'Complete'
      logger.warning("Fetch Data Failed. Status -> #{response[:status]}")
    end

    generate_csv_data(response, columns)
  end

  #
  # CSV形式に書き出すデータを生成
  #
  def generate_csv_data(data, columns)
    result = []
    data[:results].each do |row|
      record = []
      columns.each do |column|
        value = get_value(row, column)
        record << value
      end
      result << record
    end
    result
  end

  def get_value(record, key)
    result = record.select { |x| x[:field] == key }
    result.empty? ? '' : result[0][:value]
  end
end

実行結果

コンソールで実行してみると以下のような実行結果が得られます。

Aws::CloudwatchLogsService.new.call
=>
[["3820", "283"],
 ["2840", "243"],
 ["3912", "234"],
 ["1022", "210"],
 ["2192", "189"],
 ["1792", "172"],
 ["2832", "150"],
 ["3172", "142"],
 ["1047", "140"],
 ...
 ["3953", "1"],
 ["2947", "1"],
 ["2292", "1"]]

まとめ

最後のスクリプトに関しては、アプリの設計、仕様や元々のログの形式の説明を無視して載せているので分かりにくい部分があるかと思いますが、ログの取得から出力までの流れに着目してもらえれば幸いです。
CloudWatch Logsで取得したログをCSVとして出力できれば、他のデータ分析ツールに流用したり、アプリケーション上ではログの生成、取得が難しくても、別々で出力した同士をマージして一つのデータして管理できたりと、分析の幅が広がると思います。
今までCloudWatch Logs Insightsを使ったことがなかった方は、ぜひ使ってみてください!

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?