Π›ΠΎΠ³Π²Π°Π½Π΅ Π² микросСрвисна срСда .Net Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ°

Π›ΠΎΠ³Π²Π°Π½Π΅ Π² микросСрвисна срСда .Net Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ°

Π›ΠΎΠ³ΠΈΡ‚Π΅ Π΅ ΠΈΠ·ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»Π½ΠΎ Π²Π°ΠΆΠ΅Π½ инструмСнт Π·Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΡ†ΠΈΡ‚Π΅, Π½ΠΎ ΠΊΠΎΠ³Π°Ρ‚ΠΎ става Π²ΡŠΠΏΡ€ΠΎΡ Π·Π° създаванС Π½Π° Ρ€Π°Π·ΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈ систСми, Ρ‚ΠΎΠΉ става основСн Π΅Π»Π΅ΠΌΠ΅Π½Ρ‚, ΠΊΠΎΠΉΡ‚ΠΎ трябва Π΄Π° бъдС Π·Π°Π»ΠΎΠΆΠ΅Π½ Π² основата Π½Π° Π²Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Π² ΠΏΡ€ΠΎΡ‚ΠΈΠ²Π΅Π½ случай слоТността Π½Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°Ρ‚Π° Π½Π° микросСрвизи Π±ΡŠΡ€Π·ΠΎ Ρ‰Π΅ сС прояви.

Π’ .Net Core 3 бСшС Π΄ΠΎΠ±Π°Π²Π΅Π½Π° страхотна Π²ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ Π·Π° ΠΏΡ€Π΅Π΄Π°Π²Π°Π½Π΅ Π½Π° контСкста Π½Π° корСлация Π² HTTP заглавията, Ρ‚Π°ΠΊΠ° Ρ‡Π΅ Π°ΠΊΠΎ прилоТСнията Π²ΠΈ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚ пряки HTTP повиквания Π·Π° взаимодСйствиС ΠΌΠ΅ΠΆΠ΄Ρƒ услугитС, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° сС Π²ΡŠΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ ΠΎΡ‚ Ρ‚Π°Π·ΠΈ Π²Π³Ρ€Π°Π΄Π΅Π½Π° функционалност. Π’ΡŠΠΏΡ€Π΅ΠΊΠΈ Ρ‚ΠΎΠ²Π°, Π°ΠΊΠΎ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°Ρ‚Π° Π½Π° вашия Π±Π΅ΠΊΠ΅Π½Π΄ ΠΏΡ€Π΅Π΄Π²ΠΈΠΆΠ΄Π° взаимодСйствиС Ρ‡Ρ€Π΅Π· Π±Ρ€ΠΎΠΊΠ΅Ρ€ Π½Π° ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ (RabbitMQ, Kafka ΠΈ Π΄Ρ€.), всС ΠΏΠ°ΠΊ Ρ‰Π΅ трябва сами Π΄Π° сС ΠΏΠΎΠ³Ρ€ΠΈΠΆΠΈΡ‚Π΅ Π·Π° ΠΏΡ€Π΅Π΄Π°Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° корСлационния контСкст Ρ‡Ρ€Π΅Π· Ρ‚Π΅Π·ΠΈ ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ.

Π’ Ρ‚Π°Π·ΠΈ статия Ρ‰Π΅ Π²Π·Π΅ΠΌΠ΅ΠΌ прост ΡƒΠ΅Π± API ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Ρ‰Π΅ ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΈΡ€Π°ΠΌΠ΅ Π»ΠΎΠ³Π²Π°Π½Π΅Ρ‚ΠΎ, ΠΊΠΎΠ΅Ρ‚ΠΎ

  • Ρ‰Π΅ Π·Π°ΠΏΠ°Π·ΠΈ послСдоватСлна корСлация ΠΌΠ΅ΠΆΠ΄Ρƒ Π»ΠΎΠ³ΠΎΠ²Π΅Ρ‚Π΅ Π½Π° нСзависимитС услуги, Ρ‚Π°ΠΊΠ° Ρ‡Π΅ Π΄Π° ΠΌΠΎΠΆΠ΅ΠΌ лСсно Π΄Π° прослСдим всички активности, ΠΊΠΎΠΈΡ‚ΠΎ са Π±ΠΈΠ»ΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠΈΡ€Π°Π½ΠΈ ΠΎΡ‚ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Π° клиСнтска заявка.

  • Π΄Π° ΠΈΠΌΠ°ΠΌΠ΅ Π΅Π΄ΠΈΠ½Π½Π° Ρ‚ΠΎΡ‡ΠΊΠ° Π·Π° Π²Ρ…ΠΎΠ΄ с ΡƒΠ΄ΠΎΠ±Π΅Π½ Π°Π½Π°Π»ΠΈΠ·, Ρ‚Π°ΠΊΠ° Ρ‡Π΅ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚ΡŠΡ‚ Π·Π° Π»ΠΎΠ³ΠΈΡ€Π°Π½Π΅ Π΄Π° бъдС ΠΏΠΎΠ»Π΅Π·Π΅Π½ Π΄ΠΎΡ€ΠΈ Π½Π° ΠŸΠΎΠ΄Π΄Ρ€ΡŠΠΆΠΊΠ°Ρ‚Π°, която ΠΏΠΎΠ»ΡƒΡ‡Π°Π²Π° Π²ΡŠΠΏΡ€ΠΎΡΠΈ ΠΎΡ‚ Ρ‚ΠΈΠΏΠ° "Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ ΠΌΠΈ сС появи Π³Ρ€Π΅ΡˆΠΊΠ° с Ρ‚Π°ΠΊΡŠΠ² ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° заявката".

ΠŸΡŠΡ€Π²ΠΎ, трябва Π΄Π° ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ доставчика Π½Π° Π»ΠΎΠ³ΠΈΡ€Π°Π½Π΅ Π² Π½Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. ΠžΡΠ½ΠΎΠ²Π½ΠΎΡ‚ΠΎ изискванС Π·Π° ΡΡŠΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ Π»ΠΎΠ³ΠΈΡ€Π°Π½Π΅ Π΅ структурираност, Ρ‚.Π΅. трябва Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈΠΌ Π½Π΅ с плоски тСкстови ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ, Π° с ΠΎΠ±Π΅ΠΊΡ‚ΠΈ. Π‘ Ρ‚Π°ΠΊΠΈΠ²Π° Π»ΠΎΠ³ΠΎΠ²Π΅ ΠΌΠΎΠΆΠ΅ΠΌ лСсно Π΄Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°ΠΌΠ΅ прСдставяния Π½Π° Π½Π°ΡˆΠΈΡ‚Π΅ ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ ΠΎΡ‚ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ пСрспСктиви ΠΈ Π΄Π° ΠΏΡ€ΠΎΠ²Π΅ΠΆΠ΄Π°ΠΌΠ΅ Π°Π½Π°Π»ΠΈΡ‚ΠΈΡ‡Π½Π° Ρ€Π°Π±ΠΎΡ‚Π°.

Π—Π° Π½Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‰Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚Π° Serilog, ΠΊΠΎΠΉΡ‚ΠΎ ΠΏΡ€Π΅Π΄Π»Π°Π³Π° ΠΎΡ‚Π»ΠΈΡ‡Π½Π° ΠΏΠΎΠ΄Π΄Ρ€ΡŠΠΆΠΊΠ° Π·Π° структурно Π»ΠΎΠ³ΠΈΡ€Π°Π½Π΅ ΠΈ Π±ΠΎΠ³Π°Ρ‚Π° систСма ΠΎΡ‚ Ρ€Π°Π·ΡˆΠΈΡ€Π΅Π½ΠΈΡ. Π©Π΅ пропусна основнитС ΡΡ‚ΡŠΠΏΠΊΠΈ ΠΏΠΎ Π½Π΅Π³ΠΎΠ²ΠΎΡ‚ΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€Π°Π½Π΅ (ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π½Π°ΠΌΠ΅Ρ€ΠΈΡ‚Π΅ ΠΌΠ½ΠΎΠ³ΠΎ статии ΠΏΠΎ Ρ‚Π°Π·ΠΈ Ρ‚Π΅ΠΌΠ°) ΠΈ Ρ‰Π΅ ΠΏΡ€ΠΈΠ΅ΠΌΠ°, Ρ‡Π΅

  • Serilog Π²Π΅Ρ‡Π΅ Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€Π°Π½ ΠΈ Π΅ Π»ΠΎΠ³Π΅Ρ€ ΠΏΠΎ ΠΏΠΎΠ΄Ρ€Π°Π·Π±ΠΈΡ€Π°Π½Π΅ Π² вашия доставчик Π½Π° ΠΈΠ½ΠΆΠ΅ΠΊΡ‚ΠΈΡ€Π°Π½Π΅ Π½Π° зависимости

  • Π² Π½Π΅Π³ΠΎΠ²Π°Ρ‚Π° конфигурация Π΅ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΎ обогатяванС Π½Π° ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡΡ‚Π° със свойствата Π½Π° контСкста (Enrich.FromLogContext)

Π‘Π»Π΅Π΄Π²Π°Ρ‰Π°Ρ‚Π° ΡΡ‚ΡŠΠΏΠΊΠ° Π΅ Π΄Π° ΠΈΠ·Π±Π΅Ρ€Π΅ΠΌ Π² коя систСма Π·Π° Ρ†Π΅Π½Ρ‚Ρ€Π°Π»ΠΈΠ·ΠΈΡ€Π°Π½ΠΎ ΡΡŠΠ±ΠΈΡ€Π°Π½Π΅ Π½Π° Π»ΠΎΠ³ΠΎΠ²Π΅ Π΄Π° ΠΈΠ·ΠΏΡ€Π°Ρ‰Π°ΠΌΠ΅ ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ ΠΎΡ‚ 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);

Π‘Π»Π΅Π΄ стартиранС Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ Ρ‰Π΅ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° наблюдавамС Π½Π°ΡˆΠΈΡ‚Π΅ ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ Π½Π΅ само Π² ΠΊΠΎΠ½Π·ΠΎΠ»Π°Ρ‚Π°, Π½ΠΎ ΠΈ Π² Kibana.

Π›ΠΎΠ³Π²Π°Π½Π΅ Π² микросСрвисна срСда .Net Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ°

Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡΠΈ

Π›ΠΎΠ³Π²Π°Π½Π΅ Π² микросСрвисна срСда .Net Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ°

Π’ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ ΠΎΡ‚ Ρ‚ΠΈΠΏ услуга ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΎΡ‚ΠΊΡ€ΠΎΠΈΠΌ Π΄Π²Π° основни интСрфСйса Π·Π° взаимодСйствиС с външния свят, ΠΊΠΎΠΈΡ‚ΠΎ Ρ‰Π΅ ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡ΠΈΠΌ ΠΊΠ°Ρ‚ΠΎ Π²Π΅Ρ€Ρ‚ΠΈΠΊΠ°Π»Π΅Π½ ΠΈ Ρ…ΠΎΡ€ΠΈΠ·ΠΎΠ½Ρ‚Π°Π»Π΅Π½. ВСртикалният интСрфСйс Π΅ ΡƒΠ΅Π± API, ΠΏΡ€Π΅Π· ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΈΠ΄Π²Π°Ρ‚ извиквания ΠΎΡ‚ клиСнтското ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. Π₯оризонталният Π΅ Π±Ρ€ΠΎΠΊΠ΅Ρ€ Π½Π° ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ, ΠΊΠΎΠΉΡ‚ΠΎ сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° Π·Π° ΠΎΠ±ΠΌΠ΅Π½ Π½Π° Π΄Π°Π½Π½ΠΈ с Π΄Ρ€ΡƒΠ³ΠΈ Π²ΡŠΡ‚Ρ€Π΅ΡˆΠ½ΠΈ услуги.

НСка Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ Π΅Ρ‚Π°ΠΏΠΈΡ‚Π΅ Π½Π° внСдряванС Π½Π° корСлация ΠΏΡ€ΠΈ всСки ΠΎΡ‚ Ρ‚Π΅Π·ΠΈ интСрфСйси.

ΠšΠΎΡ€Π΅Π»Π°Ρ†ΠΈΡ Π² HTTP заявкитС

Π—Π° Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ възмоТно Π½Π°ΠΉ-ΠΌΠ½ΠΎΠ³ΠΎ информация, Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π΄Π° Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π°ΠΌΠ΅ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π·Π° корСлация възмоТно Π½Π°ΠΉ-Π±Π»ΠΈΠ·ΠΎ Π΄ΠΎ Π½Π°Ρ‡Π°Π»ΠΎΡ‚ΠΎ Π½Π° активността, Ρ‚.Π΅. Π½Π° шлюза ΠΈΠ»ΠΈ Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π½Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° (ΠΌΠΎΠ±ΠΈΠ»Π΅Π½ ΠΈΠ»ΠΈ ΡƒΠ΅Π±). Въй ΠΊΠ°Ρ‚ΠΎ днСс Ρ€Π°Π·Π³Π»Π΅ΠΆΠ΄Π°ΠΌΠ΅ Π±Π΅ΠΊΠ΅Π½Π΄ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, просто Ρ‰Π΅ ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡ΠΈΠΌ изискванСто Π·Π° Π·Π°Π΄ΡŠΠ»ΠΆΠΈΡ‚Π΅Π»Π΅Π½ Π·Π°Π³Π»Π°Π²Π΅Π½ Π΅Ρ‚ΠΈΠΊΠ΅Ρ‚ β€žX-Correlation-IDβ€œ във всички заявки към ΡƒΠ΅Π± API.

ДобавямС ΠΏΠ°ΠΊΠ΅Ρ‚Π° 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-Ρ„ΠΈΠ»Ρ‚ΡŠΡ€:

ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ Π·Π°ΠΏΠ΅Ρ‡Π°Ρ‚Π°Π½Π½Ρ‹ΠΉ класс ApiRequestFilter : ActionFilterAttribute
{
    ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ ApiRequestFilter(IApiRequestTracker apiRequestTracker, ICorrelationContextAccessor correlationContextAccessor)
    {
        _correlationContextAccessor = correlationContextAccessor ?? Π²Ρ‹Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ Π½ΠΎΠ²ΠΎΠ΅ ArgumentNullException(nameof(correlationContextAccessor));
    }
    
    частный readonly ICorrelationContextAccessor _correlationContextAccessor;
    
    ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ пСрСопрСдСляСмый async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        Ссли (!Guid.TryParse(_correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
        {
            context.Result = новая BadRequestResult();
            Π²ΠΎΠ·Π²Ρ€Π°Ρ‚;
        }
    
        await next.Invoke();
    }
    
    ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ пСрСопрСдСляСмый async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        await next.Invoke();
    }
}

И Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π΅Π³ΠΎ Π² ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π΅Ρ€

[Route("[controller]")]
[ApiController]
[ServiceFilter(typeof(ApiRequestFilter))]
ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ класс CarsController : ControllerBase
{

}

Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π΅Ρ€ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ 400 Bad request Π½Π° всС запросы Π±Π΅Π· Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° с ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΠΎΠΌ.

ПослС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΌΡ‹ Π½Π°Ρ‡Π°Π»ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ ΠΎΡ‚ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°, ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π² контСкст Турналирования, сдСлаСм для этого ΠΎΠ±Π΅Ρ€Ρ‚ΠΊΡƒ:

ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ класс CorrelationIdContextLogger
{
    ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ CorrelationIdContextLogger(RequestDelegate next)
    {
        _next = next ?? Π²Ρ‹Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ Π½ΠΎΠ²ΠΎΠ΅ ArgumentNullException(nameof(next));
    }
    
    readonly RequestDelegate _next;
    
    ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ async Task InvokeAsync(HttpContext httpContext, ILogger logger, ICorrelationContextAccessor correlationContextAccessor)
    {
        Ссли (Guid.TryParse(correlationContextAccessor.CorrelationContext.CorrelationId, out Guid correlationId))
        {
            ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ (logger.BeginScopeWith(("CorrelationId", correlationId)))
            {
                await _next(context);
            }
        }
        Π΅Ρ‰Π΅
        {
            await _next(context);
        }
    }
}

Π’ нашСм ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ стандартный ILogger ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° Microsoft.Extensions.Logging.Abstractions, поэтому Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅ΠΌ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ простого Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ ΠΊ Π½Π΅ΠΌΡƒ.

public static IDisposable BeginScopeWith(this ILogger logger, params (string key, object value)[] keys)
{
    Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ logger.BeginScope(keys.ToDictionary(x => x.key, x => x.value));
}

ДобавляСм ΠΎΠ±Π΅Ρ€Ρ‚ΠΊΡƒ Π² ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅Ρ€ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ запроса ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Π½ΡƒΠΆΠ½Ρ‹ΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚.

ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ класс Startup
{
    ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ void Configure(IApplicationBuilder application)
    {
        application.UseMiddleware();
    }
}

Π’Π΅ΠΏΠ΅Ρ€ΡŒ всС активности, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΡ€ΠΎΠΆΠ΄Π΅Π½Ρ‹ запросами ΠΊ Π½Π°ΡˆΠ΅ΠΌΡƒ Π²Π΅Π±-API, содСрТат коррСляционный ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€, ΠΏΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌΡƒ ΠΈΡ… ΠΌΠΎΠΆΠ½ΠΎ Π»Π΅Π³ΠΊΠΎ ΡΠ²ΡΠ·Π°Ρ‚ΡŒ.

Π›ΠΎΠ³Π²Π°Π½Π΅ Π² микросСрвисна срСда .Net Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ°

ΠšΠΎΡ€Ρ€Π΅Π»ΡΡ†ΠΈΡ Π² сообщСниях Π±Ρ€ΠΎΠΊΠ΅Ρ€Π°

Π‘Π»Π΅Π΄Π²Π°Ρ‰Π°Ρ‚Π° ΡΡ‚ΡŠΠΏΠΊΠ° Π΅ Π΄Π° настройим ΠΏΡ€Π΅Π΄Π°Π²Π°Π½Π΅Ρ‚ΠΎ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π°Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° корСлационния ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Ρ‡Ρ€Π΅Π· Π±Ρ€ΠΎΠΊΠ΅Ρ€ Π½Π° ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ. Π’ нашия ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‰Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ RabbitMQ, Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΡŠΡ‚ Ρ‰Π΅ бъдС Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΡŠΡ‚ MassTransit. ΠžΡ‚Π½ΠΎΠ²ΠΎ, Ρ‰Π΅ пропуснСм ΠΏΡŠΡ€Π²ΠΎΠ½Π°Ρ‡Π°Π»Π½Π°Ρ‚Π° настройка Π½Π° MassTransit ΠΈ Ρ‰Π΅ ΠΏΡ€Π΅ΠΌΠΈΠ½Π΅ΠΌ Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ към настройката Π½Π° Π»ΠΎΠ³Π²Π°Π½Π΅Ρ‚ΠΎ.

Π—Π° Π½Π°Ρ‡Π°Π»ΠΎ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€Π°ΠΌΠ΅ Π»ΠΎΠ³ΠΎΠ²Π΅Ρ‚Π΅ Π½Π° самия 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; }
    }
}

Π‘ΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡΡ‚Π° Π½Π° MassTransit ΠΏΠΎ ΡΡŠΡ‰Π΅ΡΡ‚Π²ΠΎ прСдставляват ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚, Π² ΠΊΠΎΠΉΡ‚ΠΎ са Π²Π»ΠΎΠΆΠ΅Π½ΠΈ ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ Π½Π° Π±Ρ€ΠΎΠΊΠ΅Ρ€Π°. ΠšΠΎΠ½Π²Π΅Ρ€Ρ‚ΡŠΡ‚ ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π° ΠΏΡ€ΠΈΠ±Π»ΠΈΠ·ΠΈΡ‚Π΅Π»Π½ΠΎ Ρ‚Π°ΠΊΠ°:

{
  "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
    {
        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; }
}

Ако Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΠΎΠ±Π½ΠΎΠ²Π΅Π½ΠΎΡ‚ΠΎ ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅, Ρ‰Π΅ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Π΅ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΡŠΡ‚ Π½Π° корСлация Π½Π΅ само стана част ΠΎΡ‚ Π½Π°ΡˆΠ΅Ρ‚ΠΎ ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅, Π½ΠΎ ΠΈ ΠΎΡ‚ ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π° β€” Ρ‚ΠΎΠ·ΠΈ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ сСга Ρ‰Π΅ сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° ΠΈ Π² Π»ΠΎΠ³ΠΎΠ²Π΅Ρ‚Π΅ Π½Π° MassTransit, ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π²Π°, Ρ‡Π΅ Ρ‰Π΅ бъдС ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎ-лСсно Π΄Π° сС справим с ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈΡ‚Π΅ Π½Π° Π½ΠΈΠ²ΠΎ ΡΡŠΠΎΠ±Ρ‰ΠΈΡ‚Π΅Π»Π΅Π½ Π±Ρ€ΠΎΠΊΠ΅Ρ€.

{
  "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": "Π—Π΄Ρ€Π°Π²Π΅ΠΉ"
  }
}

ΠžΡΡ‚Π°Π²Π° Π½ΠΈ Π΄Π° настроим рСгистриранСто Π½Π° Ρ‚Π΅Π·ΠΈ слуТСбни свойства Π½Π° ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅Ρ‚ΠΎ, Π·Π° ΠΊΠΎΠ΅Ρ‚ΠΎ Ρ‰Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΏΠ°ΠΊΠ΅Ρ‚Π° Serilog.Enrichers.MassTransitMessage. ΠŸΠ°ΠΊΠ΅Ρ‚ΡŠΡ‚ добавя Ρ„ΠΈΠ»Ρ‚ΡŠΡ€ Π² ΠΊΠΎΠ½Π²Π΅ΠΉΠ΅Ρ€Π° Π·Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π½Π° ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ Π² MassTransit, ΠΊΠΎΠΉΡ‚ΠΎ поставя контСкста Π½Π° ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅Ρ‚ΠΎ Π² потокобСзопасСн стСк. Serilog Ρ‡Π΅Ρ‚Π΅ контСкста ΠΎΡ‚ стСка ΠΈ добавя Ρ‚Π΅Π·ΠΈ Π΄ΠΎΠΏΡŠΠ»Π½ΠΈΡ‚Π΅Π»Π½ΠΈ свойства Π² Π½Π°ΡˆΠΈΡ‚Π΅ Π»ΠΎΠ³ ΠΎΠ±Π΅ΠΊΡ‚ΠΈ.

Install-Package Serilog.Enrichers.MassTransitMessage

Π’ MassTransit вмъквамС Ρ„ΠΈΠ»Ρ‚ΡŠΡ€

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

А Π² конфигурацията Π½Π° Serilog добавямС Π΅Π½Ρ€ΠΈΡ‡Π΅Ρ€

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

Въй ΠΊΠ°Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ, ΠΊΠΎΠ΅Ρ‚ΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π°Π²Π° ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅ ΠΎΡ‚ ΠΎΠΏΠ°ΡˆΠΊΠ°Ρ‚Π° RabbitMQ, ΠΈΠΌΠ° Π΄ΠΎΡΡ‚ΡŠΠΏ Π΄ΠΎ всички свойства Π½Π° ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π° Π½Π° MassTransit, ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΎΡ‚ΠΎ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π½Π° корСлация Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ-ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π», Π° ΡΡŠΡ‰ΠΎ ΠΈ Π΄Π° Π³ΠΎ ΠΏΡ€Π΅Π΄Π°Π²Π°ΠΌΠ΅ ΠΏΠΎ Π²Π΅Ρ€ΠΈΠ³Π°Ρ‚Π° Π½Π° извиквания.

Π’ Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ Π½Π°ΡˆΠΈΡ‚Π΅ Π»ΠΎΠ³ΠΎΠ²Π΅ Π·Π°ΠΏΠΎΡ‡Π½Π°Ρ…Π° Π΄Π° ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Ρ‚ CorrelationId Π½Π΅ само Π² Ρ€Π°ΠΌΠΊΠΈΡ‚Π΅ Π½Π° Π΅Π΄ΠΈΠ½ сСрвис, Π½ΠΎ ΠΈ ΠΏΡ€ΠΈ взаимодСйствиС с Π΄Ρ€ΡƒΠ³ΠΈ прилоТСния.

Π›ΠΎΠ³Π²Π°Π½Π΅ Π² микросСрвисна срСда .Net Π½Π° ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ°

Π’Π°ΠΊΠ° ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π°Ρ‚Π° систСма Π·Π° рСгистрация Π² .Net прилоТСнията Π½ΠΈ позволява Π±Π΅Π· особСни ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ Π΄Π° ΠΊΠΎΡ€Π΅Π»ΠΈΡ€Π°ΠΌΠ΅ Π»ΠΎΠ³ΠΎΠ²Π΅Ρ‚Π΅ ΠΎΡ‚ Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½ΠΎ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ микросСрвиси β€” Π΄ΠΎΡ€ΠΈ ΠΈ Ρ‚Π΅Π·ΠΈ, ΠΊΠΎΠΈΡ‚ΠΎ работят ΠΏΡ€Π΅Π· ΡΡŠΠΎΠ±Ρ‰ΠΈΡ‚Π΅Π»Π΅Π½ Π±Ρ€ΠΎΠΊΠ΅Ρ€. А с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° Elasticsearch ΠΌΠΎΠΆΠ΅ΠΌ Π±ΡŠΡ€Π·ΠΎ ΠΈ ΡƒΠ΄ΠΎΠ±Π½ΠΎ Π΄Π° Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€Π°ΠΌΠ΅ Π»ΠΎΠ³ΠΎΠ²Π΅Ρ‚Π΅, създавайки Π² Kibana Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΈΡ‚Π΅ Π½ΠΈ Ρ‚Π°Π±Π»Π° (ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΡŠΡ‚ Π΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ Π½Π° ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ към публикацията).

Π Π°Π·Π±ΠΈΡ€Π° сС, Π² Ρ‚ΠΎΠ·ΠΈ Π²ΠΈΠ΄ Π»ΠΎΠ³Π²Π°Π½Π΅Ρ‚ΠΎ няма Π΄Π° ΠΏΠΎΠΊΡ€ΠΈΠ΅ слоТни Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΈ Π½Π° взаимодСйствиС ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Π°ΡˆΠΈΡ‚Π΅ услуги ΠΈ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ външни систСми, Π½ΠΎ установяванСто Π½Π° Ρ‚Π°ΠΊΡŠΠ² Ρ€Π΅Π΄ Π² самото Π½Π°Ρ‡Π°Π»ΠΎ Π½Π° Ρ€Π°Π·Π²ΠΈΡ‚ΠΈΠ΅Ρ‚ΠΎ Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π΅ Π΅Π΄Π½ΠΎ ΠΎΡ‚ Π½Π΅Ρ‰Π°Ρ‚Π°, Π·Π° ΠΊΠΎΠΈΡ‚ΠΎ сами Ρ‰Π΅ си Π±Π»Π°Π³ΠΎΠ΄Π°Ρ€ΠΈΡ‚Π΅ Π² Π±ΡŠΠ΄Π΅Ρ‰Π΅.

ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° сС Π·Π°ΠΏΠΎΠ·Π½Π°Π΅Ρ‚Π΅ с изходния ΠΊΠΎΠ΄ Π½Π° ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π°Ρ‚Π° систСма Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°: github.com/a-postx/YA.ServiceTemplate

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС с Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ πŸ”₯ ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС с Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ | ProHoster