web-dev-qa-db-ja.com

複数のプロジェクトでSerilogにAsp.Net Core 2インジェクションを使用する

SerilogはAsp.Net Core 2.0用に構成されており、スタートアップWebプロジェクト(Microsoft.Extensions.Loggingを使用して使用する場合)で.Net Core依存性注入を介して良好に機能しますが、他のプロジェクトからはアクセスできません。

ここに私が持っているものがあります:

Program.cs

using System;
using System.IO;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Serilog;

namespace ObApp.Web.Mvc
{
    public class Program
    {
        public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
            .Build();

        public static void Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(Configuration)
                .CreateLogger();

            try
            {
                Log.Warning("Starting BuildWebHost");

                BuildWebHost(args).Run();
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Host terminated unexpectedly");
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseSerilog()
                .Build();
    }
}

Startup.cs

スタートアップ.csは純粋なデフォルトです。新しいAsp.Net Core MVCプロジェクトの元のテンプレートから変更したことはありません。

IServiceCollectionサービスにSerilogを追加する必要があるかもしれないと思っていましたが、記事Leaner、meaner ASP.NET Core 2 loggingat https:// nblumhardt。 com/2017/08/use-serilog / は不要だと教えてくれます。

その後、ぶらぶらしている他のロガー構成を削除できます。appsettings.jsonの「Logging」セクション、AddLogging()は不要で、Startup.csのILoggerFactoryを介した構成は不要です。

UseSerilog()は、組み込みのILoggerFactoryを置き換えるため、アプリケーション内のすべてのロガーは、SerilogのLogクラス、SerilogのILogger、Microsoft.Extensions.Logging.ILoggerのいずれであっても、同じSerilog実装でバックアップされ、同じ構成で制御されます。 。

私が期待したこと

ソリューションの任意のプロジェクトの任意のクラスのコンストラクターを介してロガーを単純に挿入する機能。例えば:

using Serilog;
public MyTestClass(ILogger logger) { ... }

私が得たもの-Web(スタートアップ)プロジェクト

Microsoft.Extensions.Loggingラッパーを使用すると、HomeControllerでインジェクションが機能します。

using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
        _logger.LogDebug("Controller instantiated.");
    }
}

Serilog.ILoggerをインジェクトしようとすると、プロジェクト/クラスでインジェクションが失敗します

using Serilog;
using Serilog.Extensions.Logging; // Not sure if this would help.

public class HomeController : Controller
{
    ILogger _logger;

    public HomeController(ILogger logger)
    {
        _logger = logger;
        _logger.Debug("Controller instantiated.");
    }
}

InvalidOperationException:「ObApp2.Web.Mvc.Controllers.HomeController」をアクティブ化しようとしているときに、「Serilog.ILogger」タイプのサービスを解決できません。

私の大きな問題-その他のプロジェクト

私のより大きな問題は、ソリューション内の別のプロジェクトで作業している場合、私が試したどの方法でもDI経由でロガーを取得できないことです。

Microsoft.Extensions.LoggingまたはSerilogのいずれかを使用して注入しようとすると、ビルド時に欠落パラメーター例外が発生します。

using Microsoft.Extensions.Logging;
namespace ObApp.Domain
{
    public class MyTestClass(ILogger<MyTestClass> logger) { ... }

- or -

using Serilog;
namespace ObApp.Domain
{
    public class MyTestClass(ILogger logger) { ... }

どちらも次のようなビルドエラーを生成します。

「MyTestClass.MyTestClass(ILogger)」の必須の仮パラメータ「logger」に対応する引数が指定されていません

質問

  1. このタイプのSerilog構成で注入する場合、注入を行うクラスファイルでMicrosoft.Extensions.LoggingまたはSerilogを参照することをお勧めしますか?

  2. DIをすべてのプロジェクトで機能させるにはどうすればよいですか?

13
platypusjh

私のために働いた1つの方法:

ConfigureServicesメソッドのAddSingleton()メソッドを使用して、Serilog.Core.Loggerのインスタンスを追加しました。これにより、DIの問題が解決しました。このステップは、StartUpコンストラクターでLoggerインスタンスをLog.Loggerに割り当てるステップを置き換えます。

services.AddSingleton((ILogger)new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.File(<...>)
            .CreateLogger());

また、クラスファイルの参照をSerilog.Iloggerを指すように変更します。

5
Rufus Lobo

このソリューションは、ロガーを外部プロジェクトまたはライブラリのクラスに正しく挿入します。

ルーファスが提案した答えも試しました。 OPで説明された問題はありませんでしたが、さらに奇妙な問題がありました。ILoggerが外部プロジェクトに挿入された後、MS SQLへのロギングが機能しなくなりました。コンソールロギングは機能しました。 Serilogは主に静的なサービスであるため、Log.Loggerファクトリーとして。利点は、「シングルトン」サービスに影響を与えることなく、ILogger参照をカスタマイズできることです(たとえば、コンストラクターにForContextを追加します)。

私は github に完全な実用的なソリューションを投稿しました。これには、DIをセットアップするコンソールプログラム(ASP.NET Coreからも同じように動作します)、Serilog開始除算を含む外部ライブラリが含まれます-zeroデモ、およびSerilogをサービスとして管理する別のライブラリ。

重要な部分であるSerilogサービスの登録は次のようになります(おまけとして、透過的なクリーンアップのためにProcessExitに結び付けます):

using Microsoft.Extensions.DependencyInjection;
using System;

namespace Serilog.Injection
{
    public static class RegisterSerilogServices
    {
        public static IServiceCollection AddSerilogServices(this IServiceCollection services)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .WriteTo.Console()
                .WriteTo.MSSqlServer(@"xxxxxxxxxxxxx", "Logs")
                .CreateLogger();

            AppDomain.CurrentDomain.ProcessExit += (s, e) => Log.CloseAndFlush();

            return services.AddSingleton(Log.Logger);
        }
    }
}
4
McGuireV10

Net CoreのDIを介してSerilogにアクセスすることはありません。それは静的です。 Program.Main()でLoggerを正しく構成して初期化し、スタートアップ、コントローラーなどの他の静的なものと同じように単純にアクセスします。

_public void ConfigureServices(IServiceCollection services)
            {
    Serilog.Log.Information("here I am in startup");
    //further options
};
_

または上部に追加:

_using static Serilog.Log;_

そして単純に:

Information("keystroke saving");

2
gorytus

私は実際にはまったく同じセットアップに苦労していましたが、うまくいくことができました。ソリューションは、次の点でコード例とわずかに異なります。

  • Microsoft.Extensions.Logging.ILoggerに依存します。
  • ロガーはILogger<Type>を使用して挿入されます

コントローラーコードは既にこれらの要件に適合しているため、機能しました。

using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    ILogger _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
        _logger.LogInformation("Controller instantiated");
    }
}

他のプロジェクトの他のクラスについては、Serilogの実装ではなく、デフォルトのILoggerインターフェイスに依存していることを確認してください。これには、後でSerilogを置き換えたい場合に、他のプロジェクト全体でSerilogへのすべての参照を削除することなくこれを実行できるという利点もあります。

using Microsoft.Extensions.Logging;

public class MyBusinessObject
{
    ILogger _logger;

    public MyBusinessObject(ILogger<MyBusinessObject> logger)
    {
        _logger = logger;
    }

    public void DoBusinessLog()
    {
        _logger.Information("Executing Business Logic");
    }
}

何らかの理由で、DIはILogger<Type>を必要とする場合にのみLoggerインスタンスのインスタンス化を管理しますが、ILoggerに対してはインスタンス化しません。なぜそれが正確にわからないのか、おそらく誰か他の人がそれに答えることができます。

1