From f3979769e25c550774856982522df063b5afdd2d Mon Sep 17 00:00:00 2001 From: Andrey Shabarshov Date: Tue, 11 Jul 2023 16:37:24 +0100 Subject: [PATCH] DEEP-28, DEEP-29 Metrics added --- QRBeeApi/Program.cs | 4 +++ QRBeeApi/QRBee.Api.csproj | 1 + QRBeeApi/Services/CustomMetrics.cs | 39 ++++++++++++++++++++++++++++ QRBeeApi/Services/QRBeeAPIService.cs | 27 ++++++++++++++++++- 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 QRBeeApi/Services/CustomMetrics.cs diff --git a/QRBeeApi/Program.cs b/QRBeeApi/Program.cs index 4d80d44..a5c5d5b 100644 --- a/QRBeeApi/Program.cs +++ b/QRBeeApi/Program.cs @@ -14,10 +14,13 @@ GlobalContext.Properties["LOGS_ROOT"] = Environment.GetEnvironmentVariable("LOGS System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); builder.Logging.AddLog4Net("log4net.config"); +var meters = new CustomMetrics(); + builder.Services.AddOpenTelemetry() .WithMetrics(options => { options + .AddMeter(meters.MetricName) .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddRuntimeInstrumentation() @@ -50,6 +53,7 @@ builder.Services .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() ; var app = builder.Build(); diff --git a/QRBeeApi/QRBee.Api.csproj b/QRBeeApi/QRBee.Api.csproj index becaa94..c2f65a7 100644 --- a/QRBeeApi/QRBee.Api.csproj +++ b/QRBeeApi/QRBee.Api.csproj @@ -20,6 +20,7 @@ + diff --git a/QRBeeApi/Services/CustomMetrics.cs b/QRBeeApi/Services/CustomMetrics.cs new file mode 100644 index 0000000..1843d63 --- /dev/null +++ b/QRBeeApi/Services/CustomMetrics.cs @@ -0,0 +1,39 @@ +using System.Diagnostics.Metrics; + +namespace QRBee.Api.Services +{ + public class CustomMetrics + { + private Counter MerchantRequestCounter { get; } + private Counter MerchantResponseCounter { get; } + private Counter SucceededTransactionsCounter { get; } + private Counter FailedTransactionsCounter { get; } + private Counter TotalCreditCardCheckTime { get; } + private Counter TotalPaymentTime { get; } + + + public string MetricName { get; } + + public CustomMetrics(string meterName = "QRBeeMetrics") { + var meter = new Meter(meterName); + MetricName = meterName; + + MerchantRequestCounter = meter.CreateCounter("merchant-requests", description: "Merchant has sent a request"); + MerchantResponseCounter = meter.CreateCounter("merchant-responses"); + SucceededTransactionsCounter = meter.CreateCounter("transaction-succeeded", description: "Transaction succeeded"); + FailedTransactionsCounter = meter.CreateCounter("transaction-failed", description: "Transaction failed"); + + TotalCreditCardCheckTime = meter.CreateCounter("Total-credit-card-check-time","msec"); + TotalPaymentTime = meter.CreateCounter("Total-payment-time","msec"); + } + + + public void AddMerchantRequest() => MerchantRequestCounter.Add(1); + public void AddMerchantResponse() => MerchantResponseCounter.Add(1); + public void AddSucceededTransaction() => SucceededTransactionsCounter.Add(1); + public void AddFailedTransaction() => FailedTransactionsCounter.Add(1); + public void AddTotalCreditCardCheckTime(long milliseconds) => TotalCreditCardCheckTime.Add(milliseconds); + public void AddTotalPaymentTime(long milliseconds) => TotalPaymentTime.Add(milliseconds); + + } +} diff --git a/QRBeeApi/Services/QRBeeAPIService.cs b/QRBeeApi/Services/QRBeeAPIService.cs index e4cf55b..db2f0b0 100644 --- a/QRBeeApi/Services/QRBeeAPIService.cs +++ b/QRBeeApi/Services/QRBeeAPIService.cs @@ -1,6 +1,7 @@ using QRBee.Api.Services.Database; using QRBee.Core.Data; using QRBee.Core.Security; +using System.Diagnostics; using System.Globalization; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -22,10 +23,12 @@ namespace QRBee.Api.Services private readonly TransactionMonitoring _transactionMonitoring; private static readonly object _lock = new (); + private readonly CustomMetrics _customMetrics; + private const int MaxNameLength = 512; private const int MaxEmailLength = 512; - public QRBeeAPIService(IStorage storage, ISecurityService securityService, IPrivateKeyHandler privateKeyHandler, IPaymentGateway paymentGateway, ILogger logger, TransactionMonitoring transactionMonitoring) + public QRBeeAPIService(IStorage storage, ISecurityService securityService, IPrivateKeyHandler privateKeyHandler, IPaymentGateway paymentGateway, ILogger logger, TransactionMonitoring transactionMonitoring, CustomMetrics metrics) { _storage = storage; _securityService = securityService; @@ -34,6 +37,8 @@ namespace QRBee.Api.Services _logger = logger; _transactionMonitoring = transactionMonitoring; Init(_privateKeyHandler); + + _customMetrics = metrics; } private static void Init(IPrivateKeyHandler privateKeyHandler) @@ -143,6 +148,9 @@ namespace QRBee.Api.Services try { + + _customMetrics.AddMerchantRequest(); + //1. Check payment request parameters for validity ValidateTransaction(value); var tid = value.ClientResponse.MerchantRequest.MerchantTransactionId; @@ -168,13 +176,20 @@ namespace QRBee.Api.Services _logger.LogInformation($"Transaction=\"{tid}\" Fully validated"); //5. Decrypt client card data + var creditCardCheckTime = Stopwatch.StartNew(); var clientCardData = DecryptClientData(value.ClientResponse.EncryptedClientCardData); //6. Check client card data for validity await CheckClientCardData(clientCardData, value.ClientResponse.MerchantRequest.MerchantTransactionId); _logger.LogInformation($"Transaction=\"{tid}\" Client card data validated"); + var milliseconds = creditCardCheckTime.ElapsedMilliseconds; + creditCardCheckTime.Stop(); + _customMetrics.AddTotalCreditCardCheckTime(milliseconds); + //7. Register preliminary transaction record with expiry of one minute + var paymentTime = Stopwatch.StartNew(); + var info = Convert(value); info.Status = TransactionInfo.TransactionStatus.Pending; @@ -184,22 +199,32 @@ namespace QRBee.Api.Services //8. Send client card data to a payment gateway var gatewayResponse = await _paymentGateway.Payment(info, clientCardData); + milliseconds = paymentTime.ElapsedMilliseconds; + paymentTime.Stop(); + _customMetrics.AddTotalPaymentTime(milliseconds); + //9. Record transaction with result if (gatewayResponse.Success) { info.Status=TransactionInfo.TransactionStatus.Succeeded; info.GatewayTransactionId=gatewayResponse.GatewayTransactionId; + + _customMetrics.AddSucceededTransaction(); } else { info.Status = TransactionInfo.TransactionStatus.Rejected; info.RejectReason = gatewayResponse.ErrorMessage; + + _customMetrics.AddFailedTransaction(); } await _storage.UpdateTransaction(info); _logger.LogInformation($"Transaction=\"{tid}\" complete Status=\"{info.Status}\""); //10. Make response for merchant var response = MakePaymentResponse(value, info.TransactionId ?? "", gatewayResponse.GatewayTransactionId ?? "", info.Status==TransactionInfo.TransactionStatus.Succeeded, info.RejectReason); + + _customMetrics.AddMerchantResponse(); return response; } catch (Exception e)