[c#] Startup.cs 내에서 로그를 작성하는 방법

시작시 실패하는 .net 핵심 앱을 디버깅하기 위해 startup.cs 파일 내에서 로그를 작성하고 싶습니다. startup.cs 파일 외부의 나머지 앱에서 사용할 수있는 파일 내에 로깅 설정이 있지만 startup.cs 파일 자체에서 로그를 작성하는 방법을 잘 모르겠습니다.



답변

.Net Core 3.1

불행히도 ASP.NET Core 3.0의 경우 상황이 다시 약간 다릅니다. 기본 템플릿 은 웹 응용 프로그램에 국한되지 않고 여러 다른 응용 프로그램을 호스팅 할 수있는 새 일반 호스트를 설정 하는 HostBuilder(대신 WebHostBuilder)를 사용합니다. 이 새 호스트의 일부는 이전에 웹 호스트에 대해 존재했던 두 번째 종속성 주입 컨테이너를 제거하는 것이기도합니다. 이것은 궁극적으로 당신이 떨어져 종속성을 주입 할 수 없음을 의미합니다 IConfigurationStartup클래스입니다. 따라서 ConfigureServices방법 중에는 로그를 기록 할 수 없습니다 . 그러나 로거를 Configure메소드에 삽입하고 거기에 기록 할 수 있습니다.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
    logger.LogInformation("Configure called");

    // …
}

에서 반드시 로그인 해야하는 경우를 ConfigureServices계속 사용할 수 있습니다 . 그러면 로거를 클래스에 삽입 할 수 WebHostBuilder있는 레거시가 생성됩니다 . 웹 호스트는 향후 언젠가 제거 될 가능성이 있습니다. 따라서 .NET에 로그인하지 않고도 자신에게 맞는 솔루션을 찾아야합니다 .WebHostStartupConfigureServices


.NET Core 2.x

이것은 ASP.NET Core 2.0 릴리스와 함께 크게 변경되었습니다. ASP.NET Core 2.x에서는 호스트 작성기에서 로깅이 생성됩니다. 즉, 로깅은 기본적으로 DI를 통해 사용할 수 있으며 Startup클래스에 삽입 할 수 있습니다 .

public class Startup
{
    private readonly ILogger<Startup> _logger;

    public IConfiguration Configuration { get; }

    public Startup(ILogger<Startup> logger, IConfiguration configuration)
    {
        _logger = logger;
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        _logger.LogInformation("ConfigureServices called");

        // …
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        _logger.LogInformation("Configure called");

        // …
    }
}


답변

옵션 1 : 시작시 로그 (예 : Serilog) 직접 사용

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        Log.Logger = new LoggerConfiguration()
           .MinimumLevel.Debug()
           .WriteTo.RollingFile(Path.Combine(env.ContentRootPath, "Serilog-{Date}.txt"))
           .CreateLogger();

        Log.Information("Inside Startup ctor");
        ....
    }

    public void ConfigureServices(IServiceCollection services)
    {
        Log.Information("ConfigureServices");
        ....
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        Log.Information("Configure");
        ....
    }

산출:

세릴 로그

asp.net-core 애플리케이션에서 Serilog를 설정하려면 GitHub 에서 Serilog.AspNetCore 패키지를 확인하세요 .


Option2 : 다음 과 같이 program.cs에 로그인을 구성합니다 .

var host = new WebHostBuilder()
            .UseKestrel()
            .ConfigureServices(s => {
                s.AddSingleton<IFormatter, LowercaseFormatter>();
            })
            .ConfigureLogging(f => f.AddConsole(LogLevel.Debug))
            .UseStartup<Startup>()
            .Build();

host.Run();

이와 같이 시작하는 사용자 loggerFactory-

public class Startup
{
    ILogger _logger;
    IFormatter _formatter;
    public Startup(ILoggerFactory loggerFactory, IFormatter formatter)
    {
        _logger = loggerFactory.CreateLogger<Startup>();
        _formatter = formatter;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        _logger.LogDebug($"Total Services Initially: {services.Count}");

        // register services
        //services.AddSingleton<IFoo, Foo>();
    }

    public void Configure(IApplicationBuilder app, IFormatter formatter)
    {
        // note: can request IFormatter here as well as via constructor
        _logger.LogDebug("Configure() started...");
        app.Run(async (context) => await context.Response.WriteAsync(_formatter.Format("Hi!")));
        _logger.LogDebug("Configure() complete.");
    }
}

링크에서 사용 가능한 전체 세부 정보


답변

.net core 3.1 에 따르면 LogFactory를 사용하여 직접 로거를 만들 수 있습니다.

var loggerFactory = LoggerFactory.Create(builder =>
{
     builder.AddConsole();
});

ILogger logger = loggerFactory.CreateLogger<Startup>();
logger.LogInformation("Example log message");


답변

.NET Core 3.0의 경우 공식 문서에는 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.0#create-logs-in-startup이 나와 있습니다.

Startup.ConfigureServices메서드 에서 DI 컨테이너 설정을 완료하기 전에 로그를 작성하는 것은 지원되지 않습니다.

  • Startup생성자에 로거 주입 은 지원되지 않습니다.
  • Startup.ConfigureServices메서드 서명에 로거 삽입 은 지원되지 않습니다.

그러나 문서에서 말했듯이 ILogger에 의존하는 서비스를 구성 할 수 있으므로 StartupLogger 클래스를 작성한 경우 :

public class StartupLogger
{
    private readonly ILogger _logger;

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

    public void Log(string message)
    {
        _logger.LogInformation(message);
    }
}

그런 다음 Startup.ConfigureServices에서 서비스를 추가 한 다음 DI 컨테이너에 액세스 할 수 있도록 서비스 공급자를 빌드해야합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(provider =>
    {
        var service = provider.GetRequiredService<ILogger<StartupLogger>>();
        return new StartupLogger(service);
    });
    var logger = services.BuildServiceProvider().GetRequiredService<StartupLogger>();
    logger.Log("Startup.ConfigureServices called");
}

편집 : 이것은 StartUp 클래스를 디버깅하기 위해 컴파일러 경고를 생성하지만 프로덕션에는 적합하지 않습니다.

Startup.cs (39, 32) : [ASP0000] 응용 프로그램 코드에서 ‘BuildServiceProvider’를 호출하면 단일 서비스의 추가 복사본이 생성됩니다. 종속성 주입 서비스와 같은 대안을 ‘구성’에 대한 매개 변수로 고려하십시오.


답변

공식 솔루션은 현재 다음과 같이 로컬 LoggerFactory를 설정하는 것입니다.

    using var loggerFactory = LoggerFactory.Create(builder =>
    {
        builder.SetMinimumLevel(LogLevel.Information);
        builder.AddConsole();
        builder.AddEventSourceLogger();
    });
    var logger = loggerFactory.CreateLogger("Startup");
    logger.LogInformation("Hello World");

참조 : https://github.com/dotnet/aspnetcore/issues/9337#issuecomment-539859667


답변

ILogger 인터페이스 로 “로거 버퍼”를 구현하는 타사 로거를 피하는 솔루션을 사용합니다 .

public class LoggerBuffered : ILogger
{
    class Entry
    {
        public LogLevel _logLevel;
        public EventId  _eventId;
        public string   _message;
    }
    LogLevel            _minLogLevel;
    List<Entry>         _buffer;
    public LoggerBuffered(LogLevel minLogLevel)
    {
        _minLogLevel = minLogLevel;
        _buffer = new List<Entry>();
    }
    public IDisposable BeginScope<TState>(TState state)
    {
        return null;
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        return logLevel >= _minLogLevel;
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        if (IsEnabled(logLevel)) {
            var str = formatter(state, exception);
            _buffer.Add(new Entry { _logLevel = logLevel, _eventId = eventId, _message = str });
        }
    }
    public void CopyToLogger (ILogger logger)
    {
        foreach (var entry in _buffer)
        {
            logger.Log(entry._logLevel, entry._eventId, entry._message);
        }
        _buffer.Clear();
    }
}

startup.cs에서의 사용법은 쉽습니다. 물론 Configure를 호출 한 후 로그 출력을 얻습니다. 그러나없는 것보다 낫습니다. :

public class Startup
{
ILogger         _logger;

public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
    _logger = new LoggerBuffered(LogLevel.Debug);
    _logger.LogInformation($"Create Startup {env.ApplicationName} - {env.EnvironmentName}");

}

public void ConfigureServices(IServiceCollection services)
{
    _logger.LogInformation("ConfigureServices");
    services.AddControllersWithViews();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
    (_logger as LoggerBuffered).CopyToLogger(logger);
    _logger = logger;   // Replace buffered by "real" logger
    _logger.LogInformation("Configure");

    if (env.IsDevelopment())


답변

주요 코드 :

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

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

CreateDefaultBuilder 는 기본 콘솔 로거를 설정합니다.

… ILoggerFactory를 구성하여 콘솔에 기록하고 출력을 디버그합니다.

시작 코드 :

using Microsoft.Extensions.Logging;
...
public class Startup
{
    private readonly ILogger _logger;

    public Startup(IConfiguration configuration, ILoggerFactory logFactory)
    {
        _logger = logFactory.CreateLogger<Startup>();
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        _logger.LogInformation("hello stackoverflow");
    }

ILogger가 작동하도록 주입 할 수는 없지만 컨트롤러가 아니기 때문일 수 있습니다. 더 많은 정보를 환영합니다!

참조 :