我读到在 MVC 中间件框架中使用日志范围和 Controller 的操作:
Use Scopes sparingly, and only for actions with a bounded start and end. For example, the framework provides a scope around MVC actions. Avoid nesting many scopes within one another.
和
A scope is an IDisposable type returned by calling the ILogger.BeginScope method, which lasts from the moment it is created until it is disposed. Any logging state, such as a transaction id, is attached to the scope when it is created.
我正在尝试使用此功能来写入一些日志信息。我执行了以下步骤:
1)创建Asp.net核心MVC应用程序
2) 在 appsetting.json 中将属性“IncludeScopes”设置为“true”
3)像这样创建 Controller 和 Action :
[Route("api/[controller]")]
public class TodoController : Controller
{
private readonly ILogger<TodoController> _logger;
public TodoController(ILogger<TodoController> logger)
{
_logger = logger;
}
// GET: api/values
[HttpGet]
public IEnumerable<string> Get()
{
_logger.LogInformation(1000, "Listing all items started");
Thread.Sleep(2000);
_logger.LogInformation(1000, "Listing all items finished");
return new string[] { "value1", "value2" };
}
}
我希望我的日志消息流始终只包含“列出所有已开始的项目”和“列出所有已完成的项目”部分,它们彼此不分开。
但是当我同时启动两个请求时,得到的日志流为:
RequestId: xxx 列出所有项目已开始
RequestId: yyy 列出所有项目开始
RequestId: xxx 列出所有项目已完成
RequestId: yyy 列出所有项目完成
什么原因?这是正确的行为,我在日志记录上下文中误解了“范围”术语吗?
最佳答案
日志范围有助于创建范围,通过该范围在其中创建的任何日志语句都可以使用该信息。
以下来自 ConsoleLogger
与 IncludeScopes
设置为 true
:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
=> RequestId:0HKT6JC0EVFNA RequestPath:/api/values
Request starting HTTP/1.1 GET http://localhost:5000/api/values
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
=> RequestId:0HKT6JC0EVFNA RequestPath:/api/values => WebApplication8.Controllers.ValuesController.Get (WebApplication8)
Executing action method WebApplication8.Controllers.ValuesController.Get (WebApplication8) with arguments () - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor[1]
=> RequestId:0HKT6JC0EVFNA RequestPath:/api/values => WebApplication8.Controllers.ValuesController.Get (WebApplication8)
Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
=> RequestId:0HKT6JC0EVFNA RequestPath:/api/values => WebApplication8.Controllers.ValuesController.Get (WebApplication8)
Executed action WebApplication8.Controllers.ValuesController.Get (WebApplication8) in 322.8533ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
=> RequestId:0HKT6JC0EVFNA RequestPath:/api/values
Request finished in 428.477ms 200 application/json; charset=utf-8
如果你注意到上面的日志,这里
RequestId:0HKT6JC0EVFNA
正在为每个日志语句打印(如前所述,范围或嵌套范围内的所有日志语句都将从所有这些范围中获取信息)在 ASP.NET 中默认创建的一些日志范围是
RequestId
如上所示的范围以及从日志中看到的 MVC Controller 操作调用的范围(例如这一行: => WebApplication8.Controllers.ValuesController.Get (WebApplication8)
)如果需要,您也可以自己创建范围:
using (logger.BeginScope("OrderOrchestrationId:{OrderOrchestrationId}", orderOrchestrationId))
{
// any log statements from here on would have `OrderOrchestrationId` available
}
注:
默认情况下,所有记录器都不支持范围。如果是
ConsoleLogger
它以文本格式打印范围,但范围在结构化日志记录的情况下确实很出色,如下所述。范围如何有用?
ASP.NET 日志框架允许你做
structured logging
.比如上面的代码{OrderOrchestrationId}
被用于此目的。 Serilog有一个用于 ASP.NET 5 的记录器,它实现了结构化日志记录,使用它你可以例如将数据写为 json
数据到 Azure 的 DocumentDB。所以在这种情况下,如果
OrderOrchestrationId
已写入 Azure 的 DocumentDB,您可以使用此 id 搜索日志,这在纯文本文件搜索中很难做到。
关于logging - MVC 日志记录范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38243239/