Skip to main content

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

LevelPriorityUse Case
debug0Detailed debugging information
info1General information messages
warn2Warning conditions
error3Error 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

PhaseDescription
buildBuilding the transaction
signSigning with wallet
submitSubmitting to network
confirmWaiting for confirmation
customCustom 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;
}