如何记录所有函数调用?EDGE浏览器崩溃排查技术求助
Got it, let's tackle this problem—your current setup only catches .call()/.apply() calls, but you need to log every function invocation (like someFunction()) to pinpoint what's triggering that Edge crash. Here are three practical, actionable strategies to make this work:
1. Wrap All Functions via Function.prototype (Most Comprehensive)
Since every function in JS is an instance of Function, we can modify its prototype to automatically wrap every function (existing and new) with logging logic. This will catch direct calls, .call(), .apply(), and even arrow functions (with caveats for anonymous ones).
Here's the code:
// Flag to avoid infinite wrapping loops const WRAPPED_FLAG = '__isFunctionWrapped__'; // Core wrapper function to log calls and execute the original function function wrapFunction(fn, functionName = 'anonymous') { // Skip native browser functions to avoid breaking Edge's internal behavior if (fn.toString().includes('[native code]')) return fn; // Skip already wrapped functions if (fn[WRAPPED_FLAG]) return fn; const wrapped = function(...args) { // Log critical details: function name, arguments, caller context, and stack trace console.log(`[Function Invocation] ${functionName}`, { args: args, callerContext: this, stack: new Error().stack }); try { // Execute the original function with the correct context and args return fn.apply(this, args); } catch (err) { // Log errors too—crashes often happen after uncaught exceptions console.error(`[Function Error] ${functionName}`, err); throw err; // Don't swallow errors; keep the original behavior } }; wrapped[WRAPPED_FLAG] = true; return wrapped; } // Rewrite the Function constructor to wrap new functions automatically const originalFunctionConstructor = Function; Function = function(...args) { const newFn = originalFunctionConstructor.apply(this, args); // Try to extract a name (works for function declarations/named expressions) const fnName = args.length > 0 ? args[args.length - 1].match(/function\s+([^\s(]+)/)?.[1] : 'anonymous'; return wrapFunction(newFn, fnName); }; Function.prototype = originalFunctionConstructor.prototype; Function.prototype.constructor = Function; // Wrap all existing functions on the global object (window) function wrapExistingGlobalFunctions(obj, parentNamespace = '') { for (const key in obj) { if (obj.hasOwnProperty(key)) { const prop = obj[key]; const fullName = parentNamespace ? `${parentNamespace}.${key}` : key; if (typeof prop === 'function') { obj[key] = wrapFunction(prop, fullName); } else if (typeof prop === 'object' && prop !== null && !(prop instanceof HTMLElement)) { // Recursively wrap functions in nested objects (skip DOM elements to avoid Edge bugs) wrapExistingGlobalFunctions(prop, fullName); } } } } // Initialize wrapping for all global functions wrapExistingGlobalFunctions(window);
Key Notes:
- We skip native functions (marked with
[native code]) to avoid interfering with Edge's internal APIs, which could cause more crashes. - The stack trace in the log will help you trace exactly where each function was called from—critical for narrowing down the crash trigger.
- Anonymous functions will show up as
anonymous, but their stack trace will still point you to their definition.
2. Use the Browser Debugger API (Low-Level, No Code Modifications)
Edge supports the Chrome DevTools Debugger API, which lets you intercept every function call at the browser level. This is more reliable for edge cases but requires enabling debugging mode.
if (window.debugger) { // Enable the debugger debugger; const debugInstance = window.debugger; // Listen for function call events debugInstance.onDebuggerEvent = (event) => { if (event.type === 'functionCall') { const fnName = event.function.name || 'anonymous'; console.log(`[Debugger Call] ${fnName}`, { args: event.arguments, stack: event.stackTrace }); } }; // Enable all function call intercepts debugInstance.enable(); }
Key Notes:
- This will catch every single function invocation, including those from third-party scripts and browser internals.
- Performance overhead is higher than the prototype wrapping method, so only use this for targeted debugging sessions.
- Some Edge security settings might block this API—make sure you're running in a non-production, debug-friendly environment.
3. Proxy Wrappers (For Targeted Object Functions)
If you don't need to log every global function, you can use a Proxy to wrap specific objects or modules. This is less intrusive but requires targeting specific parts of your codebase.
const wrappedModule = new Proxy(yourModule, { get(target, prop) { const value = target[prop]; if (typeof value === 'function' && !value[WRAPPED_FLAG]) { return wrapFunction(value, `yourModule.${prop}`); } return value; } });
Key Notes:
- Great for focusing on a specific part of your codebase that you suspect is causing the crash.
- Won't catch functions outside the proxied object, so it's not a universal solution.
Critical Debugging Tips for Edge:
- Limit Logging: If your project is large, logging every function call will flood the console. Add filters (e.g., only log functions from your app's namespace) to keep output manageable.
- Save Logs: Edge's console can export logs to a file. Make sure to save the logs right before the crash—you can use
console.save()(a DevTools feature) or write logs to alocalStoragebuffer. - Test in Isolation: Try reproducing the crash in a minimal Edge window (no extensions) to rule out interference from add-ons.
内容的提问来源于stack exchange,提问作者Ray

