debug
- debug - Sends a log message to the debug websocket and waits for a response.
- debugLog - Alternative method for sending debug log messages to the debug system.
- openDebugBrowser - Requests to open a debug browser at the specified URL and port.
Quick Start Guide
The debug module provides comprehensive debugging capabilities for your Codebolt applications, including logging, browser debugging, and development tools.
Basic Usage
import codebolt from '@codebolt/codeboltjs';
// Log different types of messages
await codebolt.debug.debug('Application started successfully', 'info');
await codebolt.debug.debug('API rate limit approaching', 'warning');
await codebolt.debug.debug('Database connection failed', 'error');
// Open debug browser for development
await codebolt.debug.openDebugBrowser('http://localhost:3000', 9222);
Common Workflows
Workflow 1: Structured Logging
class DebugLogger {
constructor(context) {
this.context = context;
}
async info(message, data = {}) {
const logMessage = this.formatMessage('INFO', message, data);
await codebolt.debug.debug(logMessage, 'info');
}
async warning(message, data = {}) {
const logMessage = this.formatMessage('WARN', message, data);
await codebolt.debug.debug(logMessage, 'warning');
}
async error(message, error = null, data = {}) {
const logData = {
...data,
error: error ? {
message: error.message,
stack: error.stack,
name: error.name
} : null
};
const logMessage = this.formatMessage('ERROR', message, logData);
await codebolt.debug.debug(logMessage, 'error');
}
formatMessage(level, message, data) {
const timestamp = new Date().toISOString();
const dataStr = Object.keys(data).length > 0 ? `\n${JSON.stringify(data, null, 2)}` : '';
return `[${timestamp}] [${this.context}] [${level}] ${message}${dataStr}`;
}
async logFunctionCall(fnName, args) {
await this.info(`Calling function: ${fnName}`, { args });
}
async logFunctionResult(fnName, result, duration) {
await this.info(`Function completed: ${fnName}`, {
result: typeof result === 'object' ? JSON.stringify(result) : result,
duration: `${duration}ms`
});
}
async logAsyncFunction(fnName, fn) {
const startTime = Date.now();
await this.logFunctionCall(fnName);
try {
const result = await fn();
const duration = Date.now() - startTime;
await this.logFunctionResult(fnName, result, duration);
return result;
} catch (error) {
const duration = Date.now() - startTime;
await this.error(`Function failed: ${fnName}`, error, { duration });
throw error;
}
}
}
// Usage
const logger = new DebugLogger('UserService');
await logger.info('User login attempt', { userId: 'user_123' });
await logger.warning('High memory usage', { usage: '85%' });
await logger.error('Database error', new Error('Connection timeout'), { timeout: 5000 });
// Track async functions
const result = await logger.logAsyncFunction('fetchUserData', async () => {
return await fetchUserFromAPI('user_123');
});
Workflow 2: Performance Profiling
class PerformanceProfiler {
constructor() {
this.marks = new Map();
this.measures = [];
}
async mark(name) {
const timestamp = Date.now();
this.marks.set(name, timestamp);
await codebolt.debug.debug(`Mark: ${name}`, 'info');
return timestamp;
}
async measure(name, startMark, endMark) {
const start = this.marks.get(startMark);
const end = this.marks.get(endMark);
if (!start || !end) {
throw new Error(`Marks not found: ${startMark}, ${endMark}`);
}
const duration = end - start;
this.measures.push({ name, duration, start, end });
await codebolt.debug.debug(
`Measure ${name}: ${duration}ms`,
'info'
);
return duration;
}
async profileFunction(name, fn) {
const markName = `fn_${name}_${Date.now()}`;
await this.mark(markName);
try {
const result = await fn();
const duration = Date.now() - this.marks.get(markName);
await codebolt.debug.debug(
`Function ${name} completed in ${duration}ms`,
'info'
);
return result;
} catch (error) {
await codebolt.debug.debug(
`Function ${name} failed`,
'error'
);
throw error;
}
}
async getReport() {
const report = {
totalMeasures: this.measures.length,
averageDuration: 0,
slowest: null,
fastest: null,
measures: this.measures
};
if (this.measures.length > 0) {
const durations = this.measures.map(m => m.duration);
report.averageDuration = durations.reduce((a, b) => a + b) / durations.length;
report.slowest = this.measures.reduce((a, b) => a.duration > b.duration ? a : b);
report.fastest = this.measures.reduce((a, b) => a.duration < b.duration ? a : b);
}
return report;
}
async logReport() {
const report = await this.getReport();
await codebolt.debug.debug(
`Performance Report:\n${JSON.stringify(report, null, 2)}`,
'info'
);
return report;
}
}
// Usage
const profiler = new PerformanceProfiler();
await profiler.mark('request_start');
await processUserRequest();
await profiler.mark('request_end');
const duration = await profiler.measure('total_request', 'request_start', 'request_end');
// Profile a function
const result = await profiler.profileFunction('database_query', async () => {
return await db.query('SELECT * FROM users');
});
// Get performance report
await profiler.logReport();
Workflow 3: Debug Session Manager
class DebugSession {
constructor() {
this.breakpoints = new Map();
this.watchExpressions = new Map();
this.callStack = [];
}
async setBreakpoint(file, line, condition = null) {
const bp = { file, line, condition, hits: 0 };
this.breakpoints.set(`${file}:${line}`, bp);
await codebolt.debug.debug(
`Breakpoint set at ${file}:${line}`,
'info'
);
}
async addWatch(expression, evalFn) {
this.watchExpressions.set(expression, evalFn);
await codebolt.debug.debug(
`Watch added: ${expression}`,
'info'
);
}
async evaluateWatches(context) {
const results = {};
for (const [expr, evalFn] of this.watchExpressions) {
try {
results[expr] = await evalFn(context);
} catch (error) {
results[expr] = `Error: ${error.message}`;
}
}
await codebolt.debug.debug(
`Watch expressions:\n${JSON.stringify(results, null, 2)}`,
'info'
);
return results;
}
async enterFunction(name, args) {
this.callStack.push({ name, args, timestamp: Date.now() });
await codebolt.debug.debug(
`Entering: ${name}`,
'info'
);
}
async exitFunction(name, result) {
const frame = this.callStack.pop();
if (frame.name !== name) {
await codebolt.debug.debug(
`Warning: Mismatch exit. Expected ${frame.name}, got ${name}`,
'warning'
);
}
await codebolt.debug.debug(
`Exiting: ${name}`,
'info'
);
}
async getStackTrace() {
return this.callStack.map((frame, index) => ({
depth: this.callStack.length - index,
function: frame.name,
args: frame.args,
timestamp: new Date(frame.timestamp).toISOString()
}));
}
async logStackTrace() {
const stack = await this.getStackTrace();
await codebolt.debug.debug(
`Call stack:\n${JSON.stringify(stack, null, 2)}`,
'info'
);
}
}
// Usage
const session = new DebugSession();
await session.setBreakpoint('UserService.js', 42, 'userId === "admin"');
await session.addWatch('user.role', (ctx) => ctx.user?.role);
await session.addWatch('request.headers', (ctx) => ctx.request?.headers);
await session.enterFunction('processRequest', { userId: 'user_123' });
await processUserRequest();
await session.exitFunction('processRequest', { success: true });
await session.logStackTrace();
Workflow 4: Debug Browser Integration
class BrowserDebugSession {
constructor() {
this.sessions = new Map();
this.activeSession = null;
}
async start(url, port = 9222) {
const result = await codebolt.debug.openDebugBrowser(url, port);
if (result.success) {
const session = {
url,
port,
startTime: new Date().toISOString(),
status: 'active'
};
this.sessions.set(port, session);
this.activeSession = port;
await codebolt.debug.debug(
`Debug browser started at ${url}:${port}`,
'info'
);
return session;
} else {
throw new Error(`Failed to start debug browser: ${result.error}`);
}
}
async stop(port) {
const session = this.sessions.get(port);
if (!session) {
throw new Error(`No session found on port ${port}`);
}
// Stop the debug browser
this.sessions.delete(port);
if (this.activeSession === port) {
this.activeSession = null;
}
await codebolt.debug.debug(
`Debug browser stopped on port ${port}`,
'info'
);
}
async listSessions() {
return Array.from(this.sessions.entries()).map(([port, session]) => ({
port,
...session
}));
}
async getActiveSession() {
if (!this.activeSession) {
return null;
}
return this.sessions.get(this.activeSession);
}
async logPageAction(action, details) {
await codebolt.debug.debug(
`Page action: ${action}`,
'info'
);
await codebolt.debug.debug(
`Details: ${JSON.stringify(details, null, 2)}`,
'info'
);
}
async logNetworkRequest(request) {
await codebolt.debug.debug(
`Network request: ${request.method} ${request.url}`,
'info'
);
if (request.status >= 400) {
await codebolt.debug.debug(
`Request failed with status ${request.status}`,
'warning'
);
}
}
async logConsoleMessage(level, message) {
const logType = level === 'error' ? 'error' : level === 'warn' ? 'warning' : 'info';
await codebolt.debug.debug(message, logType);
}
}
// Usage
const browser = new BrowserDebugSession();
// Start debug session
await browser.start('http://localhost:3000', 9222);
// Log page interactions
await browser.logPageAction('click', { element: 'button#submit', x: 100, y: 200 });
// Log network activity
await browser.logNetworkRequest({
method: 'GET',
url: '/api/users',
status: 200,
duration: 150
});
// List all active sessions
const sessions = await browser.listSessions();
console.log('Active debug sessions:', sessions);
Module Integration Examples
Integration with State Module
async function debugStateChanges() {
const initialState = await codebolt.cbstate.getAgentState();
// Perform state changes
await codebolt.cbstate.addToAgentState('test_key', 'test_value');
const newState = await codebolt.cbstate.getAgentState();
// Log state changes
await codebolt.debug.debug(
`State changed:\nBefore: ${JSON.stringify(initialState.payload)}\nAfter: ${JSON.stringify(newState.payload)}`,
'info'
);
}
Integration with Memory Module
async function debugMemoryOperations() {
// Log memory write
await codebolt.debug.debug('Writing to memory', 'info');
await codebolt.dbmemory.addKnowledge('test:key', { data: 'test' });
// Log memory read
await codebolt.debug.debug('Reading from memory', 'info');
const result = await codebolt.dbmemory.getKnowledge('test:key');
// Log result
await codebolt.debug.debug(
`Memory result: ${JSON.stringify(result)}`,
'info'
);
}
Integration with History Module
async function debugConversationFlow() {
const summary = await codebolt.history.summarizeAll();
await codebolt.debug.debug(
`Conversation flow:\n${JSON.stringify(summary, null, 2)}`,
'info'
);
// Analyze conversation patterns
const userMessages = summary.filter(m => m.role === 'user');
const assistantMessages = summary.filter(m => m.role === 'assistant');
await codebolt.debug.debug(
`User messages: ${userMessages.length}, Assistant messages: ${assistantMessages.length}`,
'info'
);
}
Best Practices
1. Use Appropriate Log Levels
// ✅ Good: Use appropriate log levels
await codebolt.debug.debug('Application started', 'info');
await codebolt.debug.debug('High memory usage detected', 'warning');
await codebolt.debug.debug('Database connection failed', 'error');
// ❌ Bad: Always using 'info'
await codebolt.debug.debug('Application started', 'info');
await codebolt.debug.debug('High memory usage detected', 'info');
await codebolt.debug.debug('Database connection failed', 'info');
2. Include Context in Logs
// ✅ Good: Include context
await codebolt.debug.debug(
`User login failed for ${userId} from ${ipAddress}`,
'warning'
);
// ❌ Bad: Vague message
await codebolt.debug.debug(
'Login failed',
'warning'
);
3. Use Structured Logging
// ✅ Good: Structured data
await codebolt.debug.debug(
`API request completed: ${JSON.stringify({ endpoint, status, duration })}`,
'info'
);
// ❌ Bad: Unstructured string
await codebolt.debug.debug(
`API request to ${endpoint} completed with status ${status} in ${duration}ms`,
'info'
);
4. Log Errors with Details
// ✅ Good: Include error details
try {
await riskyOperation();
} catch (error) {
await codebolt.debug.debug(
`Operation failed: ${error.message}\nStack: ${error.stack}`,
'error'
);
}
// ❌ Bad: Vague error message
try {
await riskyOperation();
} catch (error) {
await codebolt.debug.debug('Operation failed', 'error');
}
Performance Considerations
Avoid Excessive Logging
// ❌ Bad: Logging in tight loop
for (let i = 0; i < 10000; i++) {
await codebolt.debug.debug(`Processing item ${i}`, 'info');
}
// ✅ Good: Log summary
for (let i = 0; i < 10000; i++) {
processItem(i);
}
await codebolt.debug.debug('Processed 10000 items', 'info');
Use Conditional Logging
class SmartLogger {
constructor() {
this.enabled = true;
this.level = 'info';
}
async debug(message, type) {
if (!this.enabled) return;
const levels = ['info', 'warning', 'error'];
const currentLevel = levels.indexOf(this.level);
const messageLevel = levels.indexOf(type);
if (messageLevel >= currentLevel) {
await codebolt.debug.debug(message, type);
}
}
}
Common Pitfalls
Pitfall 1: Logging Sensitive Data
// ❌ Problem: Logging passwords
await codebolt.debug.debug(`User login: ${username}:${password}`, 'info');
// ✅ Solution: Redact sensitive data
await codebolt.debug.debug(`User login: ${username}:***`, 'info');
Pitfall 2: Not Handling Debug Failures
// ❌ Problem: Debug failures crash app
await codebolt.debug.debug(message, 'info'); // May throw
// ✅ Solution: Handle debug errors
try {
await codebolt.debug.debug(message, 'info');
} catch (error) {
console.error('Debug logging failed:', error);
// Continue execution
}
Pitfall 3: Over-logging
// ❌ Problem: Too much noise
await codebolt.debug.debug('Starting operation', 'info');
await codebolt.debug.debug('Step 1 complete', 'info');
await codebolt.debug.debug('Step 2 complete', 'info');
await codebolt.debug.debug('Step 3 complete', 'info');
await codebolt.debug.debug('Operation complete', 'info');
// ✅ Solution: Log key milestones
await codebolt.debug.debug('Starting operation', 'info');
await codebolt.debug.debug('Operation complete', 'info');
Pitfall 4: Not Cleaning Up Debug Sessions
// ❌ Problem: Debug sessions left open
await codebolt.debug.openDebugBrowser('http://localhost:3000', 9222);
// Forget to close
// ✅ Solution: Always clean up
const session = await codebolt.debug.openDebugBrowser('http://localhost:3000', 9222);
try {
await doDebugWork();
} finally {
await cleanupDebugSession(session);
}