ラボ > Laravel、Lumen:DB関連

laravel ログをDBに保存するけどロールバックの対象外にしたい(singleton())

トランザクション開始して例外発生でコールバックってのは問題無いけど、ログファイルまでロールバックされると困るとき…

作成日:2024-08-10, 更新日:2024-11-13

やりたいこと

下記のような感じのソースでログだけロールバックさせたくない

▼任意のファイルの任意のメソッド
try {
	\DB::beginTransaction();

	App\Lib\hoge::foo();
	if ( 問題アリのとき ) {
		throw new Exception('問題発生');
	}

	\DB::commit();
}
catch (Exception $e) {
	\DB::rollBack();
	echo $e->getMessage();
}

▼「App\Lib\hoge.php」
function foo() {
	// 処理の内容を任意のテーブルに保存
	// DBにログを保存
}

期待する出力内容

例外が発生しなかった時

// 処理の内容を任意のテーブルに保存
// DBにログを保存

例外が発生した時

// DBにログを保存

方法

  • ログをDBじゃなくファイル出力
  • ログの接続先を変更する

ログをDBじゃなくファイル出力

とりあえず下記のような感じ。一番手っ取り早い

\Log::info(〇〇〇〇);

ログの接続先を変更する

テーブルに何かするときにDBの接続先を変更
※接続先は同じなので「接続先」というより「接続名」といったほうがしっくりくる

  1. 下準備:接続先(接続名?)を用意
  2. 切替え:シングルトン(※グローバル変数の代わり)を使って接続先を切り替える

下準備:接続先(接続名?)を用意

接続先は「log_connection」とする
※「config/database.php」の「connections」のトコに追加。「mysql」をマルっとコピペして「log_connection」に変更

クエリ

クエリビルダ1
DB::connection('log_connection')->table(ログテーブル)->insert(['message' => 'エラーメッセージ']);
クエリビルダ2
$connection = DB::connection('log_connection');
$result = $connection->insert(['message' => 'エラーメッセージ']);
Eloquent ORM
$log = new \App\Models\ログテーブル();
$log->message = 'エラーメッセージ';
$log->setConnection('log_connection');
$log->save();

切替え:シングルトン(※グローバル変数の代わり)を使って接続先を切り替える

特定の条件のときだけ接続先を変更したい
→グローバル変数を使うのが手っ取り早いんだが…サービスコンテナの「シングルトンインスタンス」ってのを使う

  • シングルトンインスタンスの設定
  • ログ出力:シングルトンを使って接続先を変更する

シングルトンインスタンスの設定

接続先をログ用に…としたいので「ConnectDB」の「tblLog」としておく

▼app/Providers/AppServiceProvider.php

// 省略
class AppServiceProvider extends ServiceProvider
{
	public function register()
	{
		// 省略

		// DBの接続先。ロールバックでログが消えるのを避けたい
		$this->app->singleton('ConnectDB', function () {
			return (object) ['tblLog' => false];
			// usage. 値のセット: app('ConnectDB')->tblLog = true;
			// usage. 値の取得: app('ConnectDB')->tblLog
		});
	}
	// 省略

ログ出力:シングルトンを使って接続先を変更する

任意のタイミングで実行

app('ConnectDB')->tblLog = true;

ログ出力をメソッド化している時

個人的に…ログ出力をメソッド化していたので…

app('ConnectDB')->tblLog = true;
// メソッド化しているログ出力を実行
app('ConnectDB')->tblLog = false;

レコード挿入時

if (app('ConnectDB')->tblLog) {
	$connection = DB::connection('log_connection');
}
else {
	$connection = DB::connection(); // デフォルト設定で接続
}
$result = $connection->insert(['message' => 'エラーメッセージ']);