mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-21 14:04:12 +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 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Severity")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset>("Timestamp")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue