こんにちは!PR TIMES ソフトウェアエンジニアの河瀨翔吾(@shogogg)です。現在はバックエンド開発を主に担当しています。好きな秋の味覚は秋刀魚ですが、今年はまだ食べられていません😢。
今回は BaseMachina(ベースマキナ)の監査ログを BigQuery 経由で参照できるようにした背景や試行錯誤した経験、具体的な手法についてお話しします!
BaseMachina(ベースマキナ)とは
BaseMachina は株式会社ベースマキナが開発・運営するローコード SaaS です。手間の掛かる管理画面の開発を少ないコードで実現できる他、bridge と呼ばれる仕組みで安全に社内のデータにアクセスできる仕組みが特徴です。
詳しくは BaseMachina の公式サイトをご覧ください。
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 のサービスです。
さて、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月現在)。
BigQuery を使う場合
発生する費用はストレージ利用料に加えて、BigQuery のストレージ利用料とクエリごとに「スキャンしたデータ量に基づく従量課金」が発生します。クエリへの課金は USD 7.5/TiB であり Amazon Athena よりも割高ですが、毎月 1.0 TiB までの無料枠が設定されています(2025年10月現在)。
さらに、BigQuery ではスキャンする列を適切に指定することでスキャンするデータ量を実際に保管しているデータ量よりも少なく抑えることが可能です。Amazon Athena を使う場合のスキャン対象はあくまで JSON ファイルのままなので、パーティションを設定したとしても期間中の監査ログ全量を対象にスキャンが発生します。
無料枠があることに加えてスキャンするデータ量を抑えるようクエリを最適化すれば、BigQuery の方がコストを抑えられる可能性すらありそうです。
また、ストレージ利用料が S3 と BigQuery で二重に発生してしまいますが、S3 に保管されたデータを転送後一定期間経過した時点で削除するように設定すれば、その費用は最小限に抑えられます。また、BigQuery のストレージ利用料には無料枠も設定されており、無料〜極めて低い金額に抑えることもできそうです。
以上の通りコスト面での課題はほぼないに等しく、BigQuery を経由することで得られるメリットが大きいことから BigQuery の導入を決定しました。BaseMachina にデータソースとして BigQuery が追加されたことも後押しとなっています。

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 URI:
s3://{{ 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万件のデータを転送することができます。

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のみです。よって、次のように必要最低限の権限のみを持つサービスアカウントを作成・設定します。
- Google Cloud コンソールから IAM と管理 » サービスアカウントにアクセスし、新しいサービスアカウントを作成する。この時、汎用的なロール・権限は付与しない。
- 同じく Google Cloud コンソールから Cloud Storage » バケットにアクセスし、監査ログ転送先として用いるバケットの詳細画面へ移動する。
- バケットの「権限」タブで「アクセスを許可」から、用意したサービスアカウントに「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 ではクラウドインフラからフロントエンドまで、本人が希望すれば幅広い技術分野に挑戦できる環境・文化が整っています。興味を持ってくださった方は、ぜひ一度カジュアル面談にお越しください!



