我有一个类级别的 ILogger,它是在构造函数中使用 ILoggerFactory 设置的。然后在该类的方法中使用记录器,效果非常好。
我正在努力研究如何模拟 ILogger 和 ILoggerFactory,以便我可以对 LogError 消息进行单元测试。谁能给我举个例子吗?
我使用 xUnit 和 Microsoft.Extentions.Logging 进行登录
//This is my unit test project
[Fact]
public void TestLogErrorMessage()
{
MyClass myClass = new MyClass (MockLoggerFactory().Object);
var result = myClass.Mymethod("a")
//How do I test the LogError message???
}
//Not sure if this is correct
private Mock<ILoggerFactory> MockLoggerFactory()
{
Mock<ILoggerFactory> mockLoggerFactory = new
Mock<ILoggerFactory>(MockBehavior.Default);
mockLoggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>()))
.Returns(MockLogger().Object);
return mockLoggerFactory;
}
private Mock<ILogger> MockLogger()
{
var logger = new Mock<ILogger>();
return logger;
}
Run Code Online (Sandbox Code Playgroud)
//This is …Run Code Online (Sandbox Code Playgroud) 我正在我们的 ASP.NET Core 3 应用程序中设置一些日志记录,使用 ILogger (Microsoft.Extensions.Logging) 和 NLog 来启用写入文本文件。
问题是,ILogger 不写入跟踪和调试级别的消息。文本文件或 Visual Studio 输出窗口。使用 NLog.Logger 适用于所有级别。这个问题也存在于默认的 ASP.NET Core 3 Web API 应用程序中,从他们的官方教程中设置了 NLog。以下是我拥有的相关代码。
程序.cs
public static void Main(string[] args)
{
var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
try
{
logger.Trace("NLog Trace from Main()");
logger.Debug("NLog Debug from Main()");
logger.Info("NLog Info from Main()");
logger.Warn("NLog Warn from Main()");
logger.Error("NLog Error from Main()");
logger.Fatal("NLog Fatal from Main()");
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
//NLog: catch setup errors
logger.Error(exception, "Stopped program because of exception");
throw;
}
finally …Run Code Online (Sandbox Code Playgroud) 有没有办法读取/获取“当前范围”值?例如,我在 IPageFilter 中添加了一些“全局上下文”值:
// OnPageHandlerExecuting
var contextScopeValues = new Dictionary<string, object>
{
{ "UserId", "user-id-value" }
};
contextScope = logger.BeginScope( contextScopeValues );
// OnPageHandlerExecuted
contextScope?.Dispose();
Run Code Online (Sandbox Code Playgroud)
如果我logger.LogInformation( "Doing something for {UserId}" );在任何页面处理期间调用,这将起作用并且消息将使用正确的UserId.
但是,在使用 时LoggerMessage,如果没有字符串参数,它会引发解析错误。
public static class LoggerMessages
{
private static readonly Action<ILogger> sampleActivity;
static LoggerMessages()
{
// This line throw exception because a parameter was 'expected'
sampleActivity = LoggerMessage.Define( "Start some activity for {UserId}" );
}
public static void SampleActivity( this ILogger logger ) …Run Code Online (Sandbox Code Playgroud) 我正在设置一个新的 Web 应用程序以通过 Application Insights 进行日志记录。我已经安装了 AI,并且看到了所有预期的遥测(服务器请求、失败的请求等),但没有通过 ILogger 发送日志记录。我已经浏览了在 SO 上可以找到的所有类似问题,但没有一个解决了我的问题。
我正在使用 .NET 5 和 Microsoft.ApplicationInsights.AspNetCore nuget 包的版本 2.17.0(最新稳定版)。连接字符串和检测密钥显示正确。我尝试在 TelemetryConfiguration 中打开开发人员模式。我正在尝试记录每个级别的日志,并且我的代码在功能上与我找到的所有示例相同。
我将 ApplicationInsights 的默认 LogLevel 设置为“Trace”:
VS 中的输出窗口显示,当我登录时,正在发送跟踪遥测数据:
但我在 Application Insights 中没有看到任何日志记录!我完全被难住了。任何有关解决此问题的帮助将不胜感激。谢谢你!
到目前为止,我们都是ILogger.LogXXX通过这种方式来模拟调用的。
不幸的是,在将项目更新到.net core 3.0之后,如果您使用严格的模拟(Moq),它总是会抱怨没有相应的设置:
Moq.MockException : ILogger.Log<FormattedLogValues>(LogLevel.Information, 0,
Inicio de cancelamento de reserva: Grm.GestaoFrotas.Dtos.Reservas.Mensagens.MsgCancelamentoReserva,
null,
Func<FormattedLogValues, Exception, string>) invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.
Run Code Online (Sandbox Code Playgroud)
不幸的是,我不能FormattedLogValues像这样简单地更改对象:
_container.GetMock<ILogger<GestorReservas>>()
.Setup(l => l.Log(It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<FormattedLogValues>(),
It.IsAny<Exception>(),
It.IsAny<Func<FormattedLogValues, Exception, string>()));
Run Code Online (Sandbox Code Playgroud)
这不会起作用,因为它FormattedLogValues是内部的。
我总是可以更改模拟策略(从严格到宽松),但我更愿意保持原样(严格)。那么,有关于如何解决这个问题的线索吗?
谢谢。
我按照这个文档Logging in .NET Core and ASP.NET Core,尝试将日志写入 Windows EventLog。
首先,我在 Windows 事件日志中创建源和日志:
if (!EventLog.SourceExists("MyTestSource"))
{
EventLog.CreateEventSource("MyTestSource", "MyTestLog");
return;
}
Run Code Online (Sandbox Code Playgroud)
它被创建了。
然后,我从我的 ASP.NET Core 应用程序(核心 3.0)的 Program.cs 配置了登录 CreateHostBuilder:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddEventLog(new EventLogSettings
{
SourceName = "MyTestSource",
LogName = "MyTestLog"
});
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Run Code Online (Sandbox Code Playgroud)
我认为仅此而已。然后我在我的控制器中使用记录器:
[Route("[controller]")]
[ApiController]
public class ServerController : ControllerBase
{
ILogger<ServerController> _logger = null;
public ServerController(ILogger<ServerController> logger)
{
_logger = logger;
}
[HttpGet("GetServerInfo")]
public …Run Code Online (Sandbox Code Playgroud) 我使用 c# 创建了一个简单的 Azure 函数,我想为其他类库实现 ILoggerFactory。这是我的代码。
MyFunction => Class1 => Class2
namespace FunctionApp1
{
public class MyFunction
{
private readonly ILogger _log;
private readonly IClass1 _class1;
public MyFunction(ILoggerFactory loggerFactory, IClass1 class1)
{
_log = loggerFactory.CreateLogger<MyFunction>();
_class1 = class1;
}
[FunctionName("Function1")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req)
{
_log.LogCritical("LogCritical MyFunction");
_log.LogInformation("LogInformation MyFunction");
_log.LogError("LogError MyFunction");
_log.LogWarning("LogWarning MyFunction");
string value = _class1.Test1(23);
return new OkObjectResult($"Hello, {value}");
}
}
}
namespace ClassLibrary1
{
public interface IClass1
{
string Test1(int …Run Code Online (Sandbox Code Playgroud) 当作为参数传递给 ilogger 时,对象在 Application Insights 自定义维度中呈现为字符串(对象的名称)。未显示实际值。
注册应用洞察
services.AddApplicationInsightsTelemetry();
Run Code Online (Sandbox Code Playgroud)
新日志
public class HealthController : ControllerBase
{
private readonly ILogger<HealthController> _logger;
public HealthController(ILogger<HealthController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
var health = new HealthViewModel()
{
ok = false
};
_logger.LogInformation("Hlep me pls {health}", health);
return Ok(health);
}
}
Run Code Online (Sandbox Code Playgroud)
结果
我不想对每个日志都这样做:
var health = new HealthViewModel()
{
ok = false
};
_logger.LogInformation("Hlep me pls {health}", JsonConvert.SerializeObject(health));
Run Code Online (Sandbox Code Playgroud)
我尝试为应用程序洞察创建一个中间件,但值仍然是对象的名称。
编辑
这好像是
var health = new
{
ok = …Run Code Online (Sandbox Code Playgroud) Microsoft.Extensions.Logging.ILogger<out TCategoryName>当我无法通过标准 ASP.NET Core 依赖项注入来实现将日志输出到我的 Serilog 记录器时,如何实例化一个记录器实现?
我在 ASP.NET Core 项目中配置了 Serilog,并且设置的标准依赖项注入正确地将记录器注入到我的控制器和服务中。这些记录器的输出已正确写入我的 Serilog 配置中指定的文件。
但是,我需要将记录器传递给在 期间实例化的对象Startup.ConfigureServices(...),因此我无法通过 DI 解析它。我可以实例化 a Serilog.Logger,但由于我想避免在配置代码之外直接依赖 Serilog,因此我被迫使用自己的适配器。我希望有一些现有的适配器可以使用Microsoft.Extensions.Logging.ILogger<out TCategoryName>,但我不知道如何做到这一点。
确切的用例是将记录器注入到 a 中DbCommandInterceptor,我正在尝试在其中执行以下操作Startup.ConfigureServices(...):
var databaseConfiguration = this.Configuration
.GetSection(nameof(DatabaseConfiguration))
.Get<DatabaseConfiguration>();
var interceptor = new LoggingDbCommandInterceptor(
warning => Log.Logger.Warning("{Warning}", warning),
error => Log.Logger.Error("{Error}", error),
databaseConfiguration);
var dbConfiguration = new MyDbConfiguration(interceptor);
DbConfiguration.SetConfiguration(dbConfiguration);
Run Code Online (Sandbox Code Playgroud) 我有一个类库和一个使用 Serilog 的测试集成示例应用程序。如何将记录器添加到类库中?我更喜欢Microsoft.Extensions.Logging,但我找不到一种无需依赖注入即可做到这一点的方法。
using System.Reactive.Disposables;
using Ardalis.GuardClauses;
using Binance.WebSocket.Client.Extensions;
using Binance.WebSocket.Client.Subscriptions;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.SystemConsole.Themes;
namespace Binance.WebSocket.Client.Sample;
public class Program
{
private static readonly ManualResetEvent ExitEvent = new(false);
private static async Task Main()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.FromLogContext()
.WriteTo.Console(LogEventLevel.Debug, theme: SystemConsoleTheme.Colored)
.WriteTo.File(Path.Combine("logs", "verbose.log"), rollingInterval: RollingInterval.Day)
.CreateLogger();
var disposable = new CompositeDisposable();
var uri = new Uri("wss://stream.binance.com:9443");
using var communicator = new BinanceWebSocketCommunicator(uri);
communicator.Name = "Binance-Spot";
communicator.ReconnectTimeout = TimeSpan.FromMinutes(10);
communicator.ReconnectionHappened
.Subscribe(info => Log.Information($"Reconnection happened, …Run Code Online (Sandbox Code Playgroud)