監査ログ検索が27倍高速化。BigQuery 移行でコスト削減と高速化を両立した BaseMachina のログ分析基盤

  • URLをコピーしました!

こんにちは!PR TIMES ソフトウェアエンジニアの河瀨翔吾(@shogogg)です。現在はバックエンド開発を主に担当しています。好きな秋の味覚は秋刀魚ですが、今年はまだ食べられていません😢。

今回は BaseMachina(ベースマキナ)の監査ログを BigQuery 経由で参照できるようにした背景や試行錯誤した経験、具体的な手法についてお話しします!

目次

BaseMachina(ベースマキナ)とは

BaseMachina株式会社ベースマキナが開発・運営するローコード SaaS です。手間の掛かる管理画面の開発を少ないコードで実現できる他、bridge と呼ばれる仕組みで安全に社内のデータにアクセスできる仕組みが特徴です。

詳しくは BaseMachina の公式サイトをご覧ください。

ベースマキナ | AIネイティブな開...
ベースマキナ | 社内管理画面開発・DX/AX基盤のベースマキナ 「BaseMachina(ベースマキナ)」は、数分で安全な社内管理画面開発・DX/AX向け開発プラットフォームです。使いやすさと安全性を両立し、低いメンテナンスコストで社内シス...

PR TIMES では社内向け管理画面の一部をこの BaseMachina で開発しています。

BaseMachina の監査ログ

BaseMachina ではバックエンド処理にあたる部分を「アクション」という単位で管理しており、いつ、誰が、どこからアクションを実行したのかを記録する監査ログ機能が備わっています。

あわせて読みたい
ベースマキナ ドキュメント ベースマキナの公式ドキュメント。プロダクトの使い方や、設定項目についての説明を記載しています。

この監査ログは監査ログのストリーミングと呼ばれる機能を利用することで、Amazon S3 や Google Cloud Storage(GCS)にリアルタイムで転送することができます。弊社ではアプリケーションのインフラとして AWS を主に利用しているため、Amazon S3 に監査ログを転送するように設定していました。

監査ログを検索したい!

ところで、一般的に監査ログを取得する目的はいくつかあります。

  • コンプライアンス — データのアクセスや変更に関する記録を保管するため
  • セキュリティ — 不正アクセスやデータの持ち出しなど、セキュリティ上の脅威を検知または分析するため
  • トラブルシューティング — システム障害やデータの不整合が起きた場合や、ユーザーからのお問い合わせに対応して「いつ・なにが行われたのか」を追跡するため

目的がコンプライアンスだけであれば S3 に保管されているだけでも十分です。しかし実際には様々な理由から監査ログを検索・分析したいシーンが存在します。特に、ユーザーからのお問い合わせ対応の一環として、どのような操作が行われたのかを調査する場面は少なくありません。

そんなことを考えていた2025年4月。BaseMachina がサポートするデータソースに Amazon Athena が追加されたことで手軽に監査ログを検索できるようになったのを機に、我々は監査ログ検索機能の開発に着手しました。

Amazon Athena は便利!だけど……

Amazon Athena は、Amazon S3 に保管されている JSON や CSV 形式のデータを SQL で分析できる AWS のサービスです。

Amazon Web Services, Inc.
インタラクティブ SQL – Amazon Athena – AWS Amazon Athena は、インタラクティブなサーバーレス分析サービスであり、ペタバイト級のデータを格納先で分析するシンプルで柔軟な手段を提供します。

さて、BaseMachina のデータソースに Amazon Athena が追加された際、BaseMachina の公式ブログでも監査ログの検索について触れられており、その内容や公式のマニュアルを参考にすることで、Amazon Athena を使った監査ログの検索は実にあっさりと実現できました。

しかし、実際に作成したアクションを使ってみたところ、いくつかの課題があることがすぐに明らかになりました。

検索結果の表示に時間が掛かる

Amazon Athena によって SQL による検索が可能になったとは言え、データは依然として JSON ファイルのままです。S3 上の JSON ファイルにクエリを発行できるなんてまるで魔法のようなすごい技術ですが、それがクエリによる検索に最適化された状態でないことは火を見るよりも明らかです。

案の定、実際に使ってみると1回のクエリ実行に短くても数秒、長くて数十秒掛かることがわかりました。これでは実現したいユースケースに対して十分な性能を持っているとは言えません。

長い期間を指定すると結果が表示できない

Amazon Athena による検索は、スキャン対象のデータ量が増えれば増えるほど処理時間も増加します。

調査目的で監査ログを検索する場合、対象の期間を数週間〜数ヶ月に設定することもあり、保管されているデータ量にもよりますが、弊社のユースケースでは、期間を数週間に設定したところクエリの実行に時間が掛かりすぎてしまい、BaseMachina 上でエラーが発生してしまいました。

ベースマキナ社に問い合わせたところ、アクションの実行は現在のところ最大1分に制限されており、それを超えてしまうとエラーになってしまうようです。本制限は作業当時は明記されていなかったものの、現在はマニュアルに明記されています。

あわせて読みたい
ベースマキナ ドキュメント ベースマキナの公式ドキュメント。プロダクトの使い方や、設定項目についての説明を記載しています。

試験的に Athena による分析を運用していた期間中だけでも何度かこのエラーが発生しており、このままでは実運用が難しいと考えていました。

BigQuery を使えば解決できそう?

弊社のインフラは前述の通り主に AWS で構築されていますが、一部の用途で Google Cloud も併用しています。

特に BigQuery は様々なデータの分析目的で活用しており、S3 に保管されている監査ログをそのまま検索するのではなく、データを転送して BigQuery 経由で監査ログを分析できるようにすれば、前述の課題は2つとも解決できそうです。

懸念されるのはコスト面です。BigQuery を使うことで大幅なコスト増となるのであれば予算的に対応を断念する必要があるかもしれません。そこで、それぞれのコストを比較してみます。

Amazon Athena を使う場合

発生する費用は S3 のストレージ利用料、および Amazon Athena のクエリごとに発生する「スキャンしたデータ量に基づく従量課金」のみです。東京リージョンにおける従量課金は USD 5.0/TB です(2025年10月現在)。

Amazon Web Services, Inc.

BigQuery を使う場合

発生する費用はストレージ利用料に加えて、BigQuery のストレージ利用料とクエリごとに「スキャンしたデータ量に基づく従量課金」が発生します。クエリへの課金は USD 7.5/TiB であり Amazon Athena よりも割高ですが、毎月 1.0 TiB までの無料枠が設定されています(2025年10月現在)。

Google Cloud
BigQuery BigQuery、BigQueryML、

さらに、BigQuery ではスキャンする列を適切に指定することでスキャンするデータ量を実際に保管しているデータ量よりも少なく抑えることが可能です。Amazon Athena を使う場合のスキャン対象はあくまで JSON ファイルのままなので、パーティションを設定したとしても期間中の監査ログ全量を対象にスキャンが発生します。

無料枠があることに加えてスキャンするデータ量を抑えるようクエリを最適化すれば、BigQuery の方がコストを抑えられる可能性すらありそうです。

また、ストレージ利用料が S3 と BigQuery で二重に発生してしまいますが、S3 に保管されたデータを転送後一定期間経過した時点で削除するように設定すれば、その費用は最小限に抑えられます。また、BigQuery のストレージ利用料には無料枠も設定されており、無料〜極めて低い金額に抑えることもできそうです。

以上の通りコスト面での課題はほぼないに等しく、BigQuery を経由することで得られるメリットが大きいことから BigQuery の導入を決定しました。BaseMachina にデータソースとして BigQuery が追加されたことも後押しとなっています。

プレスリリース・ニュースリリース...
社内システム開発基盤のベースマキナ、BigQueryに対してSQLを実行する機能をリリース。対応可能な業務が拡... 株式会社ベースマキナのプレスリリース(2025年7月31日 10時56分)社内システム開発基盤のベースマキナ、BigQueryに対してSQLを実行する機能をリリース。対応可能な業務が...

BaseMachina のログ転送先を Google Cloud Storage に変更する

今回の対応に着手した当初、監査ログの転送先は Amazon S3 のまま、S3 から BigQuery へデータを転送する想定で検討を進めていました。データの転送方法としてはシンプルに BigQuery Data Transfer Service(DTS)を使う想定だったのですが、Amazon S3 + DTS の場合、自動同期が1時間に1回まで、という制約があります。

今回の要件では高いリアルタイム性が求められているわけではありませんが、さすがに遅すぎると判断しました。Cloud Run Functions を使って数分おきに DTS のジョブを起動する、などのワークアラウンドがないわけではありませんが、目的に対して少し大袈裟すぎるのと、多少とはいえ追加のコストが発生してしまいます。

一方、Google Cloud Storage(GCS)+ DTS であれば、15分周期での自動同期が可能となります。BaseMachina の監査ログストリーミング(転送)機能は、前述の通り Amazon S3 だけでなく GCS への転送にも対応しており、転送先を変更するだけで目的が達成できそうです。

移行のタイミングで追加の作業は発生してしまいますが、移行後の構成がシンプルになることを重視し、BaseMachina からのログ転送先を S3 から GCS へ変更することにしました。

S3 に保管された監査ログを手動で BigQuery にインポートする

最終的には監査ログの転送先を GCS へ変更することになりましたが、それまでの間に S3 へ保管された監査ログも BigQuery にインポートする必要があります。これが一筋縄ではいきませんでした。

DTS + S3 による転送 → 失敗

うまく行かなかった方法その1は、誰もが最初に思いつくであろう方法です。S3 をソースとした DTS 設定は自動実行周期が1時間という制約はありましたが、手動で実行する分にはそれは無視することが可能です。

BaseMachina の監査ログは S3 バケット上に以下のようなプレフィクス・オブジェクト名で保管されます。

2025-01-23/execute_action/2025-01-23T12:34:56.789Z.json

そこで、次のような DTS 設定を作成しました。

  • ソース:Amazon S3
  • スケジュール:オンデマンド
  • Amazon S3 URIs3://{{ bucket_name }}/*/execute_action/*.json

これを手動で実行して後は待つだけ!……と思いきや、早々にエラーが発生してしまいました。どうやら、Amazon S3 から DTS でインポートする場合、1度に転送できるオブジェクト数に制限があり、それに引っ掛かってしまったようです。

また、その上限は「URI に含まれるワイルドカードの数」によって変わり、ワイルドカードが0〜1個の場合は最大1,000万件のオブジェクトが転送できる一方で、今回のように2個以上のワイルドカードが含まれる場合は一気に制限が強くなり、最大1万件までしか転送できません。

今回の作業では約900万件のログを転送する必要があるため、ワイルドカードを減らすか他の方法に切り替える必要がありそうです。

ワイルドカードを減らす場合、日付ごとの DTS 設定を用意することになりますがそれは現実的ではありません。そこで、この方法はあきらめて別の方法を探ることにしました。

DTS + GCS による転送 → 失敗

Google Cloud の Storage Transfer Service(STS)を使えば、S3 に保管されているオブジェクトを GCS へ簡単に転送できます。また、DTS + S3 では思わぬ制約に引っ掛かってしまいましたが、Google Cloud のサービス間での連携であれば、そんな面倒なことはないに違いありません(フラグ)。

STS を使ったオブジェクトの転送は思った以上にあっさりと終わりましたが、DTS 設定を作成して実行してみたところ、またもやエラーとなってしまいました。

どうやら、GCS から DTS でインポートする場合、ワイルドカードの有無や数に関わらず常に最大1万件の制限があるようです。Google Cloud 内での連携なのに Amazon S3 の場合より制限が厳しいなんて……。

どうやら、また別の方法を模索する必要がありそうです。

bq load + GCS による転送 → 成功!!

bq コマンドは CLI から BigQuery を操作するためのツールです。bq コマンドにはローカル、または GCS からデータを転送するための bq load サブコマンドが用意されており、このコマンドを使えば一度に最大1,000万件のデータを転送することができます。

Google Cloud Documentation
割り当てと上限  |  BigQuery  |  Google Cloud Documentation BigQuery のジョブ、クエリ、テーブル、データセット、DML、UDF、API リクエストに適用される割り当てと上限について説明します。

DTS + GCS を試した時点で、必要なログファイルはすべて GCS に転送済みです。また、作業時点で保管されているログは前述の通り約900万件ですので、bq load コマンドを使うことですべてのログを理論上は一括で BigQuery に転送できそうです。

しかし、これまでの作業で調査不足によるトラブルとそれによる手戻りがありましたので、念には念を入れることにし、以下のようなシェルスクリプトを作成して日ごとに転送することにしました。

#!/usr/bin/env bash

set -e

GCS_URL='gs://...'
BIGQUERY_PROJECT=...
BIGQUERY_DATASET=...
BIGQUERY_TABLE=...
SCHEMA_FILE='./schema.json'

FROM="$1"
TO="$2"

if [[ -z "${FROM}" || -z "${TO}" ]]; then
    echo "Usage: $0 [FROM] [TO] [--dry-run]"
    exit 1
fi
case "$3" in
    "--dry-run")
        DRY_RUN=true
        ;;
    "")
        DRY_RUN=false
        ;;
    *)
        echo "Usage: $0 [FROM] [TO] [--dry-run]"
        exit 1
        ;;
esac

echo "Loading data from ${GCS_URL} between ${FROM} and ${TO}."
echo "------------------------------------------------------------------------------------------------"

# List urls in specified gcs bucket
urls=$(gsutil ls "${GCS_URL}")

# Loop through each prefix
for url in $urls; do
    # Skip urls outside the specified range
    if [[ "${url}" < "${GCS_URL}/${FROM}/" ]]; then
        continue
    fi
    if [[ "${url}" > "${GCS_URL}/${TO}/" ]]; then
        continue
    fi

    echo "Loading data from ${url}..."

    # Skip actual loading if dry run
    if [[ $DRY_RUN == true ]]; then
        continue
    fi

    # Load data into BigQuery
    bq load \\
        --project_id="${BIGQUERY_PROJECT}" \\
        --source_format=NEWLINE_DELIMITED_JSON \\
        "${BIGQUERY_DATASET}.${BIGQUERY_TABLE}" \\
        "${url}execute_action/*.json" \\
        "${SCHEMA_FILE}"
done

echo "------------------------------------------------------------------------------------------------"
echo "Done!"

対象の期間を指定できるようにすることで、何らかの理由で中断したりした場合に、中断したところから再開しやすいようにしています。また schema.json は BigQuery テーブルのスキーマ定義ファイルです。以下のようなコマンドで出力することができます。

# <project_id>, <dataset>, <table> は対象となるプロジェクトID・データセット名・テーブル名を指定
bq show \\
  --schema \\
  --format=prettyjson \\
  '<project_id>:<dataset>.<table>' > schema.json

これで無事に S3 に保管されている監査ログを GCS 経由で BigQuery へ転送することができるようになりました。

BaseMachina から GCS経由で BigQuery に監査ログを転送する

Google Cloud Storage バケットの作成

S3 からの転送用に用意したものとは別に、BaseMachina からの監査ログストリーミング用に新たなバケットを用意します。

切り替え前のデータは bq load を使った転送、切り替え後のデータは DTS を使った転送となります。そのため、異なる転送方式によるデータの二重登録などのトラブルを避けるため、S3 からの転送用と、GCS 移行後の転送用のバケットを分けることにしました。

Data Transfer Service の設定

BigQuery の Data Transfer Service(DTS)を新たに設定します。同期タイミングは予定通り15分周期とし、対象の URL は次の通り設定し、新しいバケットに登録されたアクション実行ログが自動的に BigQuery へ転送されるようにします。

gs://{{ bucket_name }}/*/execute_action/*.json

その他、細かい部分については割愛します。

BaseMachina 用 Google Cloud サービスアカウントを作成

BaseMachina から Google Cloud Storage に監査ログを転送する場合、サービスアカウントキー(JSON 形式)を設定する必要があります。

ここで用いるサービスアカウントに必要な権限は、監査ログ転送用に用意する特定の Google Cloud Storage へのオブジェクト作成権限storage.object.createのみです。よって、次のように必要最低限の権限のみを持つサービスアカウントを作成・設定します。

  1. Google Cloud コンソールから IAM と管理 » サービスアカウントにアクセスし、新しいサービスアカウントを作成する。この時、汎用的なロール・権限は付与しない。
  2. 同じく Google Cloud コンソールから Cloud Storage » バケットにアクセスし、監査ログ転送先として用いるバケットの詳細画面へ移動する。
  3. バケットの「権限」タブで「アクセスを許可」から、用意したサービスアカウントに「Storage オブジェクト作成者」のロールを割り当てる。

作成・設定が終わったらサービスアカウントの「鍵」タブから JSON 形式の新しいキーを生成し、ダウンロードしておきます。

BaseMachina の監査ログストリーミング設定を変更

監査ログのストリーミング設定はとても簡単です。用意したバケット名とダウンロードしておいたサービスアカウントキーの内容をコピペするだけで OK。S3 からの切り替えはほんの数秒で完了しました。

BaseMachina から BigQuery 上の監査ログを検索してみる

BigQuery 版のアクションでは、以下のようなクエリを発行するようにしました。date_from のみ必須で、その他の条件は任意としており、BaseMachina のアクションで実行するために少し複雑なクエリになっています。

SELECT
  FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', timestamp, 'Asia/Tokyo') AS timestamp,
  user.email AS user_email,
  user.name AS user_name,
  action.id AS action_id,
  action.name AS action_name,
  client_ip,
  TO_JSON_STRING(arguments) AS arguments
FROM
  `<project_id>.<dataset>.<table>`
WHERE
  environment.id = {{ environment.id }}
  AND timestamp >= TIMESTAMP({{ date_from }}, 'Asia/Tokyo')
  AND (
    {{ date_to }} = ''
    OR timestamp < TIMESTAMP_ADD(TIMESTAMP({{ date_to }}, 'Asia/Tokyo'), INTERVAL 1 DAY)
  )
  AND (
    {{ email }} = ''
    OR user.email = {{ email }}
  )
  AND (
    {{ action_id }} = ''
    OR action.id = {{ action_id }}
  )
ORDER BY
  timestamp DESC
;

元々 Athena 版のアクションでも似たようなクエリを用いて検索を行っていたので、それぞれのアクションでどれぐらい差が出ているのか、以下の条件でそれぞれのアクションを実行してみることにします。

  • 日付範囲:2025-09-21〜2025-09-30(10日間)
  • メールアドレス:自身のメールアドレス

すると Athena 版では結果が表示されるまで55秒掛かったのに対して BigQuery 版では約2秒と大幅な高速化が実現されました!

また、実行されるクエリをそれぞれコンソールで評価したところ、スキャンするデータ量も大きく異なることがわかりました。

  • Athena 版:約 422 MB
  • BigQuery 版:約 163 MB

スキャンするデータ量が4割弱となったことで、BigQuery の方が単価が高いにも関わらず今回のクエリによって発生するコストも Amazon Athena に比べておよそ 58% 程度(約4割減)となりました。クエリの条件によって細かい差はありそうですが、全体的にクエリあたりのコストは Athena よりも大きく抑えることができそうです。

まとめ

BaseMachina の監査ログを Amazon S3 + Athena から Google Cloud Storage + BigQuery に移行することで、分析機能を強化し、高速化しつつコストも抑えることに成功しました。

作業を進める中では Data Transfer Service のオブジェクト数制限など、ドキュメントを精読していないと知らないような予期せぬ制約に直面しましたが、今後も S3 や GCS、BigQuery を活用していく上でのいい学びになったと感じています。

これまでクラウドサービスは AWS を中心に触れてきましたが、これを機に Google Cloud についても理解を深めていきたいと思います。

【余談】AI がエンジニアリングを加速する体験

今回の一連の作業では AI による支援がエンジニアリングに与える影響を改めて実感することができました。実は自分にとって BigQuery や GCS に触れるのは今回の案件が初めてであり、何もわからない状態から着手しています。

弊社では AI コーディングエージェントや AI チャットツールが複数導入されており、今回は主に Gemini(2.5 Flash)を相談相手としながら作業を進めましたが、Google Cloud も Gemini も Google のプロダクトだから、という理由もあるのかもしれませんが、かなり正確な情報が提供された印象です。もちろん裏取りをしたり、既存の技術的な知識をベースに質問することで、よりよい方針を導き出す必要はあったものの、AI によってスムーズに作業を進めることができました。

はじめて触れる技術であっても AI と二人三脚で進めることができる、という体験は Google で検索しながら試行錯誤していた頃に比べると一線を画しており、時代が大きく変わったことを改めて体感することができました。

We are hiring!

PR TIMES ではクラウドインフラからフロントエンドまで、本人が希望すれば幅広い技術分野に挑戦できる環境・文化が整っています。興味を持ってくださった方は、ぜひ一度カジュアル面談にお越しください!

エンジニア採用情報|株式会社PR T...
エンジニア採用情報|株式会社PR TIMES 開発本部 株式会社PR TIMES のエンジニア採用サイトです。PRTIMESの開発本部は、「行動者発の情報が、人の心を揺さぶる時代へ」の実現に向けて、共に未来をつくっていくエンジニアを...
株式会社PR TIMES
02.開発部 の求人一覧 - 株式会社PR TIMES 株式会社PR TIMESが公開している、02.開発部 の求人一覧です
  • URLをコピーしました!

この記事を書いた人

PR TIMES のエンジニアリングマネージャー。
プレスリリース配信サービス「PR TIMES」の開発や開発チームのマネジメント、業務改善、採用などを行っています。
妻と一緒にももクロのライブに行くのが生きがい。

目次