ASP.Net Core Serilog如何在运行时读取日志文件

10
我正在开发一个基于ASP.NET Core 3.1的应用程序。我希望能够将事件记录到文件中,并且能够在应用程序运行时读取它们。为此,我尝试使用Serilog.Extensions.Logging.File NuGet包,并将日志文件路径指定如下:

Startup.cs

 public void Configure(IApplicationBuilder app, ILoggerFactory logFactory)
 {
     logFactory.AddFile("Log");
 }

任何试图以这种方式读取或写入文件的尝试
string ReadLog(string logPath)
{
    return System.IO.File.ReadAllText(logPath);
}

System.IO.IOException:“由于正在被另一个进程使用,因此无法访问文件 {log-path}。” 异常结束。


编辑:我已安装Serilog.AspNetCore,并进行了如下更改,同时从 Configure 函数中删除了 logFactory。但是异常仍然发生。


Program.cs

public static int Main(string[] args)
{
    Log.Logger = new LoggerConfiguration()
        .MinimumLevel.Debug()
        .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
        .Enrich.FromLogContext()
        .WriteTo.Console()
        .WriteTo.File(
            "Logs/log-.txt", 
            shared: true,
            flushToDiskInterval: TimeSpan.FromSeconds(5),
            rollingInterval: RollingInterval.Day)
        .CreateLogger();

    try
    {
        Log.Information("Starting web host");
        CreateHostBuilder(args).Build().Run();
        return 0;
    }
    catch (Exception ex)
    {
        Log.Fatal(ex, "Host terminated unexpectedly");
        return 1;
    }
    finally
    {
        Log.CloseAndFlush();
    }
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        }).UseSerilog();

编辑2:根据julealgon的请求,我分享我的精确读取逻辑。我正在尝试使用一个控制器进行读取,我按照以下方式声明了它:

[Controller]
[Route("[controller]")]
public class LogController : Controller
{
    [Route("Read")]
    public IActionResult ReadLog(string logPath)
    {
        if (System.IO.File.Exists(logPath))
        {
            string logContent = System.IO.File.ReadAllText(logPath);//exception appears here.
            return Content(logContent);
        }
        else return NotFound();
    }
}

然后使用下面的示例查询来读取2020年3月13日星期五记录的日志。
https://localhost:44323/Log/Read?logPath=Logs\log-20200313.txt

2
你可能需要检查一下你配置日志记录器的方式。推荐的方法是在 Program.cs 中使用来自这里AddSerilog 扩展进行配置。 - julealgon
文档来看,AddFile()方法似乎不接受shared参数。 - Fei Han
你能分享一下你的确切读取逻辑吗?这个文件路径 "Logs/log-.txt" 真的是你要读取的路径吗? - julealgon
@julealgon 当然可以。请查看我的更新问题。 - Nazar Antonyk
2个回答

8
在配置File接收器时,有一个重载可提供shared布尔参数。如果将其设置为true(默认为false),则应该能够在应用程序的其他位置读取文件的内容。

2
没错!https://github.com/serilog/serilog-sinks-file - 要启用多进程共享日志文件,请将 shared 设置为 true:.WriteTo.File("log.txt", shared: true) - asawyer
似乎对我不起作用。在 .Net 6 应用程序的其他地方使用 StreamReader 仍然会显示“正在被另一个进程使用”。 - PBMe_HikeIt
1
@PBMe_HikeIt,你能否发布一下你是如何创建StreamReader实例的?你是否在构造函数中显式传递了共享选项?如果没有,你可以尝试一下吗? - julealgon
1
@julealgon,我之前没有传递那个参数,现在修复了问题。谢谢! - PBMe_HikeIt

7
当阅读文件时,我认为使用类似以下的内容会起作用:
using (var stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var reader = new StreamReader(stream))
{
    return reader.ReadToEnd();
}

该技巧的关键似乎是将FileShare.ReadWrite指定为写入时汇聚打开日志文件时使用的策略。在serilog-sinks-file仓库中报告了类似的错误

C# 6没有'ReadAllBytes'方法。 - OverMars
1
@OverMars - 是的,你说得对,当我写答案时那是我的失误,ReadAllBytes是我在一个公共库中拥有的扩展方法。我已经更新了答案,使用了逻辑上等价的内容。 - Mike Goatly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接