
Pembalakan ialah alat yang sangat penting untuk pembangun, tetapi apabila membina sistem teragih, ia menjadi batu yang perlu diletakkan terus ke dalam asas aplikasi anda, jika tidak, kerumitan membangunkan perkhidmatan mikro akan terasa dengan cepat.
.Net Core 3 menambah yang hebat , jadi jika aplikasi anda menggunakan panggilan HTTP langsung untuk komunikasi antara perkhidmatan, maka anda boleh memanfaatkan kefungsian kotak ini. Walau bagaimanapun, jika seni bina bahagian belakang anda melibatkan interaksi melalui broker mesej (RabbitMQ, Kafka, dsb.), maka anda masih perlu menjaga topik menyampaikan konteks korelasi melalui mesej ini sendiri.
Dalam artikel ini, kami akan mengambil aplikasi api web yang mudah dan mengatur pengelogan, yang akan
simpan korelasi hujung ke hujung antara log perkhidmatan bebas supaya anda boleh melihat dengan mudah semua aktiviti yang disebabkan oleh permintaan khusus daripada pelanggan
mempunyai satu titik masuk dengan analisis yang mudah supaya Sokongan boleh menggunakan alat pengelogan, yang soalan seperti "Saya mendapat ralat dengan ID permintaan ini dan ini" muncul dalam aplikasi
Mula-mula, kami perlu membuat keputusan mengenai pembekal pembalakan dalam aplikasi kami. Keperluan utama untuk pembalakan moden ialah struktur, i.e. kita harus bekerja bukan dengan mesej teks rata, tetapi dengan objek. Terima kasih kepada log sedemikian, kami boleh membina paparan mesej kami dengan mudah dalam bahagian yang berbeza dan menjalankan analisis.
Untuk aplikasi kami, kami akan menggunakan pakej Serilog (Serilog), yang mempunyai sokongan yang sangat baik untuk pembalakan struktur dan sistem tambahan yang kaya. Saya akan meninggalkan langkah asas untuk menyediakannya (anda boleh menemui sejumlah besar artikel mengenai topik ini) dan membuat andaian bahawa
Serilog telah dikonfigurasikan dan merupakan pembalak lalai pembekal suntikan kebergantungan anda
Memperkayakan mesej dengan sifat konteks didayakan dalam konfigurasinya (Enrich.FromLogContext)
Langkah seterusnya ialah memilih sistem pembalakan berpusat untuk menghantar mesej daripada Serilog. Mungkin pilihan sumber terbuka yang paling biasa hari ini ialah timbunan ELK (Elasticsearch, Logstash dan Kibana), dan mari kita ambil. Untuk melakukan ini, kami menggunakan cadangan daripada - selepas mendaftar untuk pelan percuma, kuasa penuh enjin carian Lucene berada di tangan kami.
Tinggal untuk kami menambah pakej pada projek kami
Install-Package Serilog.Sinks.Logzio
Dan tambahkan Enricher yang sesuai pada konfigurasi logger kami dengan memberinya token akses
LoggerConfiguration loggerConfig = new LoggerConfiguration();
loggerConfig.WriteTo.Logzio(secrets.LogzioToken, 10, TimeSpan.FromSeconds(10), null, LogEventLevel.Debug);
Dengan menjalankan aplikasi, kami akan dapat melihat mesej kami bukan sahaja dalam konsol, tetapi juga di Kibane.

Antara muka

Dalam aplikasi jenis perkhidmatan, dua antara muka utama interaksinya dengan dunia luar boleh dibezakan; kami akan menandakannya sebagai menegak dan mendatar. Antara muka menegak ialah api web yang melaluinya panggilan daripada aplikasi klien tiba. Horizontal ialah broker mesej yang digunakan untuk bertukar-tukar data dengan perkhidmatan dalaman yang lain.
Mari kita pertimbangkan peringkat pelaksanaan korelasi pada setiap antara muka ini.
Korelasi dalam Permintaan HTTP
Untuk mendapatkan maklumat sebanyak mungkin, kita perlu menjana ID korelasi sedekat mungkin dengan permulaan aktiviti, i.e. pada pintu masuk atau terus pada klien (mudah alih atau web). Memandangkan kami sedang berurusan dengan aplikasi bahagian belakang hari ini, kami hanya akan menunjukkan padanya keperluan untuk pengepala "ID-Korelasi-X" mandatori dalam semua permintaan ke api web.
Menambah pakej , fungsinya adalah untuk mengambil nilai daripada pengepala yang kita perlukan
Install-Package CorrelationID
Tambahkannya pada saluran paip pemprosesan permintaan
public class Startup
{
public void Configure(IApplicationBuilder application)
{
application
.UseCorrelationId(new CorrelationIdOptions
{
Header = "X-Correlation-ID",
IncludeInResponse = false,
UpdateTraceIdentifier = false,
UseGuidForCorrelationId = false
});
}
}
Sekarang mari buat penapis tindakan mudah dengannya:
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();
}
}
Dan tambahkannya pada pengawal
[Route("[controller]")]
[ApiController]
[ServiceFilter(typeof(ApiRequestFilter))]
public class CarsController : ControllerBase
{
}
Akibatnya, pengawal akan memaparkan 400 Permintaan Buruk untuk semua permintaan tanpa pengepala dengan pengecam yang sepadan.
Selepas kami mula menerima pengecam daripada klien, kami mesti menambahkannya pada konteks pengelogan, kami akan membuat lapisan pembingkaian untuk ini:
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);
}
}
}
Dalam aplikasi kami, kami menggunakan ILogger standard daripada pakej Microsoft.Extensions.Logging.Abstractions, jadi kami akan menambah nilai menggunakan sambungan ringkas padanya.
public static IDisposable BeginScopeWith(this ILogger logger, params (string key, object value)[] keys)
{
return logger.BeginScope(keys.ToDictionary(x => x.key, x => x.value));
}
Kami menambah lapisan pada saluran paip pemprosesan permintaan dan mendapatkan hasil yang diingini.
public class Startup
{
public void Configure(IApplicationBuilder application)
{
application.UseMiddleware<CorrelationIdContextLogger>();
}
}
Kini semua aktiviti yang dijana oleh permintaan ke api web kami mengandungi pengecam korelasi yang boleh dipautkan dengan mudah.

Korelasi dalam mesej broker
Langkah seterusnya ialah menyediakan penghantaran dan penerimaan pengecam korelasi melalui broker mesej. Dalam contoh kami, kami akan menggunakan RabbitMQ, dan sebagai pelanggan kami akan menggunakan rangka kerja MassTransit (MassTranzit). Sekali lagi, mari langkau persediaan awal untuk bekerja dengan MassTransit dan terus ke penyediaan pengelogan.
Sebagai permulaan, kami boleh mendayakan log MassTransit itu sendiri, untuk ini kami akan menambah pakej pada aplikasi kami
Install-Package MassTransit.SerilogIntegration
Kini, selepas menambahkan pembalak pada tetapan MassTransit, kami akan dapat melihat log rangka kerja.
services
.AddSingleton(provider =>
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseSerilog();
});
});
Biarkan aplikasi kami menghantar acara SomethingDoneMessage dengan nilai "selesai" sebagai respons kepada permintaan POST. Kontrak mesej sedemikian boleh diterangkan seperti berikut:
namespace MbMessages
{
public interface ISomethingDoneMessageV1
{
string Value { get; }
}
}
Mesej MassTransit pada asasnya adalah sampul surat yang mengandungi mesej broker. Sampul surat kelihatan seperti ini:
{
"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"
}
}
Mesej menunjukkan medan perkhidmatan yang diperlukan untuk rangka kerja itu sendiri berfungsi, tetapi kami mempunyai keupayaan untuk menambahkan sifat tambahan kami sendiri pada sampul surat ini. Selain itu, MassTransit mempunyai alatan terbina dalam untuk bekerja dengan beberapa medan pilihan, yang paling menarik yang kami minati ialah CorrelationId.
Tambahkan antara muka CorrelatedBy pada kontrak mesej:
namespace MbMessages
{
public interface ISomethingDoneMessageV1 : CorrelatedBy<Guid>
{
string Value { get; }
}
}
Mari kita laksanakan dan tetapkan nilai kepada sifat CorrelationId apabila membuat mesej:
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; }
}
Jika kita melihat pada mesej yang dikemas kini, kita akan melihat bahawa pengecam korelasi telah menjadi bukan sahaja sebahagian daripada mesej kami, tetapi juga sebahagian daripada sampul surat - pengecam ini kini akan turut digunakan dalam semua log MassTransit, yang bermaksud ia akan menjadi lebih mudah. untuk kita menangani masalah di peringkat broker mesej.
{
"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"
}
}
Tinggal untuk kami mengkonfigurasi pengelogan sifat perkhidmatan mesej ini, untuk ini kami akan menambah pakej pada projek . Pakej itu menambah penapis pada saluran paip pemprosesan mesej MassTransit yang menolak konteks mesej ke timbunan selamat benang. Serilog membaca konteks dari timbunan dan menambah sifat tambahan ini pada objek log kami.
Install-Package Serilog.Enrichers.MassTransitMessage
Masukkan penapis dalam MassTransit
services
.AddSingleton(provider =>
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseSerilog();
cfg.UseSerilogMessagePropertiesEnricher();
});
});
Dan dalam konfigurasi Serilog, tambahkan Enricher
Log.Logger = new LoggerConfiguration()
.Enrich.FromMassTransitMessage()
.CreateLogger();
Memandangkan aplikasi yang menerima mesej daripada baris gilir RabbitMQ mempunyai akses kepada semua sifat sampul MassTransit, kami boleh menggunakan pengecam korelasi yang diterima di dalam aplikasi yang digunakan, dan juga menyampaikannya lebih jauh di sepanjang rantai panggilan.
Akibatnya, log kami mula mengandungi CorrelationId bukan sahaja dalam perkhidmatan yang sama, tetapi juga apabila berinteraksi dengan aplikasi lain.

Jadi, sistem pengelogan yang terhasil dalam aplikasi .Net membolehkan kami mengaitkan log daripada perkhidmatan mikro yang berbeza tanpa sebarang masalah - malah yang berfungsi melalui broker mesej. Dan dengan bantuan Elasticsearch, kami boleh menganalisis log dengan cepat dan mudah dengan membina papan pemuka yang kami perlukan dalam Kibana (contoh ditunjukkan dalam gambar untuk siaran).
Sudah tentu, log masuk dalam borang ini tidak akan merangkumi pilihan yang kompleks untuk interaksi perkhidmatan anda dan pelbagai sistem luaran, tetapi mewujudkan perintah sedemikian pada permulaan pembangunan projek adalah salah satu perkara yang anda akan berterima kasih kepada diri sendiri lebih daripada sekali.
Anda boleh memahami kod sumber sistem yang terhasil dalam projek:
Sumber: www.habr.com
