![](https://habrastorage.org/webt/4b/fg/ao/4bfgaoh7d94rvhf79kyaygfak5m.png)
O registro é uma ferramenta muito importante do desenvolvedor, mas, ao criar sistemas distribuídos, torna-se uma pedra que precisa ser colocada na base do seu aplicativo; caso contrário, a complexidade do desenvolvimento de microsserviços se fará sentir muito rapidamente.
.Net Core 3 HTTP-, HTTP- , . , (RabbitMQ, Kafka ..), - .
- ,
-, . , .. , . .
Serilog (), . ( ) ,
Serilog. , ELK (Elasticsearch, Logstash Kibana), . Logz.IO — Lucene.
Serilog.Sinks.Logzio
Install-Package Serilog.Sinks.Logzio
,
LoggerConfiguration loggerConfig = new LoggerConfiguration();
loggerConfig.WriteTo.Logzio(secrets.LogzioToken, 10, TimeSpan.FromSeconds(10), null, LogEventLevel.Debug);
, .
![](https://habrastorage.org/webt/rn/hk/2g/rnhk2gyckxreijnt2phnx9ucmmg.png)
![](https://habrastorage.org/webt/bu/hc/u6/buhcu66v68g6qpj68sn08z8qfoe.png)
, . — -, . — , .
.
HTTP-
, .. ( ). , «X-Correlation-ID» -.
CorrelationID,
Install-Package CorrelationID
public class Startup
{
public void Configure(IApplicationBuilder application)
{
application
.UseCorrelationId(new CorrelationIdOptions
{
Header = "X-Correlation-ID",
IncludeInResponse = false,
UpdateTraceIdentifier = false,
UseGuidForCorrelationId = false
});
}
}
action-:
public sealed class ApiRequestFilter : ActionFilterAttribute
{
public ApiRequestFilter(IApiRequestTracker apiRequestTracker, ICorrelationContextAccessor correlationContextAccessor)
{
_correlationContextAccessor = correlationContextAccessor ?? throw new ArgumentNullException(nameof(correlationContextAccessor));
}
private readonly ICorrelationContextAccessor _correlationContextAccessor;
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (!Guid.TryParse(_correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
{
context.Result = new BadRequestResult();
return;
}
await next.Invoke();
}
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
await next.Invoke();
}
}
[Route("[controller]")]
[ApiController]
[ServiceFilter(typeof(ApiRequestFilter))]
public class CarsController : ControllerBase
{
}
400 Bad request .
, , :
public class CorrelationIdContextLogger
{
public CorrelationIdContextLogger(RequestDelegate next)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
}
readonly RequestDelegate _next;
public async Task InvokeAsync(HttpContext httpContext, ILogger<CorrelationIdContextLogger> logger, ICorrelationContextAccessor correlationContextAccessor)
{
if (Guid.TryParse(correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
{
using (logger.BeginScopeWith(("CorrelationId", correlationId)))
{
await _next(context);
}
}
else
{
await _next(context);
}
}
}
ILogger Microsoft.Extensions.Logging.Abstractions, .
public static IDisposable BeginScopeWith(this ILogger logger, params (string key, object value)[] keys)
{
return logger.BeginScope(keys.ToDictionary(x => x.key, x => x.value));
}
.
public class Startup
{
public void Configure(IApplicationBuilder application)
{
application.UseMiddleware<CorrelationIdContextLogger>();
}
}
, -, .
![](https://habrastorage.org/webt/mn/0m/da/mn0mdafovsq6oscz34vajk536ui.png)
. RabbitMQ, MassTransit (). , .
, MassTransit.SerilogIntegration
Install-Package MassTransit.SerilogIntegration
MassTransit .
services
.AddSingleton(provider =>
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseSerilog();
});
});
POST- SomethingDoneMessage «done». :
namespace MbMessages
{
public interface ISomethingDoneMessageV1
{
string Value { get; }
}
}
, . :
{
"messageId": "59020000-5dba-0015-10b8-08d77ec28593",
"requestId": "59020000-5dba-0015-5674-08d77ec28592",
"conversationId": "59020000-5dba-0015-bca8-08d77ec28594",
"destinationAddress": "rabbitmq://bear.rmq.cloudamqp.com/aelzlsta/ya.servicetemplate.receiveendpoint",
"headers": {},
"messageType": [
"urn:message:MbMessages:ISomethingDoneMessageV1"
],
"message": {
"value": "done"
}
}
, , . , MassTransit , CorrelationId.
CorrelatedBy:
namespace MbMessages
{
public interface ISomethingDoneMessageV1 : CorrelatedBy<Guid>
{
string Value { get; }
}
}
CorrelationId :
internal class SomethingDoneMessageV1 : ISomethingDoneMessageV1
{
internal SomethingDoneMessageV1(Guid correlationId, string value)
{
CorrelationId = correlationId;
Value = value;
}
public Guid CorrelationId { get; private set; }
public string Value { get; private set; }
}
, , — , .
{
"messageId": "59020000-5dba-0015-10b8-08d77ec28593",
"requestId": "59020000-5dba-0015-5674-08d77ec28592",
"conversationId": "59020000-5dba-0015-bca8-08d77ec28594",
"correlationId": "c7ff562a-b639-415b-9add-c9e524a727cc",
"destinationAddress": "rabbitmq://bear.rmq.cloudamqp.com/aelzlsta/ya.servicetemplate.receiveendpoint",
"headers": {},
"messageType": [
"urn:message:MbMessages:ISomethingDoneMessageV1"
],
"message": {
"correlationId": "c7ff562a-b639-415b-9add-c9e524a727cc",
"value": "Hello"
}
}
, Serilog.Enrichers.MassTransitMessage. MassTransit, . .
Install-Package Serilog.Enrichers.MassTransitMessage
services
.AddSingleton(provider =>
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseSerilog();
cfg.UseSerilogMessagePropertiesEnricher();
});
});
Log.Logger = new LoggerConfiguration()
.Enrich.FromMassTransitMessage()
.CreateLogger();
, RabbitMQ, MassTransit, -, .
CorrelationId , .
![](https://habrastorage.org/webt/ip/s7/kt/ips7kt4rlfow5tro5dtgdv8bjmq.png)
, .Net — , . Elasticsearch , ( ).
, , — , .
Você pode entender o código fonte do sistema resultante no projeto: github.com/a-postx/YA.ServiceTemplate