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

AWS Lambdaで.NETのILoggerを使いたい

Last updated at Posted at 2025-02-10

こんにちは。

テックリードのTerukiです。

.NETアプリをLambdaで動かす時はログをCloudWatchに飛ばしたいですよね。

ILambdaContextのLoggerを使えば良いのですが、Microsoft.Extensions.Loggingの ILoggerを使いたいというか、ILambdaContextのLoggerは微妙に使いづらいのであまり使いたくありません。

今日はその辺りをうまいことやれるようにする記事を書こうと思います。

やってみる

AWSが.NETアプリにCloudWatchをILogger経由で叩けるようにライブラリを用意してくれています。

NuGetパッケージをインストールすると、ConfigureLoggingの中かILoggerBuilderでCloudWatchに飛ばす処理を登録できます。

builder.Logging.AddAWSProvider();

EC2やFargateで動かす分にはこれで終了ですが、Lambdaではそうはいきません。

このコードをLambdaで動かしてログを出力すると中途半端なログがCloudWatchに飛んできます。

Lambdaは本処理が終わるとそのアプリのプロセスをフリーズさせますが、このライブラリはログを出力するコードとは別のスレッドでCloudWatchに送る処理が動いています。

このスレッドが処理を終える前にプロセスを止められてしまうためアプリ終了間際に出力されたログはCloudWatchに届きません。

というわけで本処理を終える前に明示的にログをCloudWatchに送るように指示することができればこの問題は解決します。

以下の例はConsoleAppFramework v5のフィルタで実装してみたものです。

internal class Filter(ConsoleAppFilter next, ILogger<Filter> Logger, IServiceProvider ServiceProvider) : ConsoleAppFilter(next) {
    /// <inheritdoc />
    public async override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken) {
        try {
            await Next.InvokeAsync(context, cancellationToken).ConfigureAwait(false);
        } catch (Exception e) {
            Logger.LogError(e, "例外が発生しました");
            throw;
        } finally {
            var loggerProvider = ServiceProvider.GetRequiredService<ILoggerProvider>();
            // AWS Loggerの場合
            if (loggerProvider is AWSLoggerProvider awsLoggerProvider) {
                var coreField = awsLoggerProvider.GetType().GetField("_core", BindingFlags.Instance | BindingFlags.NonPublic)!;
                var core = coreField.GetValue(awsLoggerProvider) as IAWSLoggerCore;
                // ログを無理やりフラッシュする
                core!.Flush();
            }
        }
    }
}

リフレクションを使わずに実装するのは厳しそうでした🥲

やってることはシンプルでfinallyの段階でLoggerProviderを取得してそれがAWSLoggerProviderだった場合はFlushする処理を明示的に呼んでいるだけです。

これで中途半端にログが送信される問題は解決します。

正攻法ではないので、プロダクションで使用するかは自己責任と思いますがMicrosoft.Extensions.LoggingのILoggerを使えるので便利です。

探したらライブラリなどでもうちょっと楽に出来る何かがある説はありますが、これがミニマムかなと思います。

おわりに

リフレクションを使用しているので、ライブラリのバージョンを上げた場合はちゃんとテストをする必要があると思います。
リフレクションを使わなくてもFlushを呼べたら良いのですが、それはまだできなさそうです。

短いですが、誰かの役に立てば良いなと。

Oh my teethについて

Oh my teethでは未来の歯科体験を創るために日々活動しています。

Techチームではより良いユーザー体験を提供するべく、Webフロントエンドからバックエンド、スマホアプリに機械学習モデルなど、さまざまなプロダクトを開発しています。

一緒に未来の歯科体験を創りませんか?興味がある方は是非こちらを確認してください。

カジュアル面談も可能なので気軽に応募してみてください!

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