Testing
Debugger
- Testing
Conceptos Fundamentales
¿Qué es un Debugger?
Herramienta de desarrollo que permite ejecutar código paso a paso, inspeccionar variables y analizar el flujo de ejecución para identificar y resolver errores.
Funcionamiento Básico
- Ejecución Controlada: Pausa la ejecución en puntos específicos
- Inspección de Estado: Acceso a variables y memoria en tiempo de ejecución
- Análisis de Flujo: Seguimiento del camino de ejecución del programa
Componentes del Debugger
Call Stack
- Seguimiento de Llamadas: Muestra la pila de ejecución de funciones/métodos
- Navegación Jerárquica: Permite ver qué función llamó a la actual
- Contexto de Ejecución: Cada frame muestra variables locales y parámetros
Breakpoints
- Puntos de Interrupción: Marcadores que pausan la ejecución
- Condicionales: Se activan solo cuando se cumple una condición específica
- Temporales: Se eliminan automáticamente después de activarse
Inspección de Variables
- Variables Locales: Valores en el contexto actual de ejecución
- Variables Globales: Estado del ámbito global
- Watch Expressions: Expresiones personalizadas para monitorear
Step Through
- Step Into: Entra en la función/método actual
- Step Over: Ejecuta la línea actual sin entrar en funciones
- Step Out: Sale de la función actual y continúa
- Continue: Reanuda la ejecución hasta el próximo breakpoint
Debugging en JavaScript
Herramientas Específicas
// Console debugging
console.log('Variable value:', variable);
console.table(arrayOfObjects);
console.trace('Execution trace');
// Debugger statement
function problematicFunction() {
debugger; // Pausa la ejecución si el debugger está abierto
// código problemático
}
Chrome DevTools
// Breakpoints avanzados
// - Line breakpoints
// - Conditional breakpoints
// - DOM breakpoints
// - Event listener breakpoints
// - XHR/fetch breakpoints
// Ejemplo de watch expressions
const user = { name: 'John', age: 30 };
// Watch: user.name
// Watch: JSON.stringify(user)
Node.js Debugging
# Iniciar con inspector
node --inspect app.js
node --inspect-brk app.js # Pausa al inicio
# Con nodemon para desarrollo
nodemon --inspect app.js
Diferencias entre Lenguajes
JavaScript vs Java
// Java debugging - más estructurado
public class DebugExample {
public static void main(String[] args) {
int result = calculate(5, 3);
System.out.println("Result: " + result);
}
public static int calculate(int a, int b) {
// Punto de interrupción tradicional
int sum = a + b;
return sum * 2;
}
}
Características Comparativas
- JavaScript: Dinámico, tipado débil, debugging en navegador y Node.js
- Java: Tipado fuerte, debugging con IDEs robustas (IntelliJ, Eclipse)
- Python: Debugging interactivo, tipado dinámico
- C++: Debugging a nivel de memoria, pointers, más complejo
Técnicas Avanzadas de Debugging
Conditional Breakpoints
// Solo se activa cuando se cumple la condición
function processUsers(users) {
for (let user of users) {
// Breakpoint condicional: user.age > 65
if (user.age > 65) {
processSenior(user);
}
}
}
Watch Expressions Avanzadas
const data = {
users: [
{ id: 1, active: true },
{ id: 2, active: false }
]
};
// Watch expressions útiles:
// data.users.filter(u => u.active).length
// data.users.map(u => u.id)
// JSON.stringify(data, null, 2)
Call Stack Analysis
function a() {
b();
}
function b() {
c();
}
function c() {
console.trace(); // Muestra call stack completo
throw new Error('Debug this!');
}
a();
Debugging en Diferentes Entornos
Frontend (Browser)
- Chrome DevTools: Console, Sources, Network tabs
- Firefox Developer Tools: Similar funcionalidad
- Browser Extensions: React DevTools, Vue DevTools
Backend (Node.js)
// Debugging remoto
const inspector = require('inspector');
inspector.open(9229, '0.0.0.0', true);
// Logging estructurado
const debug = require('debug')('app:server');
debug('Server started on port %d', 3000);
IDEs y Editores
- VS Code: Integrated debugger, launch configurations
- WebStorm: Debugger avanzado para JavaScript
- Eclipse/IntelliJ: Para Java y otros lenguajes
Configuraciones de Debugging
VS Code Launch Configuration
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/app.js",
"env": {
"NODE_ENV": "development"
}
}
]
}
Chrome DevTools Snippets
// Snippets para debugging común
// 1. Monitor de eventos
function monitorEvents(element, events) {
events.forEach(event => {
element.addEventListener(event, e => {
console.log(`Event: ${event}`, e);
});
});
}
// 2. Performance measurement
function measurePerf(fn, label = 'Function') {
console.time(label);
const result = fn();
console.timeEnd(label);
return result;
}
Estrategias de Debugging Efectivo
Metodología Sistemática
- Reproducir el Error: Condiciones consistentes
- Aislar el Problema: Divide y vencerás
- Hipótesis y Verificación: Plantea teorías y compruébalas
- Solución y Validación: Corrige y verifica la solución
Herramientas de Apoyo
- Source Maps: Debugging de código minificado/compilado
- Network Analysis: Debugging de peticiones HTTP
- Memory Profiling: Detección de memory leaks
- Performance Profiling: Identificación de cuellos de botella
Debugging Avanzado
Async/Await Debugging
async function fetchUserData(userId) {
try {
// Breakpoint aquí para ver el flujo async
const response = await fetch(`/users/${userId}`);
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch failed:', error);
debugger; // Pausa en errores async
}
}
Promise Debugging
function debugPromise(promise, label) {
return promise
.then(result => {
console.log(`✅ ${label}:`, result);
return result;
})
.catch(error => {
console.error(`❌ ${label}:`, error);
debugger;
throw error;
});
}
Error Tracking
// Global error handler para debugging
window.addEventListener('error', (event) => {
console.error('Global error:', event.error);
console.log('Stack trace:', event.error.stack);
// Enviar a servicio de tracking
});
Integración con Testing
Debugging en Tests
// Jest debugging
describe('User Service', () => {
test('should create user', async () => {
const user = { name: 'Test', email: 'test@example.com' };
debugger; // Pausa durante test execution
const result = await userService.create(user);
expect(result.id).toBeDefined();
});
});
Browser Automation Debugging
// Puppeteer/Playwright debugging
await page.pause(); // Pausa la ejecución del test
await page.evaluate(() => {
debugger; // Pausa en contexto del navegador
});
debugging en mas areas con ejemplos de codigo
Debugging de Memoria
Memory Leaks Detection
// Monitor memory usage
function monitorMemory() {
const used = process.memoryUsage();
console.log('Memory usage:');
for (let key in used) {
console.log(`${key}: ${Math.round(used[key] / 1024 / 1024)} MB`);
}
}
// Force garbage collection for testing
if (global.gc) {
global.gc();
}
Heap Snapshots Analysis
// Take heap snapshot in Node.js
const heapdump = require('heapdump');
function takeHeapSnapshot() {
heapdump.writeSnapshot('/tmp/' + Date.now() + '.heapsnapshot');
}
// Chrome DevTools heap profiling
console.profile('Memory Analysis');
// ... suspicious code
console.profileEnd('Memory Analysis');
Debugging de Performance
Performance Profiling
// High-resolution timing
function measurePerformance(fn, iterations = 1000) {
const start = performance.now();
for (let i = 0; i < iterations; i++) {
fn();
}
const end = performance.now();
console.log(`Average time: ${(end - start) / iterations}ms`);
}
// Function timing wrapper
function withTiming(fn, label = 'Function') {
return function(...args) {
console.time(label);
const result = fn.apply(this, args);
console.timeEnd(label);
return result;
};
}
CPU Profiling
// CPU profiling in Node.js
const profiler = require('v8-profiler-next');
const fs = require('fs');
const profile = profiler.startProfiling('CPU Profile');
setTimeout(() => {
profile.end().then(profile => {
fs.writeFileSync('profile.cpuprofile',
JSON.stringify(profile));
});
}, 5000);
Debugging de Red y APIs
Network Request Debugging
// Intercept fetch requests
const originalFetch = window.fetch;
window.fetch = function(...args) {
console.log('Fetch request:', args);
return originalFetch.apply(this, args)
.then(response => {
console.log('Fetch response:', response);
return response;
});
};
// Monitor XMLHttpRequest
const originalXHROpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
this.addEventListener('load', function() {
console.log(`XHR ${method} ${url}:`, this.response);
});
originalXHROpen.apply(this, arguments);
};
API Response Inspection
// Debug API responses with detailed info
async function debugApiCall(url, options = {}) {
console.group(`API Call: ${url}`);
console.log('Request options:', options);
try {
const startTime = Date.now();
const response = await fetch(url, options);
const duration = Date.now() - startTime;
console.log(`Status: ${response.status}`);
console.log(`Duration: ${duration}ms`);
console.log('Headers:', Object.fromEntries(response.headers));
const data = await response.json();
console.log('Response data:', data);
console.groupEnd();
return data;
} catch (error) {
console.error('API Call failed:', error);
console.groupEnd();
throw error;
}
}
Debugging de Estado de Aplicación
State Management Debugging
// Redux-like state debugging
function createDebuggableStore(reducer, initialState) {
let state = initialState;
return {
getState: () => state,
dispatch: (action) => {
console.group('Dispatching:', action.type);
console.log('Previous state:', state);
state = reducer(state, action);
console.log('Next state:', state);
console.groupEnd();
return action;
}
};
}
// React state debugging
function useDebugState(initialState, label = 'State') {
const [state, setState] = useState(initialState);
const debugSetState = useCallback((newState) => {
console.group(`State update: ${label}`);
console.log('Previous:', state);
console.log('Next:', newState);
console.groupEnd();
setState(newState);
}, [state, label]);
return [state, debugSetState];
}
Debugging de Bases de Datos
Query Debugging
// SQL query debugging with timing
async function debugQuery(query, params = []) {
console.log('Executing query:', query);
console.log('With parameters:', params);
const startTime = Date.now();
try {
const result = await database.query(query, params);
const duration = Date.now() - startTime;
console.log(`Query completed in ${duration}ms`);
console.log('Result:', result.rows);
return result;
} catch (error) {
console.error('Query failed:', error);
throw error;
}
}
// MongoDB query debugging
function debugMongoQuery(collection, query, options = {}) {
console.log('MongoDB Query:');
console.log('Collection:', collection.collectionName);
console.log('Query:', JSON.stringify(query, null, 2));
console.log('Options:', options);
return collection.find(query, options)
.explain('executionStats')
.then(explanation => {
console.log('Query explanation:', explanation);
return collection.find(query, options).toArray();
});
}
Debugging de Concurrente y Paralelo
Race Condition Detection
// Debug async race conditions
class RaceConditionDetector {
constructor() {
this.operations = new Map();
}
startOperation(id) {
this.operations.set(id, {
start: Date.now(),
stack: new Error().stack
});
}
endOperation(id) {
const op = this.operations.get(id);
if (op) {
const duration = Date.now() - op.start;
console.log(`Operation ${id} took ${duration}ms`);
this.operations.delete(id);
}
}
logPendingOperations() {
console.log('Pending operations:', this.operations.size);
this.operations.forEach((op, id) => {
console.log(`Operation ${id} running for ${Date.now() - op.start}ms`);
console.log('Stack:', op.stack);
});
}
}
Deadlock Detection
// Resource locking debugger
class LockDebugger {
constructor() {
this.locks = new Map();
this.waiting = new Map();
}
acquireLock(resource, owner) {
if (this.locks.has(resource)) {
console.warn(`Lock contention on ${resource}`);
console.log(`Current owner: ${this.locks.get(resource)}`);
console.log(`Waiting owner: ${owner}`);
if (!this.waiting.has(resource)) {
this.waiting.set(resource, []);
}
this.waiting.get(resource).push(owner);
}
this.locks.set(resource, owner);
console.log(`Lock acquired: ${resource} by ${owner}`);
}
releaseLock(resource, owner) {
if (this.locks.get(resource) === owner) {
this.locks.delete(resource);
console.log(`Lock released: ${resource} by ${owner}`);
}
}
}
Debugging de Seguridad
Security Vulnerability Debugging
// XSS detection
function detectXSS(input) {
const suspiciousPatterns = [
/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
/javascript:/gi,
/on\w+\s*=/gi,
/expression\s*\(/gi
];
suspiciousPatterns.forEach((pattern, index) => {
if (pattern.test(input)) {
console.warn(`Potential XSS detected in input:`, input);
debugger;
}
});
}
// SQL injection detection
function detectSQLInjection(input) {
const sqlPatterns = [
/\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION)\b/gi,
/'.*--/,
/;\s*DROP/,
/OR\s+1=1/
];
sqlPatterns.forEach(pattern => {
if (pattern.test(input)) {
console.warn(`Potential SQL injection:`, input);
}
});
}
Debugging de Gráficos y UI
Visual Debugging
// Visual layout debugging
function debugLayout(element) {
const rect = element.getBoundingClientRect();
const styles = window.getComputedStyle(element);
console.group('Layout Debugging:', element.tagName);
console.log('Position:', rect);
console.log('Display:', styles.display);
console.log('Visibility:', styles.visibility);
console.log('Opacity:', styles.opacity);
console.log('Z-index:', styles.zIndex);
console.log('Transform:', styles.transform);
console.groupEnd();
// Visual overlay
const overlay = document.createElement('div');
overlay.style.cssText = `
position: absolute;
border: 2px solid red;
pointer-events: none;
top: ${rect.top}px;
left: ${rect.left}px;
width: ${rect.width}px;
height: ${rect.height}px;
z-index: 10000;
`;
document.body.appendChild(overlay);
setTimeout(() => overlay.remove(), 3000);
}
Animation Debugging
// CSS animation debugging
function debugAnimations() {
const elements = document.querySelectorAll('*');
elements.forEach(el => {
const style = window.getComputedStyle(el);
const hasAnimation = style.animationName !== 'none';
const hasTransition = style.transition !== 'none';
if (hasAnimation || hasTransition) {
console.log('Animated element:', el);
console.log('Animation:', style.animationName);
console.log('Transition:', style.transition);
}
});
}
Debugging de Build y Deployment
Build Process Debugging
// Webpack build debugging
const webpack = require('webpack');
const compiler = webpack({
// ... webpack config
stats: 'verbose', // Detailed build information
infrastructureLogging: {
level: 'verbose'
}
});
compiler.run((err, stats) => {
if (err) {
console.error('Build failed:', err);
return;
}
if (stats.hasErrors()) {
console.error('Build errors:');
stats.compilation.errors.forEach(error => {
console.error(error.message);
});
}
if (stats.hasWarnings()) {
console.warn('Build warnings:');
stats.compilation.warnings.forEach(warning => {
console.warn(warning.message);
});
}
});
Environment Debugging
// Environment variable debugging
function debugEnvironment() {
console.group('Environment Debugging');
console.log('NODE_ENV:', process.env.NODE_ENV);
console.log('Platform:', process.platform);
console.log('Architecture:', process.arch);
console.log('Node version:', process.version);
console.log('Current directory:', process.cwd());
console.groupEnd();
}
// Configuration validation
function validateConfig(config) {
const required = ['API_URL', 'DATABASE_URL', 'SECRET_KEY'];
const missing = required.filter(key => !config[key]);
if (missing.length > 0) {
console.error('Missing required configuration:', missing);
debugger;
throw new Error(`Missing configuration: ${missing.join(', ')}`);
}
}
Debugging de Logs Distribuidos
Distributed Tracing
// Correlation ID for distributed debugging
class RequestTracer {
constructor() {
this.correlationId = null;
}
startTrace(correlationId = null) {
this.correlationId = correlationId || this.generateId();
console.log(`[${this.correlationId}] Trace started`);
return this.correlationId;
}
log(message, data = null) {
const timestamp = new Date().toISOString();
console.log(`[${this.correlationId}] ${timestamp}: ${message}`);
if (data) {
console.log(`[${this.correlationId}] Data:`, data);
}
}
generateId() {
return Math.random().toString(36).substr(2, 9);
}
}
// Usage in microservices
const tracer = new RequestTracer();
const correlationId = tracer.startTrace();
tracer.log('Processing request', { userId: 123 });
Debugging de Caché
Cache Behavior Debugging
class CacheDebugger {
constructor() {
this.hits = 0;
this.misses = 0;
this.operations = [];
}
logOperation(key, operation, value = null) {
const entry = {
timestamp: Date.now(),
key,
operation,
value,
stack: new Error().stack
};
this.operations.push(entry);
if (operation === 'HIT') this.hits++;
if (operation === 'MISS') this.misses++;
console.log(`Cache ${operation}: ${key}`, value);
}
getStats() {
const hitRate = this.hits / (this.hits + this.misses);
return {
hits: this.hits,
misses: this.misses,
hitRate: hitRate.toFixed(2),
totalOperations: this.operations.length
};
}
inspectKey(key) {
return this.operations.filter(op => op.key === key);
}
}
Debugging de WebSockets
WebSocket Connection Debugging
class WebSocketDebugger {
constructor(url) {
this.messages = [];
this.connectionStates = [];
this.socket = new WebSocket(url);
this.setupDebugging();
}
setupDebugging() {
const events = ['open', 'message', 'error', 'close'];
events.forEach(event => {
this.socket.addEventListener(event, (e) => {
this.logEvent(event, e);
if (event === 'error' || event === 'close') {
debugger; // Pause on connection issues
}
});
});
}
logEvent(type, event) {
const entry = {
timestamp: Date.now(),
type,
data: event.data,
readyState: this.socket.readyState,
code: event.code,
reason: event.reason
};
this.connectionStates.push(entry);
console.log(`WebSocket ${type}:`, entry);
}
sendWithDebug(data) {
console.group('WebSocket Send');
console.log('Data:', data);
console.log('ReadyState:', this.socket.readyState);
console.groupEnd();
this.socket.send(JSON.stringify(data));
}
getConnectionHealth() {
const recent = this.connectionStates.slice(-10);
const errors = recent.filter(state => state.type === 'error');
return {
totalMessages: this.messages.length,
recentErrors: errors.length,
currentState: this.socket.readyState,
latency: this.calculateLatency()
};
}
}
Debugging de Workers
Web Worker Debugging
// Main thread worker debugger
class WorkerDebugger {
constructor(workerScript) {
this.worker = new Worker(workerScript);
this.messages = [];
this.setupDebugging();
}
setupDebugging() {
this.worker.addEventListener('message', (e) => {
this.logMessage('FROM_WORKER', e.data);
if (e.data.type === 'ERROR') {
console.error('Worker error:', e.data.error);
debugger;
}
});
this.worker.addEventListener('error', (e) => {
console.error('Worker runtime error:', e);
debugger;
});
}
postMessageWithDebug(data) {
const messageId = this.generateMessageId();
const debugData = {
...data,
_debugId: messageId,
_timestamp: Date.now()
};
this.logMessage('TO_WORKER', debugData);
this.worker.postMessage(debugData);
return messageId;
}
logMessage(direction, data) {
this.messages.push({
direction,
data,
timestamp: Date.now(),
stack: direction === 'TO_WORKER' ? new Error().stack : null
});
console.log(`Worker ${direction}:`, data);
}
}
// Worker internal debugging
self.addEventListener('message', function(e) {
const debugId = e.data._debugId;
try {
// Process message
const result = processData(e.data);
self.postMessage({
type: 'SUCCESS',
result,
_debugId: debugId
});
} catch (error) {
self.postMessage({
type: 'ERROR',
error: error.message,
stack: error.stack,
_debugId: debugId
});
}
});
Debugging de Autenticación
Auth Flow Debugging
class AuthDebugger {
constructor() {
this.authEvents = [];
this.tokenStates = [];
}
debugAuthFlow() {
// Monitor localStorage/sessionStorage for tokens
const originalSetItem = localStorage.setItem;
localStorage.setItem = (key, value) => {
if (key.includes('token') || key.includes('auth')) {
this.logAuthEvent('TOKEN_STORED', { key, value });
}
originalSetItem.call(localStorage, key, value);
};
// Monitor fetch requests for auth headers
const originalFetch = window.fetch;
window.fetch = (...args) => {
const request = args[1] || {};
if (request.headers && request.headers.Authorization) {
this.logAuthEvent('AUTH_HEADER_SENT', {
url: args[0],
header: request.headers.Authorization
});
}
return originalFetch(...args);
};
}
logAuthEvent(type, data) {
const event = {
type,
timestamp: Date.now(),
data,
stack: new Error().stack
};
this.authEvents.push(event);
console.log(`Auth Event [${type}]:`, data);
if (type === 'TOKEN_EXPIRED' || type === 'AUTH_FAILED') {
debugger; // Pause on auth failures
}
}
validateToken(token) {
try {
const payload = JSON.parse(atob(token.split('.')[1]));
const expiry = payload.exp * 1000;
const now = Date.now();
this.logAuthEvent('TOKEN_VALIDATED', {
expiry: new Date(expiry),
isExpired: now > expiry,
timeUntilExpiry: expiry - now
});
return now < expiry;
} catch (error) {
this.logAuthEvent('TOKEN_INVALID', { error: error.message });
return false;
}
}
}
Debugging de Rendimiento en Tiempo Real
Real-time Performance Monitoring
class PerformanceDebugger {
constructor() {
this.metrics = new Map();
this.thresholds = {
slowOperation: 100, // ms
memoryLeak: 1000, // KB
highCPU: 80 // %
};
}
startMonitoring() {
this.monitorMemory();
this.monitorCPU();
this.monitorEventLoop();
}
monitorMemory() {
setInterval(() => {
const memory = process.memoryUsage();
const heapUsed = Math.round(memory.heapUsed / 1024);
this.recordMetric('memory', heapUsed);
if (heapUsed > this.thresholds.memoryLeak) {
console.warn(`High memory usage: ${heapUsed}KB`);
this.takeHeapSnapshot();
}
}, 5000);
}
monitorEventLoop() {
let lastTime = Date.now();
setInterval(() => {
const now = Date.now();
const delay = now - lastTime - 1000; // Expected 1s interval
this.recordMetric('eventLoopDelay', delay);
if (delay > 100) {
console.warn(`Event loop delayed: ${delay}ms`);
this.analyzeBlockingOperations();
}
lastTime = now;
}, 1000);
}
measureRenderTime(componentName, renderFn) {
const start = performance.now();
const result = renderFn();
const duration = performance.now() - start;
this.recordMetric(`render_${componentName}`, duration);
if (duration > this.thresholds.slowOperation) {
console.warn(`Slow render (${componentName}): ${duration}ms`);
}
return result;
}
analyzeBlockingOperations() {
const longTasks = performance.getEntriesByType('long-task');
longTasks.forEach(task => {
console.warn('Long task detected:', {
duration: task.duration,
startTime: task.startTime,
name: task.name
});
});
}
}
Debugging de Internacionalización
i18n Debugging
class I18nDebugger {
constructor() {
this.missingTranslations = new Set();
this.usedTranslations = new Map();
}
wrapI18nFunction(i18nFunction) {
return (key, params = {}) => {
const result = i18nFunction(key, params);
// Track usage
this.usedTranslations.set(key, {
lastUsed: Date.now(),
params,
result
});
// Check for missing translations
if (result === key || result.includes('missing')) {
this.missingTranslations.add(key);
console.warn(`Missing translation: ${key}`);
debugger; // Pause on missing translations
}
return result;
};
}
analyzeCoverage() {
const allKeys = this.getAllTranslationKeys();
const usedKeys = Array.from(this.usedTranslations.keys());
const unusedKeys = allKeys.filter(key => !usedKeys.includes(key));
console.group('i18n Coverage Analysis');
console.log('Total keys:', allKeys.length);
console.log('Used keys:', usedKeys.length);
console.log('Unused keys:', unusedKeys.length);
console.log('Missing translations:', this.missingTranslations.size);
console.groupEnd();
return { usedKeys, unusedKeys, missing: Array.from(this.missingTranslations) };
}
detectHardcodedStrings() {
// Search for non-wrapped strings in components
const hardcodedPatterns = [
/[^=]=['"][A-Za-z][^=]*?['"]/g,
/>[A-Za-z][^<]*?</g
];
// This would typically run against source code
console.log('Hardcoded string detection running...');
}
}
Debugging de Accesibilidad
A11y Debugging
class AccessibilityDebugger {
constructor() {
this.violations = [];
}
scanPage() {
this.checkColorContrast();
this.checkKeyboardNavigation();
this.checkScreenReaderCompatibility();
this.checkFormLabels();
}
checkColorContrast() {
const elements = document.querySelectorAll('*');
elements.forEach(el => {
const style = window.getComputedStyle(el);
const bgColor = style.backgroundColor;
const color = style.color;
const contrast = this.calculateContrast(bgColor, color);
if (contrast < 4.5) {
this.recordViolation('LOW_CONTRAST', {
element: el,
contrast: contrast.toFixed(2),
required: 4.5
});
}
});
}
checkKeyboardNavigation() {
const focusable = document.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]'
);
focusable.forEach((el, index) => {
const tabIndex = el.getAttribute('tabindex');
const computedStyle = window.getComputedStyle(el);
if (computedStyle.visibility === 'hidden' ||
computedStyle.display === 'none') {
this.recordViolation('HIDDEN_FOCUSABLE', { element: el });
}
if (tabIndex && parseInt(tabIndex) < 0) {
this.recordViolation('NEGATIVE_TABINDEX', { element: el, tabIndex });
}
});
}
checkFormLabels() {
const inputs = document.querySelectorAll('input, select, textarea');
inputs.forEach(input => {
const label = document.querySelector(`label[for="${input.id}"]`);
const ariaLabel = input.getAttribute('aria-label');
if (!label && !ariaLabel && input.type !== 'hidden') {
this.recordViolation('MISSING_LABEL', { element: input });
}
});
}
recordViolation(type, data) {
const violation = {
type,
timestamp: Date.now(),
...data,
stack: new Error().stack
};
this.violations.push(violation);
console.warn(`A11y Violation [${type}]:`, data);
// Highlight problematic elements
if (data.element) {
this.highlightElement(data.element, type);
}
}
highlightElement(element, violationType) {
const borderColor = violationType === 'LOW_CONTRAST' ? 'orange' : 'red';
element.style.outline = `2px solid ${borderColor}`;
element.style.outlineOffset = '2px';
}
}
Debugging de Offline y Sync
Offline Capability Debugging
class OfflineDebugger {
constructor() {
this.syncOperations = [];
this.networkState = 'online';
this.setupNetworkMonitoring();
}
setupNetworkMonitoring() {
window.addEventListener('online', () => {
this.networkState = 'online';
this.logSyncEvent('NETWORK_ONLINE');
this.processPendingOperations();
});
window.addEventListener('offline', () => {
this.networkState = 'offline';
this.logSyncEvent('NETWORK_OFFLINE');
});
// Simulate network conditions for testing
this.simulateNetworkConditions();
}
logSyncOperation(operation, data) {
const syncOp = {
id: this.generateId(),
operation,
data,
timestamp: Date.now(),
networkState: this.networkState,
status: this.networkState === 'online' ? 'PENDING' : 'QUEUED'
};
this.syncOperations.push(syncOp);
console.log(`Sync Operation [${operation}]:`, syncOp);
if (this.networkState === 'offline') {
this.queueForSync(syncOp);
}
return syncOp.id;
}
queueForSync(operation) {
// Store in IndexedDB for later sync
const dbRequest = indexedDB.open('SyncQueue', 1);
dbRequest.onsuccess = (event) => {
const db = event.target.result;
const transaction = db.transaction(['operations'], 'readwrite');
const store = transaction.objectStore('operations');
store.add(operation);
};
console.log('Operation queued for offline sync:', operation);
}
async processPendingOperations() {
const pending = this.syncOperations.filter(op => op.status === 'QUEUED');
console.group('Processing pending operations');
for (const operation of pending) {
try {
await this.executeSyncOperation(operation);
operation.status = 'COMPLETED';
console.log(`Operation ${operation.id} completed`);
} catch (error) {
operation.status = 'FAILED';
operation.error = error.message;
console.error(`Operation ${operation.id} failed:`, error);
}
}
console.groupEnd();
}
simulateNetworkConditions() {
// For testing offline scenarios
if (process.env.NODE_ENV === 'development') {
window.debugSimulateOffline = () => {
this.networkState = 'offline';
window.dispatchEvent(new Event('offline'));
};
window.debugSimulateOnline = () => {
this.networkState = 'online';
window.dispatchEvent(new Event('online'));
};
}
}
}
Debugging de Machine Learning
Model Training Debugging
class MLTrainingDebugger:
def __init__(self):
self.training_history = []
self.gradient_norms = []
self.loss_breakdown = []
def log_training_step(self, epoch, loss, accuracy, gradients):
step_data = {
'epoch': epoch,
'loss': float(loss),
'accuracy': float(accuracy),
'gradient_norm': float(torch.norm(gradients)),
'timestamp': time.time()
}
self.training_history.append(step_data)
# Check for vanishing/exploding gradients
if step_data['gradient_norm'] < 1e-7:
print(f"⚠️ Vanishing gradients detected at epoch {epoch}")
debugger()
elif step_data['gradient_norm'] > 1e5:
print(f"⚠️ Exploding gradients detected at epoch {epoch}")
debugger()
def analyze_loss_components(self, model, dataloader, criterion):
model.eval()
total_loss = 0
component_losses = {}
with torch.no_grad():
for batch in dataloader:
outputs = model(batch)
loss_components = criterion(outputs, batch, reduce=False)
for key, component_loss in loss_components.items():
if key not in component_losses:
component_losses[key] = []
component_losses[key].append(component_loss.mean().item())
print("📊 Loss Component Analysis:")
for component, losses in component_losses.items():
avg_loss = sum(losses) / len(losses)
print(f" {component}: {avg_loss:.6f}")
Debugging de Realidad Virtual/Aumentada
VR/AR Performance Debugging
class VRARDebugger {
constructor(renderer, camera) {
this.renderer = renderer;
this.camera = camera;
this.performanceMetrics = {
frameTimes: [],
memoryUsage: [],
drawCalls: []
};
this.setupVRDebugging();
}
setupVRDebugging() {
// Monitor frame rate and performance
this.monitorFrameRate();
this.monitorMemoryUsage();
this.trackRenderPerformance();
}
monitorFrameRate() {
let lastTime = performance.now();
let frameCount = 0;
const checkFrameRate = () => {
frameCount++;
const currentTime = performance.now();
if (currentTime - lastTime >= 1000) {
const fps = frameCount;
frameCount = 0;
lastTime = currentTime;
this.performanceMetrics.frameTimes.push(fps);
if (fps < 60) {
console.warn(`Low frame rate: ${fps} FPS`);
this.analyzePerformanceBottleneck();
}
}
requestAnimationFrame(checkFrameRate);
};
checkFrameRate();
}
trackRenderPerformance() {
const originalRender = this.renderer.render;
this.renderer.render = (scene, camera) => {
const startTime = performance.now();
originalRender.call(this.renderer, scene, camera);
const renderTime = performance.now() - startTime;
this.performanceMetrics.drawCalls.push({
time: renderTime,
triangles: this.renderer.info.render.triangles,
calls: this.renderer.info.render.calls,
timestamp: Date.now()
});
if (renderTime > 16) { // More than 16ms per frame
console.warn(`Slow render: ${renderTime.toFixed(2)}ms`);
}
};
}
debugPoseTracking() {
// Debug VR controller/hand tracking
const originalUpdate = this.controllers.update;
this.controllers.update = function() {
originalUpdate.call(this);
this.controllers.forEach(controller => {
console.log('Controller pose:', {
position: controller.position,
rotation: controller.rotation,
connected: controller.connected
});
});
};
}
}
Debugging de Blockchain
Smart Contract Debugging
class BlockchainDebugger {
constructor(web3, contractAddress) {
this.web3 = web3;
this.contractAddress = contractAddress;
this.transactionLog = [];
this.gasUsage = [];
}
async debugTransaction(txHash) {
console.group(`🔍 Debugging Transaction: ${txHash}`);
try {
const receipt = await this.web3.eth.getTransactionReceipt(txHash);
const tx = await this.web3.eth.getTransaction(txHash);
console.log('Transaction Details:', {
from: tx.from,
to: tx.to,
value: tx.value,
gasUsed: receipt.gasUsed,
status: receipt.status ? 'Success' : 'Failed'
});
if (receipt.status === false) {
await this.analyzeFailure(receipt, tx);
}
this.analyzeGasUsage(receipt);
} catch (error) {
console.error('Transaction debug failed:', error);
}
console.groupEnd();
}
async analyzeFailure(receipt, tx) {
// Try to decode revert reason
try {
const code = await this.web3.eth.getCode(this.contractAddress);
if (code === '0x') {
console.error('❌ Contract does not exist at address');
return;
}
// Simulate the transaction to get revert reason
const result = await this.web3.eth.call({
from: tx.from,
to: tx.to,
value: tx.value,
data: tx.input,
gas: tx.gas
});
console.log('Transaction simulation result:', result);
} catch (simError) {
console.error('Revert reason:', simError.message);
}
}
monitorEvents(contract) {
const allEvents = contract.events.allEvents({
fromBlock: 'latest'
});
allEvents.on('data', (event) => {
console.group(`📝 Contract Event: ${event.event}`);
console.log('Return values:', event.returnValues);
console.log('Block:', event.blockNumber);
console.log('Transaction:', event.transactionHash);
console.groupEnd();
this.transactionLog.push({
type: 'EVENT',
event: event.event,
values: event.returnValues,
block: event.blockNumber,
txHash: event.transactionHash,
timestamp: Date.now()
});
});
}
}
Debugging de IoT y Dispositivos
IoT Device Communication Debugging
class IoTDebugger:
def __init__(self):
self.message_log = []
self.connection_states = []
self.sensor_readings = []
def debug_mqtt_communication(self, client):
"""Debug MQTT message flow"""
original_publish = client.publish
original_subscribe = client.subscribe
def debug_publish(topic, payload, **kwargs):
message_id = f"msg_{len(self.message_log)}"
log_entry = {
'id': message_id,
'direction': 'OUTGOING',
'topic': topic,
'payload': payload,
'timestamp': time.time(),
'qos': kwargs.get('qos', 0)
}
self.message_log.append(log_entry)
print(f"📤 MQTT Publish: {topic} -> {payload}")
return original_publish(topic, payload, **kwargs)
def debug_subscribe(topic, **kwargs):
print(f"📥 MQTT Subscribe: {topic}")
return original_subscribe(topic, **kwargs)
client.publish = debug_publish
client.subscribe = debug_subscribe
# Monitor connection state
client.on_connect = lambda client, userdata, flags, rc: (
self.connection_states.append({'event': 'CONNECT', 'code': rc}),
print(f"🔗 MQTT Connected: RC={rc}")
)
client.on_disconnect = lambda client, userdata, rc: (
self.connection_states.append({'event': 'DISCONNECT', 'code': rc}),
print(f"🔌 MQTT Disconnected: RC={rc}")
)
def monitor_sensor_data(self, sensor_callback):
"""Wrap sensor reading callbacks with debugging"""
def debug_sensor_reading(*args, **kwargs):
reading = sensor_callback(*args, **kwargs)
sensor_entry = {
'timestamp': time.time(),
'reading': reading,
'sensor_type': sensor_callback.__name__
}
self.sensor_readings.append(sensor_entry)
# Check for abnormal readings
if self.is_abnormal_reading(reading, sensor_callback.__name__):
print(f"⚠️ Abnormal sensor reading: {reading}")
# Trigger debug breakpoint
import pdb; pdb.set_trace()
return reading
return debug_sensor_reading
def is_abnormal_reading(self, reading, sensor_type):
"""Detect abnormal sensor readings"""
thresholds = {
'temperature': (-40, 85),
'humidity': (0, 100),
'pressure': (300, 1100)
}
if sensor_type in thresholds:
min_val, max_val = thresholds[sensor_type]
return reading < min_val or reading > max_val
return False
Debugging de Sistemas Embebidos
Embedded System Debugging
#include <debug_utils.h>
typedef struct {
uint32_t timestamp;
char function_name[32];
uint32_t line_number;
char message[128];
DebugLevel level;
} DebugEntry;
class EmbeddedDebugger {
private:
DebugEntry log_buffer[DEBUG_BUFFER_SIZE];
uint32_t log_index;
bool real_time_debug;
public:
void init_debugger() {
log_index = 0;
real_time_debug = true;
// Setup debug UART
uart_init(DEBUG_UART, 115200);
// Enable cycle counter for timing
enable_cycle_counter();
}
void debug_log(DebugLevel level, const char* function, uint32_t line, const char* format, ...) {
if (log_index >= DEBUG_BUFFER_SIZE) {
log_index = 0; // Circular buffer
}
DebugEntry* entry = &log_buffer[log_index++];
entry->timestamp = get_system_time();
strncpy(entry->function_name, function, 31);
entry->line_number = line;
entry->level = level;
va_list args;
va_start(args, format);
vsnprintf(entry->message, 127, format, args);
va_end(args);
// Real-time output if enabled
if (real_time_debug) {
uart_printf(DEBUG_UART, "[%lu] %s:%lu - %s\n",
entry->timestamp, function, line, entry->message);
}
// Break on critical errors
if (level == DEBUG_CRITICAL) {
trigger_breakpoint();
}
}
void dump_memory_map() {
printf("Memory Map Dump:\n");
printf("Heap start: 0x%08lX\n", get_heap_start());
printf("Heap end: 0x%08lX\n", get_heap_end());
printf("Stack pointer: 0x%08lX\n", get_stack_pointer());
printf("Free memory: %lu bytes\n", get_free_memory());
}
void profile_function(const char* function_name, void (*func)(void)) {
uint32_t start_cycles = get_cycle_count();
uint32_t start_time = get_system_time();
func(); // Execute the function
uint32_t end_cycles = get_cycle_count();
uint32_t end_time = get_system_time();
printf("Function %s profiling:\n", function_name);
printf(" CPU cycles: %lu\n", end_cycles - start_cycles);
printf(" Execution time: %lu us\n", end_time - start_time);
}
};
// Macros for easy debugging
#define DEBUG_INFO(...) debug_log(DEBUG_INFO, __FUNCTION__, __LINE__, __VA_ARGS__)
#define DEBUG_WARN(...) debug_log(DEBUG_WARN, __FUNCTION__, __LINE__, __VA_ARGS__)
#define DEBUG_ERROR(...) debug_log(DEBUG_ERROR, __FUNCTION__, __LINE__, __VA_ARGS__)
#define DEBUG_CRITICAL(...) debug_log(DEBUG_CRITICAL, __FUNCTION__, __LINE__, __VA_ARGS__)
Debugging de Sistemas Distribuidos
Distributed System Tracing
public class DistributedTracingDebugger {
private final ThreadLocal<String> currentTraceId = new ThreadLocal<>();
private final Map<String, TraceContext> traces = new ConcurrentHashMap<>();
private final SpanCollector spanCollector;
public void startTrace(String traceId, String operation) {
currentTraceId.set(traceId);
TraceContext context = new TraceContext(traceId, operation);
traces.put(traceId, context);
logTraceEvent("TRACE_START", traceId, operation, null);
}
public void logSpan(String spanName, Map<String, Object> tags) {
String traceId = currentTraceId.get();
if (traceId != null) {
Span span = new Span(spanName, traceId, System.currentTimeMillis(), tags);
spanCollector.collect(span);
logTraceEvent("SPAN_CREATED", traceId, spanName, tags);
}
}
public void logRemoteCall(String service, String endpoint, Map<String, String> headers) {
String traceId = currentTraceId.get();
if (traceId != null) {
// Inject trace context into headers
headers.put("X-Trace-Id", traceId);
headers.put("X-Span-Id", generateSpanId());
logTraceEvent("REMOTE_CALL", traceId,
String.format("%s:%s", service, endpoint), headers);
}
}
public void analyzeTrace(String traceId) {
TraceContext context = traces.get(traceId);
if (context != null) {
System.out.println("=== Trace Analysis ===");
System.out.println("Trace ID: " + traceId);
System.out.println("Operation: " + context.getOperation());
System.out.println("Duration: " + context.getDuration() + "ms");
System.out.println("Spans: " + context.getSpans().size());
// Identify bottlenecks
context.getSpans().stream()
.filter(span -> span.getDuration() > 1000) // Spans longer than 1s
.forEach(span ->
System.out.println("Slow span: " + span.getName() +
" (" + span.getDuration() + "ms)"));
}
}
public void detectDistributedDeadlocks() {
// Analyze trace dependencies for potential deadlocks
traces.values().stream()
.filter(context -> context.getDuration() > 30000) // Traces longer than 30s
.forEach(context -> {
System.out.println("Potential deadlock detected in trace: " +
context.getTraceId());
analyzeTrace(context.getTraceId());
});
}
}
Debugging de Sistemas en Tiempo Real
Real-time System Debugging
class RealTimeDebugger {
private:
std::vector<RTSTask> tasks;
std::chrono::steady_clock::time_point start_time;
bool deadline_missed;
public:
void monitor_task_deadlines() {
for (auto& task : tasks) {
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - task.start_time);
if (elapsed.count() > task.deadline_ms && !task.completed) {
deadline_missed = true;
log_deadline_miss(task.id, elapsed.count());
// Trigger emergency response
handle_deadline_miss(task);
}
}
}
void log_deadline_miss(int task_id, long actual_time) {
std::cout << "🚨 Deadline missed - Task: " << task_id
<< ", Actual: " << actual_time << "ms" << std::endl;
// Dump system state for analysis
dump_system_state();
// If in debug mode, break execution
#ifdef DEBUG_MODE
raise(SIGTRAP); // Trigger debugger breakpoint
#endif
}
void profile_interrupt_latency() {
auto interrupt_start = std::chrono::high_resolution_clock::now();
// Simulate interrupt handling
handle_interrupt();
auto interrupt_end = std::chrono::high_resolution_clock::now();
auto latency = std::chrono::duration_cast<std::chrono::microseconds>(
interrupt_end - interrupt_start);
if (latency.count() > MAX_INTERRUPT_LATENCY) {
std::cout << "⚠️ High interrupt latency: " << latency.count() << "μs" << std::endl;
}
}
void analyze_scheduling() {
// Monitor context switches
auto context_switches = get_context_switch_count();
static auto last_check = std::chrono::steady_clock::now();
auto now = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - last_check);
if (duration.count() >= 1) {
auto switches_per_second = context_switches / duration.count();
if (switches_per_second > MAX_CONTEXT_SWITCHES) {
std::cout << "⚠️ High context switch rate: "
<< switches_per_second << "/s" << std::endl;
}
last_check = now;
}
}
};
Debugging de Sistemas de Archivos
File System Operation Debugging
class FileSystemDebugger:
def __init__(self):
self.file_operations = []
self.lock_contention = []
self.open_handles = {}
def monitor_file_operations(self):
"""Monitor all file system operations"""
original_open = builtins.open
original_remove = os.remove
original_rename = os.rename
def debug_open(filename, mode='r', *args, **kwargs):
start_time = time.time()
file_handle = original_open(filename, mode, *args, **kwargs)
end_time = time.time()
operation = {
'type': 'OPEN',
'filename': filename,
'mode': mode,
'duration': end_time - start_time,
'timestamp': start_time,
'thread': threading.current_thread().name
}
self.file_operations.append(operation)
# Track open file handles
self.open_handles[file_handle] = {
'filename': filename,
'open_time': start_time,
'mode': mode
}
print(f"📁 File opened: {filename} ({mode})")
return file_handle
def debug_remove(filename):
operation = {
'type': 'REMOVE',
'filename': filename,
'timestamp': time.time(),
'thread': threading.current_thread().name
}
self.file_operations.append(operation)
print(f"🗑️ File removed: {filename}")
return original_remove(filename)
builtins.open = debug_open
os.remove = debug_remove
os.rename = debug_rename
def detect_file_leaks(self):
"""Detect unreleased file handles"""
current_time = time.time()
leaked_handles = []
for handle, info in self.open_handles.items():
if current_time - info['open_time'] > 300: # 5 minutes
leaked_handles.append((handle, info))
if leaked_handles:
print(f"⚠️ Potential file handle leaks detected: {len(leaked_handles)}")
for handle, info in leaked_handles:
print(f" - {info['filename']} opened at {info['open_time']}")
def analyze_io_patterns(self):
"""Analyze file I/O patterns for performance issues"""
reads = [op for op in self.file_operations if op['type'] == 'READ']
writes = [op for op in self.file_operations if op['type'] == 'WRITE']
print("📊 I/O Pattern Analysis:")
print(f" Read operations: {len(reads)}")
print(f" Write operations: {len(writes)}")
if reads:
avg_read_time = sum(op['duration'] for op in reads) / len(reads)
print(f" Average read time: {avg_read_time:.3f}s")
if writes:
avg_write_time = sum(op['duration'] for op in writes) / len(writes)
print(f" Average write time: {avg_write_time:.3f}s")
# Detect small, frequent writes (bad for performance)
small_writes = [op for op in writes if op.get('size', 0) < 4096]
if len(small_writes) > 100:
print("⚠️ Many small writes detected - consider buffering")
¿Te gusta este contenido? Suscríbete vía RSS