当前位置: 首页 > 知识库问答 >
问题:

从类库方法调用Serilog日志记录。NET 6最小API

赫连晋
2023-03-14

我设置了一个. Net 6核心最小API来使用SeriLog登录MS SQL Server。在我的类库中,只有当我修改了类库中的构造函数时,我才设法用SeriLog进行日志记录。我试图避免修改我的类库类或方法的构造函数。

在我使用控制台应用程序的经验中,如果我在我的main Program.cs中设置了SeriLog,那么我可以在我的类库中的任何类中使用日志记录,而无需将日志记录器传递给构造函数。所以,我可以用Log。信息(“我的消息”)在类库的任何地方,它的工作。我正试图在一个. Net 6最小API项目中用我的Program.cs实现同样的效果。

我觉得从这个主题的其他问题来看,应该可以做到。特别是这个答案,其中的答案是:

你不必在类库里做任何事情。只有主应用程序具有合成根(应用程序生命周期中可以设置对象图的最早点)。

因此,根据上述内容,在我的API程序中.CS,我有这个代码(我已经在注释中指出了哪些有效,哪些无效):

//Configure SeriLog
builder.Logging.ClearProviders();
var appSettings = new ConfigurationBuilder()
   .SetBasePath(Directory.GetCurrentDirectory())
   .AddJsonFile("appsettings.json")
   .Build();

var logDB = 
builder.Configuration.GetSection("ConnectionStrings:Default").Value;
var sinkOpts = new MSSqlServerSinkOptions { TableName = "Logs" };
var columnOptions = new ColumnOptions();

var logger = new LoggerConfiguration()
   .MinimumLevel.Override("Microsoft", 
Serilog.Events.LogEventLevel.Information)
  .WriteTo.MSSqlServer(
      connectionString: logDB,        
      sinkOptions: sinkOpts,
      columnOptions: columnOptions,
      appConfiguration: appSettings
    ).CreateLogger();

builder.Logging.AddSerilog(logger);

//Depency injection for Class Library method 
//LoggerTestClass is a class in my Class Library project
builder.Services.AddScoped<ILoggerTestClass, LoggerTestClass>();

var app = builder.Build();
app.ConfigureTestAPI();

方法“ConfigureTestAPI()”位于如下所示的扩展类中:

public static class API_Test
{

public static void ConfigureTestAPI(this WebApplication app) 
//Extension method for app
{               
    app.MapGet("/test/", GetTest);
    
}

private static async Task<IResult> GetTest(int id, 
ILogger<LoggerTestClass> logger, ILoggerTestClass testClass)
{
    try
    {
        try
        {
            //This works
            logger.LogInformation("Starting test now");  

            //This does NOT work
            Log.Information("Using Log. directly"); 

            
            testClass.Test();  //Call to class library method

            logger.LogInformation("Test finished");  //Also works
            return Results.Ok("OK");
        }
        catch (Exception ex)
        {
            return Results.Problem(ex.Message);
        }
    }
    catch (Exception ex)
    {
        return Results.Problem(ex.Message);
    }
 }
}

最后,这是我的类库中包含测试方法的类:

    namespace TestingLib.Testing;
public class LoggerTestClass : ILoggerTestClass
{

    private Microsoft.Extensions.Logging.ILogger _logger;

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

    public void Test()
    {
        try
        {

           //Does not work
           Log.Information("Test logging from class library using Log.");

           //Does not work
           Log.Logger.Information("In Test Class in DLL. Trying loging with [Log.Logger.Information]");

           //This works
           _logger.LogInformation("In Test Class in DLL. Trying loging with [_logger.LogInformation]");
        }
        catch (Exception ex)
        {
            Log.Error("An error in class library");
        }
    }

}

共有1个答案

武琛
2023-03-14

我发现问题是我的API程序中缺少一行代码.cs文件。我需要添加:“Log.Logger = logger;”在设置SeriLog记录器之后。

工作解决方案的代码如下。

在我的. NET6 APIProgram.cs文件中,我有这个:

var builder = WebApplication.CreateBuilder(args);

//Configure SeriLog
builder.Logging.ClearProviders();
var appSettings = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json")
    .Build();

var logDB = builder.Configuration.GetSection("ConnectionStrings:Default").Value;
var sinkOpts = new MSSqlServerSinkOptions { TableName = "Logs" };
var columnOptions = new ColumnOptions
{
    AdditionalColumns = new Collection<SqlColumn>
    {
        new SqlColumn("UserID", SqlDbType.Int),
        new SqlColumn("RunTag", SqlDbType.NVarChar),
        new SqlColumn("CustomType", SqlDbType.NVarChar)
    }
};

var logger = new LoggerConfiguration()
    .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Information)
    .WriteTo.MSSqlServer(
        connectionString: logDB,
        sinkOptions: sinkOpts,
        columnOptions: columnOptions,
        appConfiguration: appSettings
    ).CreateLogger();

builder.Logging.AddSerilog(logger);

//NOTE that this is not needed
//builder.Services.AddScoped<TestingLib.Testing.ILoggerTestClass, TestingLib.Testing.LoggerTestClass>();

然后在这个文件的下部,我有这个:

Log.Logger = logger; //This was the line I was missing!

var app = builder.Build();

我调用类库的API Get方法现在看起来像这样(如果与问题中的原始方法相比,您将看到不再需要传递ILogger):

private static async Task<IResult> GetTest(int id)
    {
        try
        {
            try
            {
                string runTag = "In API GetTest(id)";
                string custom = "Calling from API method";                
                Log.Information("{Message}-{RunTag}-{CustomType}", "Message logging in API method", runTag, custom);
                
                //Call to Class Library Method - no need to pass ILogger
                LoggerTestClass testClass = new LoggerTestClass();
                testClass.Test();
               
                return Results.Ok("OK");
            }
            catch (Exception ex)
            {
                return Results.Problem(ex.Message);
            }
        }
        catch (Exception ex)
        {
            return Results.Problem(ex.Message);
        }
    }

最后,这是我的类库中的完整测试类。类库包含对 SeriLog 的引用:

using Serilog;

namespace TestingLib.Testing;
public class LoggerTestClass //: ILoggerTestClass
{

    public LoggerTestClass()
    {
        //No need to pass in ILogger to class
    }

    public void Test()
    {
        try
        {
            string runTag = "In Class Library Method)";
            string custom = "Calling class library method Test()";
            Log.Information("{Message}-{RunTag}-{CustomType}", "Message logging in Class Library", runTag, custom);            
        }
        catch (Exception ex)
        {
            Log.Error("An error in class library");
        }
    }

}

我发现这非常适合我的项目。从类库登录直接进入我的SQL数据库,带有自定义列等。

 类似资料:
  • 主要内容:Logger日志方法的例子,Logger的日志方法Logger 类有多种方法来处理日志记录活动。Logger 类不允许我们实例化一个新的 Logger 实例,但它支持两种获取 Logger 对象的静态方法: 两个方法中的第一个返回应用程序实例的根记录器,它没有名称。 任何其他命名的 Logger 对象实例都是通过传递记录器的名称由第二种方法获得的。记录器的名称可以是您传递的任何字符串,通常是类或包名称,如下所述: Logger日志方法的例子 Lo

  • 一般来说,你应该在运行时增加调试选项来调试问题;也可以把调试选项添加到 Ceph 配置文件里来调试启动问题,然后查看 /var/log/ceph (默认位置)下的日志文件。 Tip 调试输出会拖慢系统,这种延时有可能掩盖竞争条件。 日志记录是资源密集任务。如果你碰到的问题在集群的某个特定区域,只启用那个区域对应的日志功能即可。例如,你的 OSD 运行良好、元数据服务器却不行,这时应该先打开那个可疑

  • 我想在我的应用程序中使用SLF4J+logback用于两个目的--日志和审计。 14:41:57.978[main]信息AUDIT_LOGGER-110欢迎使用main 如何确保审核消息在审核记录器下只出现一次?

  • 问题内容: 我正在考虑将Redis用于Web应用程序日志记录目的。我用谷歌搜索,有人将日志转储到Redis队列/列表中,然后将计划的工作人员转储到磁盘中。 http://nosql.mypopescu.com/post/8652869828/another-redis-use-case- centralized-logging 我希望寻求理解,为什么不直接使用Redis持久化到磁盘?如果我分配了一

  • logging 模块自 2.3 版以来一直是 Python 标准库的一部分。在 PEP 282 中有对它的简洁描述。除了 基础日志教程 之外,这些文档是非常难以阅读的。 日志记录一般有两个目的: 诊断日志 记录与应用程序操作相关的日志。例如,当用户遇到程序报错时, 可通过搜索诊断日志以获得上下文信息。 审计日志 为商业分析而记录的日志。从审计日志中,可提取用户的交易信息, 并结合其他用户资料构成用

  • 我正在使用Python日志模块,并希望禁用由我导入的第三方模块打印的日志消息。例如,我使用的是如下所示: 当我执行logger.debug时,它会输出我的调试消息(“my Message!”),但它也会从我导入的任何模块中输出调试消息(如请求和许多其他东西)。 我只想看到我感兴趣的模块的日志消息。有没有可能让日志模块做到这一点?