Monitoring and logging
This page shows what you can observe in a running libspiffy node and how to wire it into your own logging and metrics. libspiffy 5.0.0 does not collect or export metrics itself. It gives you three things to build on: log records, coordinator events, and a few status getters.
Logging
Section titled “Logging”libspiffy logs through package:logging. Nothing is printed
until you listen to the root logger:
import 'package:logging/logging.dart';
void setUpLogging() { Logger.root.level = Level.INFO; Logger.root.onRecord.listen((r) { print('${r.time.toIso8601String()} ${r.level.name} ${r.loggerName}: ${r.message}' '${r.error != null ? ' ${r.error}' : ''}'); });}Each component logs under its own name. The names are flat, not dotted, so filter on
record.loggerName. Useful ones:
| Logger name | What it reports |
|---|---|
LibSpiffyActorSystem |
Start-up, the P2P network chosen, peer redials, shutdown, a missing secureStorage (SEVERE) |
ARCActor, SubmissionWatcherActor |
Broadcasts, status scans, the retry queue |
HeaderSyncActor, BlockHeaderChain, SpiffyNodeBridge, LibSpiffyPeerHandler, LibSpiffy-SpiffyNode |
P2P header sync and peers |
CdnHeaderSyncService, LibSpiffy-CDNSync |
CDN header sync |
SPVActor |
Proof and BEEF validation |
WalletCoordinatorActor, WalletManagerActor, BitcoinWalletAggregate |
Commands and the wallet aggregate |
PaymentCoordinatorActor, InvoiceCoordinatorActor, PaymentChannelManagerActor |
Payments, invoices, channels |
ImportActor, TransactionImportService, WhatsOnChainDataSource |
Wallet import and the data source |
PostgresEventStore, PostgresWalletStorage |
PostgreSQL storage |
A SEVERE record from LibSpiffyActorSystem saying no secureStorage was supplied means your keys
are in memory only. Alert on it.
Coordinator events to watch
Section titled “Coordinator events to watch”Subscribe to libspiffy.coordinatorEvents, or to one kind with libspiffy.coordinator.on<E>(),
and count or alert on these. Fields are listed in Events.
| Event | When | What to do with it |
|---|---|---|
ErrorEvent |
Something failed that has no reply of its own to report it in. Carries walletId, source, message, stackTrace, and requestId when a request caused it. |
Count by source; alert on spikes. |
BroadcastFailureEvent |
ARC refused or could not take a broadcast. Carries txid, error, willRetry. |
Count; a rising rate means ARC is refusing or unreachable. |
TransactionConfirmedEvent |
A merkle proof put a wallet’s transaction in a block on the active chain (txid, blockHeight). |
Time from send to confirmation. |
TransactionConfirmationRevertedEvent |
A confirmation was taken back by a reorganization or a contradicting header (reason). |
Alert: anything you did on the confirmation lost its evidence. |
BlockHeadersStoredEvent |
Each batch of headers stored (headersStored, startHeight, endHeight, success, error, source). |
Header sync throughput; alert on success == false. |
HeaderSyncStatusEvent |
Header sync caught up with its peers, or fell behind them. Carries a HeaderSyncStatus. |
Gauge of sync state. |
WalletStatusEvent |
The coordinator shut down (status 'shutdown', message). |
Lifecycle log. |
// Sketch: count failures by source with your own metrics client.libspiffy.coordinatorEvents?.listen((event) { switch (event) { case ErrorEvent(:final source, :final message): metrics.increment('libspiffy.error', tags: {'source': source}); log.warning('$source: $message'); case BroadcastFailureEvent(:final willRetry): metrics.increment('libspiffy.broadcast_failure', tags: {'retry': '$willRetry'}); case HeaderSyncStatusEvent(:final status): metrics.gauge('libspiffy.header_height', status.height); metrics.gauge('libspiffy.peers', status.peerCount); default: break; }});metrics and log stand for your own clients; they are not part of libspiffy.
Header sync status
Section titled “Header sync status”HeaderSyncStatus has four fields:
| Field | Meaning |
|---|---|
height |
Height of the active chain’s tip. |
networkHeight |
The higher of height and what the connected peers reported in their handshake; 0 while no peer reported one. For showing progress. |
synced |
Whether the last answer a peer gave held fewer than a full batch (2,000) of headers. The verdict on “caught up”. |
peerCount |
Peers connected now. 0 means nothing is syncing. |
Ask for it at any time with GetHeaderSyncStatusQuery. ask() completes with its
HeaderSyncStatusResponse:
final response = await libspiffy.coordinator.ask(GetHeaderSyncStatusQuery());final status = response.status;print('${status.height}/${status.networkHeight}, synced: ${status.synced}');A request that fails makes ask() throw CoordinatorFailure, and one with no reply within its
timeout (one minute for this query) throws TimeoutException. Count both if you poll the status
from a health check.
CDN header sync callbacks
Section titled “CDN header sync callbacks”On first start, initialize() can import headers from a CDN. Its two callbacks are the only way to
watch that phase:
onHeaderSyncProgress: (int current, int total, CdnSyncPhase phase) { ... }onHeaderSyncResult: (CdnSyncResult result) { ... }withsuccess,headersImported,finalHeight,elapsedanderror.
See CDN header sync.
Status getters
Section titled “Status getters”On LibSpiffyActorSystem:
| Getter | Meaning |
|---|---|
isReady / ready |
The actors take commands. Completes before header sync is done. |
isInitialized |
The system is up and not shut down. |
networkHeight |
The network’s tip as best known: the higher of peers’ reports and the local chain; 0 while no peer is connected. |
headerChain.bestHeight |
The height of the local header chain. |
A readiness probe for a server can combine isReady with HeaderSyncStatus.synced and
peerCount > 0.
What libspiffy does not measure
Section titled “What libspiffy does not measure”There are no built-in counters, timers or exporters for message rates, actor memory, ARC response times, invoice rates or proof validation rates. If you need them, derive them from the events and log records above, or time your own calls.