Debug Utilities
Debug utilities provide logging, tracing, and performance monitoring for development and troubleshooting.
Overview
import {
enableDebug,
disableDebug,
createDebugLogger,
traceTransaction,
withTiming,
debugWrap
} from 'cardano-devkit';
// Enable global debug mode
enableDebug({ level: 'debug', timestamps: true });
// Create a logger for your module
const logger = createDebugLogger('MyApp');
logger.info('Application started');
Debug Mode
enableDebug(config?)
Enable global debug mode with configuration.
import { enableDebug } from 'cardano-devkit';
enableDebug({
level: 'debug', // 'debug' | 'info' | 'warn' | 'error'
timestamps: true, // Include timestamps in output
colors: true, // Colorize output
outputFormat: 'text', // 'text' | 'json'
persist: false, // Persist logs to memory
});
disableDebug()
Disable global debug mode.
import { disableDebug } from 'cardano-devkit';
disableDebug();
DebugLogger
The DebugLogger class provides structured logging with levels and namespaces.
createDebugLogger(namespace)
Create a namespaced logger.
import { createDebugLogger } from 'cardano-devkit';
const logger = createDebugLogger('WalletService');
logger.debug('Fetching UTxOs...');
logger.info('Found 5 UTxOs');
logger.warn('Large transaction detected');
logger.error('Failed to submit transaction', { error: err });
DebugLogger Class
import { DebugLogger } from 'cardano-devkit';
const logger = new DebugLogger('MyModule', {
level: 'info',
timestamps: true,
});
// Basic logging
logger.debug('Debug message');
logger.info('Info message');
logger.warn('Warning message');
logger.error('Error message');
// With data
logger.info('Transaction built', { txHash, fee: '0.2 ADA' });
// Child loggers
const childLogger = logger.child('SubModule');
childLogger.info('Message from child'); // [MyModule:SubModule] Message from child
// Check if level is enabled
if (logger.isLevelEnabled('debug')) {
// Expensive debug computation
}
// Get all logs (if persist: true)
const logs = logger.getLogs();
// Clear logs
logger.clearLogs();
Log Levels
| Level | Priority | Use Case |
|---|---|---|
debug | 0 | Detailed debugging information |
info | 1 | General information messages |
warn | 2 | Warning conditions |
error | 3 | Error conditions |
Higher priority levels include all lower levels. Setting level to warn shows warn and error messages.
Transaction Tracing
Trace the complete lifecycle of a transaction through build, sign, submit, and confirm phases.
traceTransaction(lucid, buildFn)
Trace a transaction from build to confirmation.
import { traceTransaction, formatTrace } from 'cardano-devkit';
const { txHash, trace } = await traceTransaction(lucid, async (l) => {
const tx = await l.newTx()
.pay.ToAddress(recipient, { lovelace: 5_000_000n })
.complete();
const signed = await tx.sign.withWallet().complete();
return await signed.submit();
});
// Format and display trace
console.log(formatTrace(trace));
Output:
Transaction Trace
═══════════════════════════════════════════════════════════════
Phase: build
Started: 2024-01-15T10:30:00.000Z
Duration: 145ms
Status: completed
Phase: sign
Started: 2024-01-15T10:30:00.145Z
Duration: 52ms
Status: completed
Phase: submit
Started: 2024-01-15T10:30:00.197Z
Duration: 1203ms
Status: completed
Data: { txHash: "abc123..." }
Total Duration: 1400ms
═══════════════════════════════════════════════════════════════
TransactionTracer Class
For more control, use the TransactionTracer class directly.
import { TransactionTracer, formatTrace } from 'cardano-devkit';
const tracer = new TransactionTracer();
// Trace each phase
tracer.startPhase('build');
const tx = await lucid.newTx()
.pay.ToAddress(recipient, { lovelace: 5_000_000n })
.complete();
tracer.endPhase('build', { inputCount: 2, outputCount: 2 });
tracer.startPhase('sign');
const signed = await tx.sign.withWallet().complete();
tracer.endPhase('sign');
tracer.startPhase('submit');
const txHash = await signed.submit();
tracer.endPhase('submit', { txHash });
tracer.startPhase('confirm');
await lucid.awaitTx(txHash);
tracer.endPhase('confirm', { confirmed: true });
// Get trace
const trace = tracer.getTrace();
console.log(formatTrace(trace));
// Get timing breakdown
const timings = tracer.getTimings();
console.log('Build time:', timings.build, 'ms');
console.log('Sign time:', timings.sign, 'ms');
console.log('Submit time:', timings.submit, 'ms');
Transaction Phases
| Phase | Description |
|---|---|
build | Building the transaction |
sign | Signing with wallet |
submit | Submitting to network |
confirm | Waiting for confirmation |
custom | Custom user-defined phases |
Performance Utilities
withTiming(label, fn)
Wrap an async function with timing measurement.
import { withTiming } from 'cardano-devkit';
const { result, durationMs } = await withTiming('fetchUTxOs', async () => {
return await lucid.wallet().getUtxos();
});
console.log(`Fetched UTxOs in ${durationMs}ms`);
debugWrap(fn, options)
Wrap a function with debug logging for inputs and outputs.
import { debugWrap } from 'cardano-devkit';
const buildTx = debugWrap(
async (recipient: string, amount: bigint) => {
return await lucid.newTx()
.pay.ToAddress(recipient, { lovelace: amount })
.complete();
},
{
name: 'buildTx',
logInputs: true,
logOutputs: true,
logTiming: true,
}
);
// Automatically logs:
// [buildTx] Called with: ["addr_test1...", 5000000n]
// [buildTx] Completed in 145ms
// [buildTx] Returned: TxComplete { ... }
await buildTx(recipient, 5_000_000n);
Global Debug Instance
A global debug instance is available for quick debugging:
import { debug } from 'cardano-devkit';
// Use global logger
debug.log('Quick debug message');
debug.info('Info message');
debug.warn('Warning');
debug.error('Error', { context: 'additional data' });
// Enable/disable
debug.enable();
debug.disable();
// Check if enabled
if (debug.isEnabled()) {
debug.log('Debug is on');
}
Namespace Imports
All debug utilities are available via the Debug namespace:
import { Debug } from 'cardano-devkit/namespaces';
Debug.enable({ level: 'debug' });
const logger = Debug.createLogger('MyApp');
const tracer = Debug.createTracer();
const result = await Debug.withTiming('operation', async () => {
// ... operation
});
Debug.formatTrace(tracer.getTrace());
Best Practices
1. Use Namespaced Loggers
Create separate loggers for different parts of your application:
const walletLogger = createDebugLogger('Wallet');
const txLogger = createDebugLogger('Transaction');
const networkLogger = createDebugLogger('Network');
2. Structured Logging
Include relevant data with log messages:
logger.info('Transaction submitted', {
txHash,
fee: lovelaceToAda(fee),
network: 'Preprod',
});
3. Conditional Debug Code
Check if debug is enabled before expensive operations:
if (logger.isLevelEnabled('debug')) {
const utxoDetails = await formatUtxoDetails(utxos);
logger.debug('UTxO Details', utxoDetails);
}
4. Production Considerations
Disable debug in production or set level to 'error':
if (process.env.NODE_ENV === 'production') {
disableDebug();
} else {
enableDebug({ level: 'info' });
}
5. Trace Performance-Critical Paths
Use tracing for transaction workflows:
const { trace } = await traceTransaction(lucid, async (l) => {
// Critical transaction path
});
if (trace.totalDuration > 5000) {
logger.warn('Slow transaction detected', { trace });
}
TypeScript Types
import type {
LogLevel,
DebugConfig,
TransactionPhase,
TransactionTrace,
PhaseData,
PerformanceMetrics,
DebugLoggerOptions,
} from 'cardano-devkit';
Examples
Full Debug Setup
import {
enableDebug,
createDebugLogger,
traceTransaction,
formatTrace,
} from 'cardano-devkit';
// Enable debug mode
enableDebug({
level: 'debug',
timestamps: true,
persist: true,
});
// Create module logger
const logger = createDebugLogger('PaymentService');
async function sendPayment(recipient: string, amount: bigint) {
logger.info('Starting payment', { recipient, amount });
const { txHash, trace } = await traceTransaction(lucid, async (l) => {
logger.debug('Building transaction...');
const tx = await l.newTx()
.pay.ToAddress(recipient, { lovelace: amount })
.complete();
logger.debug('Signing transaction...');
const signed = await tx.sign.withWallet().complete();
logger.debug('Submitting transaction...');
return await signed.submit();
});
logger.info('Payment completed', {
txHash,
duration: `${trace.totalDuration}ms`,
});
// Log trace if slow
if (trace.totalDuration > 3000) {
logger.warn('Slow transaction', { trace: formatTrace(trace) });
}
return txHash;
}
Debugging Transaction Issues
import {
createDebugLogger,
TransactionTracer,
formatTrace,
} from 'cardano-devkit';
const logger = createDebugLogger('TxDebug');
const tracer = new TransactionTracer();
try {
tracer.startPhase('build');
logger.debug('Inputs:', { utxos: await lucid.wallet().getUtxos() });
const tx = await lucid.newTx()
.pay.ToAddress(recipient, { lovelace: amount })
.complete();
tracer.endPhase('build', {
fee: tx.toJSON(), // Log tx details
});
} catch (error) {
tracer.endPhase('build', { error: String(error) });
logger.error('Transaction build failed', {
error,
trace: formatTrace(tracer.getTrace()),
});
throw error;
}