Logimine mikroteenuste keskkonnas .Net'is praktikas

Logimine mikroteenuste keskkonnas .Net'is praktikas

Logimine on arendaja jaoks vĂ€ga oluline tööriist, kuid jaotatud sĂŒsteemide loomisel muutub see vajalikuks aluseks, mille peate asetama just oma rakenduse fundamenti; vastasel juhul vĂ”ib mikroteenuste arendamise keerukus kiiresti ilmneda.

.Net Core 3 on lisandunud suurepÀrane vÔimalus edastada korrelatsiooni konteksti HTTP-pealkirjades, seega, kui teie rakendused kasutavad otse HTTP-kÔnesid teenustevaheliseks suhtlemiseks, vÔite seda vÀlja pakutud funktsionaalsust kasutada. Kuid kui teie taustaarhitektuur eeldab suhtlemist sÔnumite edastamise kaudu (nÀiteks RabbitMQ, Kafka jne), peate endiselt ise pöörama tÀhelepanu selle korrelatsiooni konteksti edastamisele lÀbi nende sÔnumite.

Selles artiklis vÔtame lihtsa veeb-API rakenduse ja seadistame logimise, mis

  • salvestab pideva korrelatsiooni sĂ”ltumatute teenuste logide vahel, et oleks lihtne vaadata kĂ”iki tegevusi, mis olid seotud konkreetse kliendi pĂ€ringuga.

  • omada ĂŒhtne sissepÀÀs mugava analĂŒĂŒsi vĂ”imalustega, et logimise tööriista saaks kasutada isegi tugi, kelle poole pöördutakse kĂŒsimustega nagu «mul on siin rakenduses sellise pĂ€ringu ID-ga viga»

Esiteks peame vĂ€lja valima logimise teenusepakkuja meie rakendusele. Peamine nĂ”ue kaasaegsele logimisele on struktuursus, st me ei tohi töötada tasaste tekstisĂ”numitega, vaid objektidega. TĂ€nu sellistele logidele saame hĂ”lpsasti luua meie sĂ”numite esitusi erinevates mÔÔtmetes ja teostada analĂŒĂŒtikat.

Meie rakenduses kasutame Serilogi paketti, mis toetab suurepĂ€raselt struktuurset logimist ja omab laia lisandite sĂŒsteemi. JĂ€tan vahele selle seadistamise pĂ”hietapid (saate leida palju artikleid selle kohta) ja teen eeldusi, et

  • Serilog on juba konfigureeritud ja on teie sĂ”ltuvuse sisestamise teenusepakkuja vaikimisi logija

  • tema konfiguratsioonis on aktiveeritud sĂ”numite rikastamine konteksti omadustega (Enrich.FromLogContext)

JĂ€rgmiseks sammuks on valida, millisesse kesksesse logide kogumise sĂŒsteemi edastada sĂ”numid Serilogist. TĂ€napĂ€eval on kĂ”ige laialdasemalt kasutatav avatud lĂ€htekoodiga lahendus ELK (Elasticsearch, Logstash ja Kibana), ja valimegi selle. Selleks kasutame ettepanekut Logz.IO — pĂ€rast tasuta plaaniga registreerimist on meie kĂ€sutuses kogu Lucene'i otsimootori jĂ”ud.

Peame lihtsalt meie projekti lisama paki Serilog.Sinks.Logzio

Install-Package Serilog.Sinks.Logzio

Ja lisama vastava rikastaja meie logeri konfiguratsiooni, andes talle juurdepÀÀsutokeni

LoggerConfiguration loggerConfig = new LoggerConfiguration();
loggerConfig.WriteTo.Logzio(secrets.LogzioToken, 10, TimeSpan.FromSeconds(10), null, LogEventLevel.Debug);

Rakenduse kÀivitamisel saame jÀlgida meie sÔnumeid mitte ainult konsoolis, vaid ka Kibanas.

Logimine mikroteenuste keskkonnas .Net'is praktikas

Liidesed

Logimine mikroteenuste keskkonnas .Net'is praktikas

Teenuse rakenduses vÔib eristada kaht peamist liidest, mille kaudu see suhtub vÀlismaailmaga, tÀhistame neid kui vertikaalne ja horisontaalne. Vertikaalne liides on veeb-API, mille kaudu tuleb kliendirakenduselt kutsed. Horisontaalne on sÔnumite vahendaja, mida kasutatakse andmete vahetamiseks teiste sisemiste teenustega.

Vaatame korrelatsiooni rakendamise etappe igas nendes liidestes.

Korrelatsioon HTTP-pÀringutes

Kuna soovime saada vĂ”imalikult palju teavet, peame genereerima korrelatsiooni ID nii varakult kui vĂ”imalik, st vĂ€ravas vĂ”i otse kliendis (mobiilne vĂ”i veeb). Kuna tĂ€na kĂ€sitleme tagaplaneerimise rakendust, mĂ€rkime lihtsalt nĂ”ude kohustusliku pĂ€ise „X-Correlation-ID” olemasolu kĂ”igis veeb-API pĂ€ringutes.

Lisame paketi CorrelationID, mille funktsioon on vÔtta vajalik vÀÀrtus vajaliku pÀise seest.

Install-Package CorrelationID

Lisame selle pÀringu töötlemise torusse

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 tema 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
{

}

Seega hakkab kontroller vastama kÔigile pÀringutele, millel puudub vastava identifikaatoriga pÀis, 400 Bad Request.

PĂ€rast seda, kui hakkasime klientidelt identifikaatorit saama, peame selle logimis konteksti lisama, selleks loome ĂŒmberpĂ€rimise vahekihina:

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(httpContext);
            }
        }
        else
        {
            await _next(httpContext);
        }
    }
}

Meie rakenduses kasutame Microsoft.Extensions.Logging.Abstractions paketist standardset ILogger'i, seetÔttu lisame vÀÀrtuse 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 vahendaja pÀringute töötlemise konveierisse ja saame soovitud tulemuse.

public class Startup
{
    public void Configure(IApplicationBuilder application)
    {
        application.UseMiddleware();
    }
}

NĂŒĂŒd sisaldavad kĂ”ik tegevused, mis on pĂ”hjustatud meie veeb API pĂ€ringutest, korrelatsioonilist identifikaatorit, mille kaudu neid on lihtne omavahel seostada.

Logimine mikroteenuste keskkonnas .Net'is praktikas

Korrelatsioon sÔnumites maakleris

JĂ€rgmise sammuna peame seadma ĂŒles korrelatsioonilise identifikaatori edastamise ja vastuvĂ”tmise sĂ”numiteenuse kaudu. Meie nĂ€ites kasutame RabbitMQ-d ja kliendiks on MassTransit raamistik. JĂ€tame vahele MassTransit'i esialgse seadistamise ja liigume kohe logimise seadistamise juurde.

Esimese asjana saame sisse lĂŒlitada MassTransit'i logid, selle jaoks lisame oma rakendusse paketi MassTransit.SerilogIntegration

Install-Package MassTransit.SerilogIntegration

NĂŒĂŒd, pĂ€rast logeri lisamist MassTransit'i seadistustesse, nĂ€eme raamistikku logisid.

services
    .AddSingleton(provider =>
        {
            return Bus.Factory.CreateUsingRabbitMq(cfg =>
            {
                cfg.UseSerilog();
            });
        });

Las meie rakendus reageerib POST-pĂ€ringule, saates sĂŒndmuse SomethingDoneMessage vÀÀrtusega „done“. Sellise sĂ”numi lepingut saab kirjeldada jĂ€rgmiselt:

namespace MbMessages
{
    public interface ISomethingDoneMessageV1
    {
        string Value { get; }
    }
}

MassTransit'i sĂ”numid on sisuliselt ĂŒmbrikud, kuhu on pakitud sĂ”numid brokeri poolt. Ümbrik nĂ€eb vĂ€lja umbes nii:

{
  "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 sĂŒsteemivĂ€ljad, mis on vajalikud raamistiku toimimiseks, kuid meil on vĂ”imalik lisada sellesse ĂŒmbrikusse ka enda tĂ€iendavad omadused. Veelgi enam, MassTransit sisaldab sisseehitatud vĂ”imalusi teatud valikuvĂ€ljade töötlemiseks, millest meid kĂ”ige rohkem huvitab CorrelationId koordineerimise identifikaator.

Lisame sÔnumi lepingule CorrelatedBy liidese:

namespace MbMessages
{
    public interface ISomethingDoneMessageV1 : CorrelatedBy
    {
        string Value { get; }
    }
}

Rakendame seda ja mÀÀrame CorrelationId omadusele vÀÀrtuse sÔnumi loomisel:

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 vĂ€rskendatud teadet, siis nĂ€eme, et korrelatsioonidentifikaator on saanud mitte ainult meie sĂ”numi osaks, vaid ka ĂŒmbriku osaks — see identifikaator kasutatakse nĂŒĂŒd ka kĂ”igis MassTransit logides, mis teeb probleemide lahendamise sĂ”numi vahendaja tasemel oluliselt 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"
  }
}

Meil jÀÀb ĂŒle vaid seadistada nende teenuslikud omadused sĂ”numite logimine, selleks lisame projekti paketi Serilog.Enrichers.MassTransitMessage. Paketiga lisatakse MassTransit sĂ”numite töötlemise torustikku filter, mis kogub sĂ”numi konteksti lĂ”imeta ohutusse kuhja. Serilog loeb konteksti kuhjast ja lisab meie logiobjektidesse need lisad omadused.

Install-Package Serilog.Enrichers.MassTransitMessage

MassTransit'is lisame filtri

teenused
    .AddSingleton(provider =>
        {
            return Bus.Factory.CreateUsingRabbitMq(cfg =>
            {
                cfg.UseSerilog();
                cfg.UseSerilogMessagePropertiesEnricher();
            });
        });

Ja Serilogi konfiguratsioonis lisame rikastaja

Log.Logger = new LoggerConfiguration()
    .Enrich.FromMassTransitMessage()
    .CreateLogger();

Kuna rakendus, mis saab sÔnumi RabbitMQ jÀrjekorrast, pÀÀseb ligi kÔigile MassTransit konverteerimise omadustele, saame kasutada saadud korrelatsiooni ID-d ka tarbija rakenduses ning edastada seda edasi kogu kutsehelise ahela jooksul.

Kuna meie logid sisaldavad CorrelationId mitte ainult ĂŒhe teenuse piires, vaid ka suheldes teiste rakendustega.

Logimine mikroteenuste keskkonnas .Net'is praktikas

Seega vĂ”imaldab saadud logimissĂŒsteem .Net rakendustes meil probleemideta korreleerida logisid tĂ€iesti erinevatest mikroteenustest — isegi nendest, mis töötavad sĂ”numivahendaja kaudu. Ja Elasticsearchi abil saame kiiresti ja mugavalt analĂŒĂŒsida logisid, luues Kibanas vajalikud juhtpaneelid (nĂ€ide on toodud postituse pildil).

Muidugi ei kata selline logimine keerulisi teie teenuste ja erinevate vĂ€listoodete vahelisi interaktsioone, kuid sellise korra kehtestamine projekti arengu alguses on ĂŒks neist asjadest, mille eest ĂŒtlete endale hiljem tĂ€nu.

Saate uurida projekti saadud sĂŒsteemi lĂ€htekoodi: github.com/a-postx/YA.ServiceTemplate

Allikas: habr.com

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster