mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 22:25:28 +01:00
Merge pull request #1872 from Kukks/invoie-severity
Add invoice event severity
This commit is contained in:
commit
85d393fec3
10 changed files with 110 additions and 51 deletions
|
@ -20,6 +20,7 @@ namespace BTCPayServer.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
|
public EventSeverity Severity { get; set; } = EventSeverity.Info;
|
||||||
|
|
||||||
internal static void OnModelCreating(ModelBuilder builder)
|
internal static void OnModelCreating(ModelBuilder builder)
|
||||||
{
|
{
|
||||||
|
@ -35,5 +36,25 @@ namespace BTCPayServer.Data
|
||||||
#pragma warning restore CS0618
|
#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
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -240,6 +240,9 @@ namespace BTCPayServer.Migrations
|
||||||
b.Property<string>("Message")
|
b.Property<string>("Message")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Severity")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<DateTimeOffset>("Timestamp")
|
b.Property<DateTimeOffset>("Timestamp")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ namespace BTCPayServer.Controllers
|
||||||
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter invoicePaymentMethodFilter, CancellationToken cancellationToken = default)
|
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter invoicePaymentMethodFilter, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
InvoiceLogs logs = new InvoiceLogs();
|
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 getAppsTaggingStore = _InvoiceRepository.GetAppsTaggingStore(store.Id);
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
|
@ -273,7 +273,7 @@ namespace BTCPayServer.Controllers
|
||||||
}
|
}
|
||||||
catch (AggregateException ex)
|
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);
|
await _InvoiceRepository.AddInvoiceLogs(entity.Id, logs);
|
||||||
});
|
});
|
||||||
|
@ -286,16 +286,16 @@ namespace BTCPayServer.Controllers
|
||||||
return Task.WhenAll(fetchingByCurrencyPair.Select(async pair =>
|
return Task.WhenAll(fetchingByCurrencyPair.Select(async pair =>
|
||||||
{
|
{
|
||||||
var rateResult = await pair.Value;
|
var rateResult = await pair.Value;
|
||||||
logs.Write($"{pair.Key}: The rating rule is {rateResult.Rule}");
|
logs.Write($"{pair.Key}: The rating rule is {rateResult.Rule}", InvoiceEventData.EventSeverity.Info);
|
||||||
logs.Write($"{pair.Key}: The evaluated rating rule is {rateResult.EvaluatedRule}");
|
logs.Write($"{pair.Key}: The evaluated rating rule is {rateResult.EvaluatedRule}", InvoiceEventData.EventSeverity.Info);
|
||||||
if (rateResult.Errors.Count != 0)
|
if (rateResult.Errors.Count != 0)
|
||||||
{
|
{
|
||||||
var allRateRuleErrors = string.Join(", ", rateResult.Errors.ToArray());
|
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)
|
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());
|
}).ToArray());
|
||||||
}
|
}
|
||||||
|
@ -331,7 +331,7 @@ namespace BTCPayServer.Controllers
|
||||||
paymentMethod.Calculate().Due, supportedPaymentMethod.PaymentId);
|
paymentMethod.Calculate().Due, supportedPaymentMethod.PaymentId);
|
||||||
if (!string.IsNullOrEmpty(errorMessage))
|
if (!string.IsNullOrEmpty(errorMessage))
|
||||||
{
|
{
|
||||||
logs.Write($"{logPrefix} {errorMessage}");
|
logs.Write($"{logPrefix} {errorMessage}", InvoiceEventData.EventSeverity.Error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,11 +348,11 @@ namespace BTCPayServer.Controllers
|
||||||
}
|
}
|
||||||
catch (PaymentMethodUnavailableException ex)
|
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)
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@ using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Client.Models;
|
using BTCPayServer.Client.Models;
|
||||||
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Events;
|
using BTCPayServer.Events;
|
||||||
|
using BTCPayServer.Logging;
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Services;
|
using BTCPayServer.Services;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
|
@ -306,7 +308,7 @@ namespace BTCPayServer.HostedServices
|
||||||
List<Task> tasks = new List<Task>();
|
List<Task> tasks = new List<Task>();
|
||||||
|
|
||||||
// Awaiting this later help make sure invoices should arrive in order
|
// 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.
|
// 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)
|
if (invoice.FullNotifications)
|
||||||
|
@ -337,26 +339,26 @@ namespace BTCPayServer.HostedServices
|
||||||
|
|
||||||
leases.Add(_EventAggregator.Subscribe<InvoiceDataChangedEvent>(async e =>
|
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 =>
|
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 =>
|
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;
|
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)
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using BTCPayServer.Data;
|
||||||
|
|
||||||
namespace BTCPayServer.Logging
|
namespace BTCPayServer.Logging
|
||||||
{
|
{
|
||||||
|
@ -8,20 +9,21 @@ namespace BTCPayServer.Logging
|
||||||
{
|
{
|
||||||
public DateTimeOffset Timestamp { get; set; }
|
public DateTimeOffset Timestamp { get; set; }
|
||||||
public string Log { get; set; }
|
public string Log { get; set; }
|
||||||
|
public InvoiceEventData.EventSeverity Severity { get; set; }
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{Timestamp.UtcDateTime}: {Log}";
|
return $"{Timestamp.UtcDateTime}:{Severity} {Log}";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public class InvoiceLogs
|
public class InvoiceLogs
|
||||||
{
|
{
|
||||||
readonly List<InvoiceLog> _InvoiceLogs = new List<InvoiceLog>();
|
readonly List<InvoiceLog> _InvoiceLogs = new List<InvoiceLog>();
|
||||||
public void Write(string data)
|
public void Write(string data, InvoiceEventData.EventSeverity eventSeverity)
|
||||||
{
|
{
|
||||||
lock (_InvoiceLogs)
|
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;
|
var timespan = DateTimeOffset.UtcNow - _Before;
|
||||||
if (timespan.TotalSeconds >= 1.0)
|
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
|
else
|
||||||
{
|
{
|
||||||
_logs.Write($"{_msg} took {(int)timespan.TotalMilliseconds} milliseconds");
|
_logs.Write($"{_msg} took {(int)timespan.TotalMilliseconds} milliseconds", InvoiceEventData.EventSeverity.Info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,11 +171,11 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||||
?.CanSupportTransactionCheck is true;
|
?.CanSupportTransactionCheck is true;
|
||||||
onchainMethod.PayjoinEnabled &= supportedPaymentMethod.IsHotWallet && nodeSupport;
|
onchainMethod.PayjoinEnabled &= supportedPaymentMethod.IsHotWallet && nodeSupport;
|
||||||
if (!supportedPaymentMethod.IsHotWallet)
|
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)
|
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)
|
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;
|
return onchainMethod;
|
||||||
|
|
|
@ -5,6 +5,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Events;
|
using BTCPayServer.Events;
|
||||||
using BTCPayServer.Filters;
|
using BTCPayServer.Filters;
|
||||||
using BTCPayServer.HostedServices;
|
using BTCPayServer.HostedServices;
|
||||||
|
@ -141,7 +142,7 @@ namespace BTCPayServer.Payments.PayJoin
|
||||||
await using var ctx = new PayjoinReceiverContext(_invoiceRepository, _explorerClientProvider.GetExplorerClient(network), _payJoinRepository);
|
await using var ctx = new PayjoinReceiverContext(_invoiceRepository, _explorerClientProvider.GetExplorerClient(network), _payJoinRepository);
|
||||||
ObjectResult CreatePayjoinErrorAndLog(int httpCode, PayjoinReceiverWellknownErrors err, string debug)
|
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));
|
return StatusCode(httpCode, CreatePayjoinError(err, debug));
|
||||||
}
|
}
|
||||||
var explorer = _explorerClientProvider.GetExplorerClient(network);
|
var explorer = _explorerClientProvider.GetExplorerClient(network);
|
||||||
|
|
|
@ -218,20 +218,19 @@ retry:
|
||||||
|
|
||||||
public async Task AddInvoiceLogs(string invoiceId, InvoiceLogs logs)
|
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()
|
Severity = log.Severity,
|
||||||
{
|
InvoiceDataId = invoiceId,
|
||||||
InvoiceDataId = invoiceId,
|
Message = log.Log,
|
||||||
Message = log.Log,
|
Timestamp = log.Timestamp,
|
||||||
Timestamp = log.Timestamp,
|
UniqueId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(10))
|
||||||
UniqueId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(10))
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
await context.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
await context.SaveChangesAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetDestination(PaymentMethod paymentMethod)
|
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()
|
Severity = severity,
|
||||||
{
|
InvoiceDataId = invoiceId,
|
||||||
InvoiceDataId = invoiceId,
|
Message = evt.ToString(),
|
||||||
Message = evt.ToString(),
|
Timestamp = DateTimeOffset.UtcNow,
|
||||||
Timestamp = DateTimeOffset.UtcNow,
|
UniqueId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(10))
|
||||||
UniqueId = Encoders.Hex.EncodeData(RandomUtils.GetBytes(10))
|
});
|
||||||
});
|
try
|
||||||
try
|
{
|
||||||
{
|
await context.SaveChangesAsync();
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
catch (DbUpdateException) { } // Probably the invoice does not exists anymore
|
|
||||||
}
|
}
|
||||||
|
catch (DbUpdateException) { } // Probably the invoice does not exists anymore
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MarkUnassigned(string invoiceId, InvoiceEntity entity, ApplicationDbContext context, PaymentMethodId paymentMethodId)
|
private static void MarkUnassigned(string invoiceId, InvoiceEntity entity, ApplicationDbContext context, PaymentMethodId paymentMethodId)
|
||||||
|
|
|
@ -221,7 +221,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (var evt in Model.Events)
|
@foreach (var evt in Model.Events)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr class="alert alert-@evt.GetCssClass()">
|
||||||
<td>@evt.Timestamp.ToBrowserDate()</td>
|
<td>@evt.Timestamp.ToBrowserDate()</td>
|
||||||
<td>@evt.Message</td>
|
<td>@evt.Message</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
Loading…
Add table
Reference in a new issue