시작시 실패하는 .net 핵심 앱을 디버깅하기 위해 startup.cs 파일 내에서 로그를 작성하고 싶습니다. startup.cs 파일 외부의 나머지 앱에서 사용할 수있는 파일 내에 로깅 설정이 있지만 startup.cs 파일 자체에서 로그를 작성하는 방법을 잘 모르겠습니다.
답변:
.Net Core 3.1
불행히도 ASP.NET Core 3.0의 경우 상황이 다시 약간 다릅니다. 기본 템플릿 은 웹 응용 프로그램에 국한되지 않고 여러 다른 응용 프로그램을 호스팅 할 수있는 새 일반 호스트를 설정 하는 HostBuilder
(대신 WebHostBuilder
)를 사용합니다. 이 새 호스트의 일부는 이전에 웹 호스트에 대해 존재했던 두 번째 종속성 주입 컨테이너를 제거하는 것이기도합니다. 이것은 궁극적으로 당신이 떨어져 종속성을 주입 할 수 없음을 의미합니다 IConfiguration
에 Startup
클래스입니다. 따라서 ConfigureServices
방법 중에는 로그를 기록 할 수 없습니다 . 그러나 로거를 Configure
메소드에 삽입하고 거기에 기록 할 수 있습니다.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
logger.LogInformation("Configure called");
// …
}
에서 반드시 로그인 해야하는 경우를 ConfigureServices
계속 사용할 수 있습니다 . 그러면 로거를 클래스에 삽입 할 수 WebHostBuilder
있는 레거시가 생성됩니다 . 웹 호스트는 향후 언젠가 제거 될 가능성이 있습니다. 따라서 .NET에 로그인하지 않고도 자신에게 맞는 솔루션을 찾아야합니다 .WebHost
Startup
ConfigureServices
.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");
// …
}
}
ConfigureServices
실행될 때까지 로거가 실제로 존재하지 않기 때문에 "어려움" 입니다. 따라서 아직 로거가 없기 때문에 해당 지점에서 로그를 기록 할 수 없습니다. 플러스 측면에서, 그것은 여전히 당신에게 로거를 구성 할 수있는 능력을 제공합니다.ConfigureServices
장점은 모두 동일한 DI 컨테이너이기 때문에 있다는 점입니다 (실제로는 좋은 것입니다). – 항목을 반드시 기록해야하는 경우, 예를 들어 정보를 별도로 수집 (예 : 목록) 한 다음 로거를 사용할 수있게되는 즉시 로그 아웃 할 수 있습니다.
.NET 3.1
당신은 현재 내에서 로그인 할 수있는 ConfigureServices
방법 없이 온 뒤 떨어지는 WebHostBuilder
. 아래 답변 사용 : stackoverflow.com/a/61488490/2877982
Startup.cs
대신 (종속성을 잊고 때 컴파일러 오류를 얻을 수 있도록) 만 등록 사용자 종속성. 따라서이 로거를 해결해야합니다. 그러나 이것은 약간 엉망 일 수 있습니다.
옵션 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");
ILogger logger = LoggerFactory.Create(builder => builder.AddLog4Net()).CreateLogger<Startup>();
. 그러나 예외 만 기록하면 Windows EventLog (IIS 사용시)에 이미 표시된 것보다 더 많이 표시되지 않습니다.
.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가 작동하도록 주입 할 수는 없지만 컨트롤러가 아니기 때문일 수 있습니다. 더 많은 정보를 환영합니다!
참조 :
위의 답변 중 어느 것도 나를 위해 일하지 않았습니다. 나는 NLog를 사용하고 있으며 심지어 새로운 ServiceCollection을 구축하고 모든 서비스 컬렉션에서 .CreateBuilder ()를 호출하고 로깅 서비스를 생성합니다.
문제는 로깅이 ServiceCollection이 빌드 될 때까지는 실제로 문제가되지 않으며 ConfigureServices 중에 빌드되지 않는다는 것입니다.
기본적으로 구성 확장 방법으로 시작하는 동안 무슨 일이 일어나고 있는지 기록하기를 원합니다. 왜냐하면 제가 문제가있는 유일한 계층은 디버거를 연결할 수없는 PROD이기 때문입니다.
나를 위해 일한 솔루션은 이전 .NET Framework NLog 방법을 사용하는 것입니다.
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
습니다. 확장 메서드 클래스에 해당 권한을 추가했으며 ConfigureServices 및 이후에 로그 ( "로그")에 쓸 수있었습니다.
이것이 실제로 프로덕션 코드로 릴리스하는 것이 좋은 아이디어인지는 모르겠지만 (.NET 제어 ILogger와이 NLog.ILogger가 어느 시점에서든 충돌하는지 여부는 모르겠습니다), 무슨 일이 일어나고 있는지보기 위해서만 필요했습니다. 의 위에.
파일에 Nlog를 사용하여 로거를 정적으로 만든 다음 시작 방법 내에서 이것을 사용하여이 작업을 수행했습니다.
private readonly NLog.Logger _logger = new NLog.LogFactory().GetCurrentClassLogger();
System.IO.File.Write()
방법 말고 다른 것 같아요 .