如何从Startup.cs中编写日志

时间:2016-12-22 16:27:23

标签: c# asp.net-core

为了调试启动失败的.net核心应用程序,我想从startup.cs文件中编写日志。我在文件中有日志设置,可以在startup.cs文件之外的应用程序的其余部分中使用,但不知道如何从startup.cs文件本身写入日志。

12 个答案:

答案 0 :(得分:55)

随着ASP.NET Core 2.0的发布,这已经发生了重大变化。在ASP.NET Core 2.0中,将在主机构建器中创建日志记录。这意味着默认情况下可以通过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 :(得分:23)

选项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");
        ....
    }

输出:

serilog

要在asp.net-core应用程序中设置Serilog,请查看Serilog.AspNetCore package on GitHub

选项2:在这样的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.");
    }
}

有关此link

的详细信息

答案 2 :(得分:9)

.NET Core 3.1中,您可以直接使用LogFactory创建记录器。

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

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

答案 3 :(得分:6)

当前的官方解决方案是像这样设置本地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

答案 4 :(得分:4)

我使用的解决方案是避免第三方记录器通过 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())

答案 5 :(得分:1)

对于.NET Core 3.0,官方文档应这样说:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.0#create-logs-in-the-startup-class

  

不支持在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] Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to 'Configure'.

答案 6 :(得分:0)

我已经设法通过在文件中静态创建一个带有Nlog的记录器来完成此操作,然后在启动方法中使用它。

private readonly NLog.Logger _logger = new NLog.LogFactory().GetCurrentClassLogger();

答案 7 :(得分:0)

主要代码:

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,但也许这是因为它不是控制器。更多信息欢迎!

参考文献:

答案 8 :(得分:0)

现有答案中没有一个对我有用。我正在使用NLog,甚至构建一个新的ServiceCollection,在任何服务集合上调用.CreateBuilder(),创建一个日志记录服务……在ConfigureServices期间,这些都不会写入日志文件。

问题在于,直到构建ServiceCollection之后,日志记录才真正成为问题,并且在ConfigureServices期间不会构建日志记录。

基本上,我只想(需要)使用配置扩展方法记录启动过程中发生的情况,因为我遇到问题的唯一层是PROD,我无法在其中附加调试器。

最适合我的解决方案是使用旧的.NET Framework NLog方法:

private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();

在扩展方法类中添加了该权限,因此我能够在ConfigureServices期间及之后写入日志(“ the”日志)。

我不知道将其实际发布到生产代码中是否是一个好主意(我不知道.NET控制的ILogger和此NLog.ILogger是否会在任何时候发生冲突),但是我只需要它来查看发生了什么事。

答案 9 :(得分:0)

使用 Rolf's answer,我把它放在我的启动构造函数中:

private readonly ILogger _logger;

public Startup(IConfiguration configuration)
{
    Configuration = configuration;

    using var loggerFactory = LoggerFactory.Create(builder =>
    {
        builder.SetMinimumLevel(LogLevel.Information);
        builder.AddConsole();
        builder.AddEventSourceLogger();
    });
    _logger = loggerFactory.CreateLogger<Startup>();
}

public void ConfigureServices(IServiceCollection services)
{
    _logger.LogInformation("ConfigureServices...");
    // ...and so on...
}

答案 10 :(得分:-1)

这对我有用

private static readonly Logger logger = LogManager.GetLogger("Audit")

答案 11 :(得分:-2)

只需使用以下行登录Startup.cs

x <- seq_along(dat)

foo <- function(x, lwr, upr) {
  y <- x
  y[x <= lwr | x > upr] <- mean(dat[x <= lwr | x > upr])
  y[x > lwr & x <= upr] <- mean(dat[x > lwr & x <= upr])
  y
}

SSE <- function(lwr, upr) {
  sum((dat - foo(x, lwr, upr))^ 2) 
}

limits <- expand.grid(lwr = x, upr = x)
limits <- limits[limits$lwr <= limits$upr,]
nrow(limits)

SSEvals <- mapply(SSE, limits$lwr, limits$upr)

id <- which(SSEvals == min(SSEvals))
optlims <- limits[id,]
meanouter <-  mean(dat[x <= optlims$lwr | x > optlims$upr])
meaninner <- mean(dat[x > optlims$lwr & x <= optlims$upr])

bar <- function(x) {
  y <- x
  y[x <= optlims$lwr | x > optlims$upr] <- meanouter
  y[x > optlims$lwr & x <= optlims$upr] <- meaninner
  y
}

plot(dat/100)
curve(bar(x) / 100, add = TRUE)