.Net Core 3.1
Desafortunadamente, para ASP.NET Core 3.0, la situación es nuevamente un poco diferente. Las plantillas predeterminadas usan HostBuilder
(en lugar de WebHostBuilder
), que configura un nuevo host genérico que puede albergar varias aplicaciones diferentes, sin limitarse a aplicaciones web. Parte de este nuevo host es también la eliminación del segundo contenedor de inyección de dependencia que existía anteriormente para el host web. En última instancia, esto significa que no podrá inyectar ninguna dependencia aparte de IConfiguration
en la Startup
clase. Por lo tanto, no podrá iniciar sesión durante el ConfigureServices
método. Sin embargo, puede inyectar el registrador en el Configure
método e iniciar sesión allí:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
logger.LogInformation("Configure called");
}
Si es absolutamente necesario iniciar sesión ConfigureServices
, puede continuar usando el WebHostBuilder
que creará el legado WebHost
que puede inyectar el registrador en la Startup
clase. Tenga en cuenta que es probable que el servidor web se elimine en algún momento en el futuro. Por lo tanto, debe intentar encontrar una solución que funcione para usted sin tener que iniciar sesión ConfigureServices
.
.NET Core 2.x
Esto ha cambiado significativamente con el lanzamiento de ASP.NET Core 2.0. En ASP.NET Core 2.x, el registro se crea en el generador de host. Esto significa que el registro está disponible a través de DI de forma predeterminada y se puede inyectar en la Startup
clase:
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
ejecuta, el registrador todavía no existe. Por lo tanto, no podrá iniciar sesión en ese momento simplemente porque aún no hay un registrador. En el lado positivo, eso todavía le da la capacidad de configurar el registrador dentro delConfigureServices
ya que es el mismo contenedor DI (lo cual es realmente algo bueno). - Si es absolutamente necesario registrar cosas, por ejemplo, puede recopilar la información por separado (por ejemplo, en una lista) y luego cerrar la sesión tan pronto como el registrador esté disponible..NET 3.1
usted actualmente PUEDE iniciar sesión dentro delConfigureServices
método sin recurrir alWebHostBuilder
. Utilice la respuesta a continuación: stackoverflow.com/a/61488490/2877982Startup.cs
(por lo que obtengo errores de compilador cuando olvido una dependencia) en lugar de solo registrar dependencias personalizadas. Por lo tanto, necesito resolver estos registradores. Pero esto podría ser un poco complicado, sí.Opción 1: utilizar directamente el registro (por ejemplo, Serilog) en el inicio
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"); .... }
Salida:
Para configurar Serilog en la aplicación asp.net-core, consulte el paquete Serilog.AspNetCore en GitHub .
Opción 2: configurar el inicio de sesión en program.cs de esta manera-
var host = new WebHostBuilder() .UseKestrel() .ConfigureServices(s => { s.AddSingleton<IFormatter, LowercaseFormatter>(); }) .ConfigureLogging(f => f.AddConsole(LogLevel.Debug)) .UseStartup<Startup>() .Build(); host.Run();
User loggerFactory en inicio como este-
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."); } }
Detalles completos disponibles en este enlace
fuente
En .NET Core 3.1 , puede crear un registrador directamente usando LogFactory.
var loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); }); ILogger logger = loggerFactory.CreateLogger<Startup>(); logger.LogInformation("Example log message");
fuente
ILogger logger = LoggerFactory.Create(builder => builder.AddLog4Net()).CreateLogger<Startup>();
. Sin embargo, si solo registra excepciones, no revelará mucho más de lo que ya se muestra en el EventLog de Windows (cuando se usa IIS).Para .NET Core 3.0, los documentos oficiales tienen esto que decir: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.0#create-logs-in-startup
Pero como dicen en los documentos, puede configurar un servicio que depende de ILogger, por lo que si escribió una clase StartupLogger:
public class StartupLogger { private readonly ILogger _logger; public StartupLogger(ILogger<StartupLogger> logger) { _logger = logger; } public void Log(string message) { _logger.LogInformation(message); } }
Luego, en Startup.ConfigureServices agregue el servicio, luego necesita construir el proveedor de servicios para obtener acceso al contenedor 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"); }
Editar: esto produce una advertencia del compilador, en aras de depurar su clase de inicio, esto debería estar bien, pero no para producción:
fuente
La solución oficial actualmente es configurar una LoggerFactory local como esta:
using var loggerFactory = LoggerFactory.Create(builder => { builder.SetMinimumLevel(LogLevel.Information); builder.AddConsole(); builder.AddEventSourceLogger(); }); var logger = loggerFactory.CreateLogger("Startup"); logger.LogInformation("Hello World");
Véase también: https://github.com/dotnet/aspnetcore/issues/9337#issuecomment-539859667
fuente
Utilizo una solución que evita que los registradores de terceros implementen un "búfer de registrador" con la interfaz 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(); } }
El uso en startup.cs es fácil, por supuesto, obtiene una salida de registro después de llamar a Configure. Pero mejor que nada. :
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())
fuente
Código principal:
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 configura un registrador de consola predeterminado.
Código de inicio:
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"); }
No pude hacer funcionar la inyección de un ILogger, pero tal vez sea porque no es un controlador. ¡Más información bienvenido!
Refs:
fuente
Ninguna de las respuestas anteriores funcionó para mí. Estoy usando NLog, e incluso construyendo un nuevo ServiceCollection, llamando a .CreateBuilder () en cualquier colección de servicios, creando un servicio de registro ... nada de eso escribiría en un archivo de registro durante ConfigureServices.
El problema es que el registro no existe realmente hasta después de que se construye ServiceCollection, y no se construye durante ConfigureServices.
Básicamente, solo quiero (necesito) registrar lo que está sucediendo durante el inicio en un método de extensión de configuración, porque el único nivel en el que tengo un problema es PROD, donde no puedo adjuntar un depurador.
La solución que funcionó para mí fue usar el antiguo método .NET Framework NLog: agregué
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
ese derecho a la clase de método de extensión y pude escribir en un registro ("el" registro) durante ConfigureServices y después.No tengo idea si esta es una buena idea para publicarla en el código de producción (no sé si el ILogger controlado por .NET y este NLog.ILogger entrarán en conflicto en algún momento), pero solo lo necesitaba para ver qué estaba pasando. en.
fuente
Logré hacer esto creando estáticamente un registrador con Nlog en el archivo, luego lo uso dentro de los métodos de inicio.
private readonly NLog.Logger _logger = new NLog.LogFactory().GetCurrentClassLogger();
fuente
System.IO.File.Write()
métodos.Simplemente use la línea a continuación para iniciar sesión en Startup.cs
Log.Information("App started.");
fuente