
Logimine on arendaja jaoks vĂ€ga oluline tööriist, kuid hajussĂŒsteemide loomisel muutub see vundamendikiviks, mis tuleb paika panna kohe rakenduse alusesse, vastasel juhul annab mikroteenuste arenduse keerukus end vĂ€ga kiiresti tunda.
.Net Core 3-s lisandus suurepĂ€rane , seega kui teie rakendused kasutavad teenustevaheliseks suhtluseks otseseid HTTP-kutseid, saate kasutada seda valmislahendust. Kui teie backendâi arhitektuur eeldab aga suhtlust sĂ”numivahendaja kaudu (RabbitMQ, Kafka jne), peate endiselt ise hoolitsema korrelatsioonikonteksti edastamise eest nende sĂ”numite kaudu.
Selles artiklis vÔtame lihtsa Web API rakenduse ja seadistame logimise, mis
sÀilitab sÔltumatute teenuste logide vahel lÀbiva korrelatsiooni nii, et oleks lihtne nÀha kÔiki tegevusi, mille konkreetne kliendipÀring kÀivitas
vĂ”imaldab luua ĂŒhe keskse sisenemispunkti koos mugava analĂŒĂŒsiga, et logimistööriista saaks kasutada isegi tugi, kellele jĂ”uavad kĂŒsimused stiilis âmul viskas rakenduses veateate sellise pĂ€ringu ID-gaâ
Esiteks peame oma rakenduses valima logimislahenduse pakkuja. Kaasaegse logimise peamine nĂ”ue on struktureeritus, st me ei tööta lamedate tekstsĂ”numitega, vaid objektidega. TĂ€nu sellistele logidele saame hĂ”lpsalt luua oma sĂ”numitest erinevaid vaateid ja teha analĂŒĂŒsi.
Oma rakenduses kasutame paketti Serilog, millel on suurepĂ€rane struktureeritud logimise tugi ja rikkalik laienduste ökosĂŒsteem. JĂ€tan selle pĂ”hiseadistuse etapid vahele (sellel teemal leiab palju artikleid) ja eeldan, et
Serilog on juba seadistatud ja on teie sĂ”ltuvussĂŒstimise pakkuja vaikimisi logger
selle konfiguratsioonis on lubatud sÔnumite rikastamine konteksti omadustega (Enrich.FromLogContext)
JĂ€rgmine samm on valida, millisesse tsentraliseeritud logikogumissĂŒsteemi Serilogi sĂ”numid saata. TĂ”enĂ€oliselt on tĂ€napĂ€eval kĂ”ige levinum avatud lĂ€htekoodiga lahendus ELK stack (Elasticsearch, Logstash ja Kibana), seega kasutame seda. Selleks vĂ”tame appi lahenduse ettevĂ”ttelt â pĂ€rast tasuta paketi registreerimist on meie kĂ€sutuses kogu Lucene'i otsingumootori vĂ”imekus.
Meil jÀÀb ĂŒle lisada oma projekti pakett
Install-Package Serilog.Sinks.Logzio
Ja lisada meie logeri konfiguratsiooni vastav enricher, andes sellele ette juurdepÀÀsutokeni
LoggerConfiguration loggerConfig = new LoggerConfiguration();
loggerConfig.WriteTo.Logzio(secrets.LogzioToken, 10, TimeSpan.FromSeconds(10), null, LogEventLevel.Debug);
PÀrast rakenduse kÀivitamist nÀeme oma sÔnumeid mitte ainult konsoolis, vaid ka Kibanas.

Liidesed

TeenusetĂŒĂŒpi rakendusel saab eristada kahte peamist liidest vĂ€lismaailmaga suhtlemiseks, nimetagem neid vertikaalseks ja horisontaalseks. Vertikaalne liides on Web API, mille kaudu saabuvad kliendirakenduse pĂ€ringud. Horisontaalne liides on sĂ”numivahendaja, mida kasutatakse andmevahetuseks teiste sisemiste teenustega.
Vaatleme korrelatsiooni juurutamise etappe kummagi liidese puhul.
Korrelatsioon HTTP-pÀringutes
Et saada vĂ”imalikult palju teavet, tuleb korrelatsiooniidentifikaator genereerida vĂ”imalikult tegevuse alguse lĂ€hedal, s.t. lĂŒĂŒsis vĂ”i otse kliendi poolel (mobiili- vĂ”i veebirakenduses). Kuna tegeleme tĂ€na backend-rakendusega, siis piirduleme nĂ”udega, et kĂ”igil Web API pĂ€ringutel peab olema kohustuslik pĂ€is âX-Correlation-IDâ.
Lisame paketi , mille ĂŒlesanne on lugeda vÀÀrtus meie jaoks vajalikust pĂ€isest
Install-Package CorrelationID
Lisame selle pÀringutöötluse konveierisse
public class Startup
{
public void Configure(IApplicationBuilder application)
{
application
.UseCorrelationId(new CorrelationIdOptions
{
Header = "X-Correlation-ID",
IncludeInResponse = false,
UpdateTraceIdentifier = false,
UseGuidForCorrelationId = false
});
}
}
NĂŒĂŒd teeme selle abil lihtsa action-filtri:
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();
}
}
Ja lisame selle kontrollerisse
[Route("[controller]")]
[ApiController]
[ServiceFilter(typeof(ApiRequestFilter))]
public class CarsController : ControllerBase
{
}
Selle tulemusel hakkab kontroller tagastama kÔigile pÀringutele ilma vastava identifikaatoriga pÀiseta vastuse 400 Bad Request.
PĂ€rast seda, kui hakkasime kliendilt identifikaatorit saama, peame selle lisama logimiskonteksti. Selleks teeme eraldi vahekihi:
public class CorrelationIdContextLogger
{
public CorrelationIdContextLogger(RequestDelegate next)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
}
readonly RequestDelegate _next;
public async Task InvokeAsync(HttpContext httpContext, ILogger logger, ICorrelationContextAccessor correlationContextAccessor)
{
if (Guid.TryParse(correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
{
using (logger.BeginScopeWith(("CorrelationId", correlationId)))
{
await _next(context);
}
}
else
{
await _next(context);
}
}
}
Meie rakenduses kasutame standardset ILoggerit paketist Microsoft.Extensions.Logging.Abstractions, seega lisame vÀÀrtuse selle jaoks loodud lihtsa laienduse abil.
public static IDisposable BeginScopeWith(this ILogger logger, params (string key, object value)[] keys)
{
return logger.BeginScope(keys.ToDictionary(x => x.key, x => x.value));
}
Lisame vahekihi pÀringutöötluse konveierisse ja saame soovitud tulemuse.
public class Startup
{
public void Configure(IApplicationBuilder application)
{
application.UseMiddleware();
}
}
NĂŒĂŒd sisaldavad kĂ”ik tegevused, mille kĂ€ivitavad pĂ€ringud meie Web API-le, korrelatsiooniidentifikaatorit, mille alusel saab need hĂ”lpsasti omavahel siduda.

Korrelatsioon sÔnumibrokeri teadetes
JÀrgmise sammuna peame seadistama korrelatsiooniidentifikaatori edastamise ja vastuvÔtmise sÔnumivahendaja kaudu. Meie nÀites kasutame RabbitMQ-d ning kliendina vÔtame kasutusele MassTransit frameworki. JÀtame taas MassTransiti esmase seadistuse vahele ja liigume kohe logimise seadistamise juurde.
Alustuseks vĂ”ime sisse lĂŒlitada MassTransiti enda logid; selleks lisame oma rakendusse paketi
Install-Package MassTransit.SerilogIntegration
PÀrast loggeri lisamist MassTransiti seadistusse nÀeme frameworki logisid.
services
.AddSingleton(provider =>
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseSerilog();
});
});
Oletame, et meie rakendus saadab POST-pĂ€ringu tulemusena sĂŒndmuse SomethingDoneMessage vÀÀrtusega âdoneâ. Sellise sĂ”numi lepingu saab kirjeldada jĂ€rgmiselt:
namespace MbMessages
{
public interface ISomethingDoneMessageV1
{
string Value { get; }
}
}
MassTransiti sĂ”numid on sisuliselt ĂŒmbris, mille sisse on paigutatud vahendaja sĂ”numid. See ĂŒmbris nĂ€eb vĂ€lja umbes selline:
{
"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"
}
}
SĂ”numis on nĂ€ha teenindusvĂ€lju, mida framework ise oma tööks vajab, kuid meil on vĂ”imalik sellesse ĂŒmbrisesse lisada ka oma tĂ€iendavaid omadusi. Lisaks on MassTransitis olemas sisseehitatud vahendid mĂ”ne valikulise vĂ€lja kasutamiseks, millest meid huvitab kĂ”ige rohkem korrelatsiooniidentifikaator CorrelationId.
Lisame sÔnumi lepingule liidese CorrelatedBy:
namespace MbMessages
{
public interface ISomethingDoneMessageV1 : CorrelatedBy
{
string Value { get; }
}
}
Rakendame selle ja mÀÀrame sÔnumi loomisel atribuudile CorrelationId vÀÀrtuse:
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; }
}
Kui vaatame uuendatud teadet, nĂ€eme, et korrelatsiooniidentifikaatorist on saanud mitte ainult meie sĂ”numi, vaid ka ĂŒmbriku osa â seda identifikaatorit kasutatakse nĂŒĂŒd ka kĂ”igis MassTransit'i logides, mis tĂ€hendab, et sĂ”numivahendaja tasemel probleemide analĂŒĂŒsimine muutub meie jaoks mĂ€rksa lihtsamaks.
{
"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"
}
}
NĂŒĂŒd jÀÀb ĂŒle seadistada nende sĂ”numi teenusatribuutide logimine, selleks lisame projekti paketi . Pakett lisab MassTransit'i sĂ”numitöötluse konveierisse filtri, mis paigutab sĂ”numi konteksti lĂ”imeturvalisse pinu. Serilog loeb konteksti pinust ja lisab need tĂ€iendavad omadused meie logiobjektidele.
Install-Package Serilog.Enrichers.MassTransitMessage
MassTransit'is lisame filtri
services
.AddSingleton(provider =>
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseSerilog();
cfg.UseSerilogMessagePropertiesEnricher();
});
});
Ja Serilogi konfiguratsiooni lisame enricheri
Log.Logger = new LoggerConfiguration()
.Enrich.FromMassTransitMessage()
.CreateLogger();
Kuna rakendusel, mis vĂ”tab sĂ”numi RabbitMQ jĂ€rjekorrast vastu, on juurdepÀÀs kĂ”igile MassTransit'i ĂŒmbriku omadustele, saame saadud korrelatsiooniidentifikaatorit kasutada tarbijarakenduse sees ning edastada seda edasi kogu kutsungiahela ulatuses.
Selle tulemusel sisaldavad meie logid nĂŒĂŒd CorrelationId-d mitte ainult ĂŒhe teenuse piires, vaid ka suhtluses teiste rakendustega.

KokkuvĂ”ttes vĂ”imaldab selline .Net-rakenduste logimissĂŒsteem meil ilma suuremate raskusteta korreleerida logisid tĂ€iesti erinevatest mikroteenustest â isegi neist, mis töötavad sĂ”numivahendaja kaudu. Elasticsearchi abil saame logisid kiiresti ja mugavalt analĂŒĂŒsida, luues Kibanas vajalikud armatuurlauad (nĂ€ide on toodud postituse pildil).
Muidugi ei kata sellisel kujul logimine teie teenuste ja erinevate vĂ€liste sĂŒsteemide keerukamaid koostööstsenaariume, kuid sellise korra loomine juba projekti arenduse alguses on ĂŒks neist sammudest, mille eest tĂ€nate end hiljem korduvalt.
Valmis sĂŒsteemi lĂ€htekoodiga saate tutvuda selles projektis:
Allikas: habr.com
