APM elastis di aplikasi

Saya belum menerbitkan artikel untuk waktu yang lama dan sekarang lagi ... Artikel ini tidak terlalu besar, tapi, semoga bermanfaat. Setelah kami memutuskan untuk menggunakan Prometheus untuk mengumpulkan metrik, tapi ... Setelah beberapa saat, kami memutuskan untuk beralih ke Elastic APM, karena kami sudah memiliki seluruh tumpukan Elastis dan kami memutuskan untuk mendukung metrik dalam tumpukan ini.


Jadi, Elastic APM adalah alat untuk bekerja dengan metrik, untuk ini aplikasinya menggunakan Elastic APM Agent - agen untuk mengumpulkan metrik untuk berbagai bahasa. Kami menggunakan Elastic APM .NET Agent. Paket ini didukung oleh .NET Framework sejak versi 4.6.2.


Agen mengirim metrik ke server (Elastic APM Server). Semua pengaturan yang diperlukan ditulis dalam web.config dengan kunci spesifik yang diharapkan oleh Agen APM Elastis.
Kita perlu mengkonfigurasi setidaknya url untuk Server APM Elastis. Untuk memisahkan, saat menampilkan metrik dalam LC, berdasarkan aplikasi dan lingkungan, kita memerlukan parameter berikut:


  • ElasticApm: ServiceName - nama layanan, harus memenuhi aturan berikut: ^ [a-zA-Z0-9 _-] + $.
  • ElasticApm: Lingkungan - nama lingkungan memungkinkan Anda untuk memfilter data di tingkat global dalam aplikasi. Hanya didukung di Kibana dimulai dengan versi 7.2.

Untuk mengatur waktu setelah metrik mana yang akan dikirim, kami memerlukan parameter berikut:


  • ElasticApm: MetricsInterval - memungkinkan Anda untuk mengatur waktu setelah mana metrik akan dikirim ke server, secara default - 5 dtk. Jika waktunya diatur ke 0, metrik tidak akan dikirim ke server. Semua pengukuran untuk parameter ini dalam hitungan detik.

Anda juga dapat mengkonfigurasi level logging: ElasticApm: LogLevel.


Contoh mengisi web.config:


<?xml version="1.0" encoding="utf-8"?> <!-- ... --> <configuration> <!-- ... --> <appSettings> <!-- ... --> <add key="ElasticApm:ServerUrls" value="https://my-apm-server:8200" /> <add key="ElasticApm:MetricsInterval" value="10" /> <add key="ElasticApm:Environment" value="Stage" /> <add key="ElasticApm:ServiceName" value="Web.Api" /> <!-- ... --> </appSettings> <!-- ... --> </configuration> 

Unit kerja dari paket Agen APM Elastis adalah transaksi - objek dari jenis transaksi IT. Data transaksi dikumpulkan di dalam objek Reporter dan dikirim ke server satu kali pada waktu yang ditentukan. Pengaturan waktu pengiriman diberikan di atas.


Awal transaksi dimulai dengan panggilan ke metode StartTransaction, selesai dengan panggilan ke metode End (). Selain metode StartTransaction, Anda juga dapat menggunakan metode CaptureTransaction, tetapi metode End () tidak dipanggil untuk itu, semua yang Anda butuhkan diteruskan sebagai parameter untuk metode tersebut. Jika tidak perlu untuk menangkap pengecualian, maka ada metode CaptureException untuk ini.


Metode ini akan menulis objek transaksi yang akan berisi pengecualian yang diteruskan ke sana. Semua informasi tambahan - metadata - ditulis ke objek transaksi dengan mengisi properti Label dari objek transaksi.


Jadi apa yang terjadi? Pertama, tambahkan model yang akan berisi pengaturan yang diperlukan untuk objek transaksi IT bagi kami:


 public class MeasurementData { public static string ApmServerUrl => ConfigurationManager.AppSettings["ElasticApm:ServerUrls"] ?? "http://localhost:8200"; public static string MetricsInterval => ConfigurationManager.AppSettings["ElasticApm:MetricsInterval"] ?? "10"; public static string ApmEnvironment => ConfigurationManager.AppSettings["ElasticApm:Environment"] ?? "local"; public static string ServiceName => ConfigurationManager.AppSettings["ElasticApm:ServiceName"] ?? "Api"; public ITransaction MetricsObject { get; set; } //    public static ITransaction Create(string metricsName) { Environment.SetEnvironmentVariable(ConfigConsts.EnvVarNames.ServerUrls, ApmServerUrl); Environment.SetEnvironmentVariable(ConfigConsts.EnvVarNames.MetricsInterval, MetricsInterval); Environment.SetEnvironmentVariable(ConfigConsts.EnvVarNames.Environment, ApmEnvironment); Environment.SetEnvironmentVariable(ConfigConsts.EnvVarNames.ServiceName, ServiceName); return Agent.Tracer.StartTransaction(metricsName, ApiConstants.TypeRequest); } } 

Selanjutnya, kita membuat pembangun di mana kita akan membuat objek transaksi, menulis metadata ke transaksi, membuat transaksi untuk menyimpan pengecualian, menyelesaikan transaksi:


 public class MetricsBuilder { private readonly MeasurementData _measurementData = new MeasurementData(); private string _metricName; public void BuildMetrics(string metricName) { //      ,   _metricName = string.IsNullOrEmpty(metricName) ? "api_payment_request_duration" : metricName; CheckAndCreateMetricsObjects(); } //      public void AddMetricsLabels(string key, string value) { CheckAndCreateMetricsObjects(); if (!_measurementData.MetricsObject.Labels.ContainsKey(key)) { _measurementData.MetricsObject.Labels.Add(key, value); return; } _measurementData.MetricsObject.Labels[key] = value; } //    public void CaptureMetricException(Exception exception) { CheckAndCreateMetricsObjects(); _measurementData.MetricsObject.CaptureException(exception); } public void Dispose() { CheckAndCreateMetricsObjects(); _measurementData.MetricsObject.End(); } // ,      , //   -  private void CheckAndCreateMetricsObjects() { if (_measurementData.MetricsObject == null) { _measurementData.MetricsObject = MeasurementData.Create(_metricName); Logger.Info($"{nameof(MetricsBuilder)}: CurrentTransaction: {JsonConvert.SerializeObject(Agent.Tracer.CurrentTransaction)} " + $"ServerUrls: {JsonConvert.SerializeObject(Agent.Config.ServerUrls)} " + $"MetricsIntervalInMilliseconds: {JsonConvert.SerializeObject(Agent.Config.MetricsIntervalInMilliseconds)}"); } } } public interface IMetricsService : IDisposable { void AddMetricsLabels(string key, string value); void CaptureMetricException(string message, Exception exception); } public class MetricsService : IMetricsService { private readonly MetricsBuilder _builder; public MetricsService(string metricName) { _builder = new MetricsBuilder(); Build(metricName); } public void AddMetricsLabels(string key, string value) { try { _builder.AddMetricsLabels(key, value); } catch (Exception exception) { CaptureMetricException("Can't write metrics labels", exception); } } public void CaptureMetricException(string message, Exception exception) { Logger.Error(message, exception); try { _builder.CaptureMetricException(exception); } catch (Exception exec) { Logger.Error("Can't write capture exception of metrics", exec); } } public void Dispose() { try { _builder.Dispose(); } catch (Exception exception) { CaptureMetricException($"Can't to do correct dispose of object: {typeof(MetricsService)}", exception); } } private void Build(string metricName) { try { _builder.BuildMetrics(metricName); } catch (Exception exception) { CaptureMetricException("Can't create metrics object", exception); } } } 

Untuk kelas tempat metrik dikumpulkan, kami membuat dekorator tempat kami akan menggunakan kelas MetricsService kami. Jangan lupa tentang mendaftarkan dekorator untuk implementasi dependensi yang benar.


 public class TestClientMetricsService : ITestObject { private readonly ITestObject _testObject; public GatewayClientMetricsService(ITestObject testObject) { _testObject = testObject; } public ProcessingResult TestMethod() { return WriteMetrics("Test_Method", () => _testObject.Test()); } private ProcessingResult WriteMetrics(string methodName, Func<Result> testMethod) { using (var metricsService = new MetricsService(methodName)) { try { metricsService.AddMetricsLabels("assemblyName", Assembly.GetCallingAssembly().FullName); var requestResult = testMethod(); metricsService.AddMetricsLabels("success", requestResult?.Success.ToString() ?? "false"); metricsService.AddMetricsLabels("resultCode", requestResult?.GetResultCode().ToString()); return requestResult; } catch (Exception exception) { metricsService.CaptureMetricException("Can't write metrics", exception); throw; } } } } 

Saya harap artikel ini bermanfaat bagi mereka yang ingin menggunakan Elastic APM sebagai alat untuk mengumpulkan metrik.

Source: https://habr.com/ru/post/id485996/


All Articles