Merge pull request #1872 from Kukks/invoie-severity

Add invoice event severity
This commit is contained in:
Nicolas Dorier 2020-09-03 21:24:20 +09:00 committed by GitHub
commit 85d393fec3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 110 additions and 51 deletions

View file

@ -20,6 +20,7 @@ namespace BTCPayServer.Data
}
public string Message { get; set; }
public EventSeverity Severity { get; set; } = EventSeverity.Info;
internal static void OnModelCreating(ModelBuilder builder)
{
@ -35,5 +36,25 @@ namespace BTCPayServer.Data
#pragma warning restore CS0618
});
}
public enum EventSeverity
{
Info,
Error,
Success,
Warning
}
public string GetCssClass()
{
return Severity switch
{
EventSeverity.Info => "info",
EventSeverity.Error => "danger",
EventSeverity.Success => "success",
EventSeverity.Warning => "warning",
_ => null
};
}
}
}

View file

@ -0,0 +1,32 @@
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20200901161733_AddInvoiceEventLogSeverity")]
public partial class AddInvoiceEventLogSeverity : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "Severity",
table: "InvoiceEvents",
nullable: false,
defaultValue: 0);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
if (this.SupportDropColumn(migrationBuilder.ActiveProvider))
{
migrationBuilder.DropColumn(
name: "Severity",
table: "InvoiceEvents");
}
}
}
}

View file

@ -240,6 +240,9 @@ namespace BTCPayServer.Migrations
b.Property<string>("Message")
.HasColumnType("TEXT");
b.Property<int>("Severity")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("TEXT");

View file

@ -181,7 +181,7 @@ namespace BTCPayServer.Controllers
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter invoicePaymentMethodFilter, CancellationToken cancellationToken = default)
{
InvoiceLogs logs = new InvoiceLogs();
logs.Write("Creation of invoice starting");
logs.Write("Creation of invoice starting", InvoiceEventData.EventSeverity.Info);
var getAppsTaggingStore = _InvoiceRepository.GetAppsTaggingStore(store.Id);
var storeBlob = store.GetStoreBlob();
@ -273,7 +273,7 @@ namespace BTCPayServer.Controllers
}
catch (AggregateException ex)
{
ex.Handle(e => { logs.Write($"Error while fetching rates {ex}"); return true; });
ex.Handle(e => { logs.Write($"Error while fetching rates {ex}", InvoiceEventData.EventSeverity.Error); return true; });
}
await _InvoiceRepository.AddInvoiceLogs(entity.Id, logs);
});
@ -286,16 +286,16 @@ namespace BTCPayServer.Controllers
return Task.WhenAll(fetchingByCurrencyPair.Select(async pair =>
{
var rateResult = await pair.Value;
logs.Write($"{pair.Key}: The rating rule is {rateResult.Rule}");
logs.Write($"{pair.Key}: The evaluated rating rule is {rateResult.EvaluatedRule}");
logs.Write($"{pair.Key}: The rating rule is {rateResult.Rule}", InvoiceEventData.EventSeverity.Info);
logs.Write($"{pair.Key}: The evaluated rating rule is {rateResult.EvaluatedRule}", InvoiceEventData.EventSeverity.Info);
if (rateResult.Errors.Count != 0)
{
var allRateRuleErrors = string.Join(", ", rateResult.Errors.ToArray());
logs.Write($"{pair.Key}: Rate rule error ({allRateRuleErrors})");
logs.Write($"{pair.Key}: Rate rule error ({allRateRuleErrors})", InvoiceEventData.EventSeverity.Error);
}
foreach (var ex in rateResult.ExchangeExceptions)
{
logs.Write($"{pair.Key}: Exception reaching exchange {ex.ExchangeName} ({ex.Exception.Message})");
logs.Write($"{pair.Key}: Exception reaching exchange {ex.ExchangeName} ({ex.Exception.Message})", InvoiceEventData.EventSeverity.Error);
}
}).ToArray());
}
@ -331,7 +331,7 @@ namespace BTCPayServer.Controllers
paymentMethod.Calculate().Due, supportedPaymentMethod.PaymentId);
if (!string.IsNullOrEmpty(errorMessage))
{
logs.Write($"{logPrefix} {errorMessage}");
logs.Write($"{logPrefix} {errorMessage}", InvoiceEventData.EventSeverity.Error);
return null;
}
@ -348,11 +348,11 @@ namespace BTCPayServer.Controllers
}
catch (PaymentMethodUnavailableException ex)
{
logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Payment method unavailable ({ex.Message})");
logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Payment method unavailable ({ex.Message})", InvoiceEventData.EventSeverity.Error);
}
catch (Exception ex)
{
logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Unexpected exception ({ex.ToString()})");
logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Unexpected exception ({ex.ToString()})", InvoiceEventData.EventSeverity.Error);
}
return null;
}

View file

@ -6,7 +6,9 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.Events;
using BTCPayServer.Logging;
using BTCPayServer.Payments;
using BTCPayServer.Services;
using BTCPayServer.Services.Invoices;
@ -306,7 +308,7 @@ namespace BTCPayServer.HostedServices
List<Task> tasks = new List<Task>();
// Awaiting this later help make sure invoices should arrive in order
tasks.Add(SaveEvent(invoice.Id, e));
tasks.Add(SaveEvent(invoice.Id, e, InvoiceEventData.EventSeverity.Info));
// we need to use the status in the event and not in the invoice. The invoice might now be in another status.
if (invoice.FullNotifications)
@ -337,26 +339,26 @@ namespace BTCPayServer.HostedServices
leases.Add(_EventAggregator.Subscribe<InvoiceDataChangedEvent>(async e =>
{
await SaveEvent(e.InvoiceId, e);
await SaveEvent(e.InvoiceId, e, InvoiceEventData.EventSeverity.Info);
}));
leases.Add(_EventAggregator.Subscribe<InvoiceStopWatchedEvent>(async e =>
{
await SaveEvent(e.InvoiceId, e);
await SaveEvent(e.InvoiceId, e, InvoiceEventData.EventSeverity.Info);
}));
leases.Add(_EventAggregator.Subscribe<InvoiceIPNEvent>(async e =>
{
await SaveEvent(e.InvoiceId, e);
await SaveEvent(e.InvoiceId, e, string.IsNullOrEmpty(e.Error)? InvoiceEventData.EventSeverity.Success: InvoiceEventData.EventSeverity.Error);
}));
return Task.CompletedTask;
}
private Task SaveEvent(string invoiceId, object evt)
private Task SaveEvent(string invoiceId, object evt, InvoiceEventData.EventSeverity severity)
{
return _InvoiceRepository.AddInvoiceEvent(invoiceId, evt);
return _InvoiceRepository.AddInvoiceEvent(invoiceId, evt, severity);
}
public Task StopAsync(CancellationToken cancellationToken)

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BTCPayServer.Data;
namespace BTCPayServer.Logging
{
@ -8,20 +9,21 @@ namespace BTCPayServer.Logging
{
public DateTimeOffset Timestamp { get; set; }
public string Log { get; set; }
public InvoiceEventData.EventSeverity Severity { get; set; }
public override string ToString()
{
return $"{Timestamp.UtcDateTime}: {Log}";
return $"{Timestamp.UtcDateTime}:{Severity} {Log}";
}
}
public class InvoiceLogs
{
readonly List<InvoiceLog> _InvoiceLogs = new List<InvoiceLog>();
public void Write(string data)
public void Write(string data, InvoiceEventData.EventSeverity eventSeverity)
{
lock (_InvoiceLogs)
{
_InvoiceLogs.Add(new InvoiceLog() { Timestamp = DateTimeOffset.UtcNow, Log = data });
_InvoiceLogs.Add(new InvoiceLog() { Timestamp = DateTimeOffset.UtcNow, Log = data, Severity = eventSeverity});
}
}
@ -54,11 +56,11 @@ namespace BTCPayServer.Logging
var timespan = DateTimeOffset.UtcNow - _Before;
if (timespan.TotalSeconds >= 1.0)
{
_logs.Write($"{_msg} took {(int)timespan.TotalSeconds} seconds");
_logs.Write($"{_msg} took {(int)timespan.TotalSeconds} seconds", InvoiceEventData.EventSeverity.Info);
}
else
{
_logs.Write($"{_msg} took {(int)timespan.TotalMilliseconds} milliseconds");
_logs.Write($"{_msg} took {(int)timespan.TotalMilliseconds} milliseconds", InvoiceEventData.EventSeverity.Info);
}
}
}

View file

@ -171,11 +171,11 @@ namespace BTCPayServer.Payments.Bitcoin
?.CanSupportTransactionCheck is true;
onchainMethod.PayjoinEnabled &= supportedPaymentMethod.IsHotWallet && nodeSupport;
if (!supportedPaymentMethod.IsHotWallet)
logs.Write($"{prefix} Payjoin should have been enabled, but your store is not a hotwallet");
logs.Write($"{prefix} Payjoin should have been enabled, but your store is not a hotwallet", InvoiceEventData.EventSeverity.Warning);
if (!nodeSupport)
logs.Write($"{prefix} Payjoin should have been enabled, but your version of NBXplorer or full node does not support it.");
logs.Write($"{prefix} Payjoin should have been enabled, but your version of NBXplorer or full node does not support it.", InvoiceEventData.EventSeverity.Warning);
if (onchainMethod.PayjoinEnabled)
logs.Write($"{prefix} Payjoin is enabled for this invoice.");
logs.Write($"{prefix} Payjoin is enabled for this invoice.", InvoiceEventData.EventSeverity.Info);
}
return onchainMethod;

View file

@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Data;
using BTCPayServer.Events;
using BTCPayServer.Filters;
using BTCPayServer.HostedServices;
@ -141,7 +142,7 @@ namespace BTCPayServer.Payments.PayJoin
await using var ctx = new PayjoinReceiverContext(_invoiceRepository, _explorerClientProvider.GetExplorerClient(network), _payJoinRepository);
ObjectResult CreatePayjoinErrorAndLog(int httpCode, PayjoinReceiverWellknownErrors err, string debug)
{
ctx.Logs.Write($"Payjoin error: {debug}");
ctx.Logs.Write($"Payjoin error: {debug}", InvoiceEventData.EventSeverity.Error);
return StatusCode(httpCode, CreatePayjoinError(err, debug));
}
var explorer = _explorerClientProvider.GetExplorerClient(network);

View file

@ -218,20 +218,19 @@ retry:
public async Task AddInvoiceLogs(string invoiceId, InvoiceLogs logs)
{
using (var context = _ContextFactory.CreateContext())
await using var context = _ContextFactory.CreateContext();
foreach (var log in logs.ToList())
{
foreach (var log in logs.ToList())
await context.InvoiceEvents.AddAsync(new InvoiceEventData()
{
context.InvoiceEvents.Add(new InvoiceEventData()
{
InvoiceDataId = invoiceId,
Message = log.Log,
Timestamp = log.Timestamp,
UniqueId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(10))
});
}
await context.SaveChangesAsync().ConfigureAwait(false);
Severity = log.Severity,
InvoiceDataId = invoiceId,
Message = log.Log,
Timestamp = log.Timestamp,
UniqueId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(10))
});
}
await context.SaveChangesAsync().ConfigureAwait(false);
}
private string GetDestination(PaymentMethod paymentMethod)
@ -325,23 +324,22 @@ retry:
}
}
public async Task AddInvoiceEvent(string invoiceId, object evt)
public async Task AddInvoiceEvent(string invoiceId, object evt, InvoiceEventData.EventSeverity severity)
{
using (var context = _ContextFactory.CreateContext())
await using var context = _ContextFactory.CreateContext();
await context.InvoiceEvents.AddAsync(new InvoiceEventData()
{
context.InvoiceEvents.Add(new InvoiceEventData()
{
InvoiceDataId = invoiceId,
Message = evt.ToString(),
Timestamp = DateTimeOffset.UtcNow,
UniqueId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(10))
});
try
{
await context.SaveChangesAsync();
}
catch (DbUpdateException) { } // Probably the invoice does not exists anymore
Severity = severity,
InvoiceDataId = invoiceId,
Message = evt.ToString(),
Timestamp = DateTimeOffset.UtcNow,
UniqueId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(10))
});
try
{
await context.SaveChangesAsync();
}
catch (DbUpdateException) { } // Probably the invoice does not exists anymore
}
private static void MarkUnassigned(string invoiceId, InvoiceEntity entity, ApplicationDbContext context, PaymentMethodId paymentMethodId)

View file

@ -221,7 +221,7 @@
<tbody>
@foreach (var evt in Model.Events)
{
<tr>
<tr class="alert alert-@evt.GetCssClass()">
<td>@evt.Timestamp.ToBrowserDate()</td>
<td>@evt.Message</td>
</tr>