Search Unity

No stack trace for exceptions in WebGL

Discussion in 'Web' started by liortal, Mar 31, 2016.

  1. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    Our project is set to "explicitly thrown exceptions only", but we are not seeing any stack traces in our errors.

    We are on 5.3.4p1. Is this something that is expected? (or maybe only available for dev builds?)
     
  2. jonas-echterhoff

    jonas-echterhoff

    Unity Technologies

    Joined:
    Aug 18, 2005
    Posts:
    1,666
    What kind of errors are you expecting to see stack traces for, and in what browser? Can you post a sample C# script for an "error"?
     
  3. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    Hi Jonas,

    Sorry i did not elaborate. We are hooking to receive exception using Application.logMessageReceived.
    We report all exceptions in that event to a backend service where we can later diagnose them.

    The problem is that all messages don't contain any stack trace information (only the message itself).
    I am on Google Chrome on OSX - 49.0.2623.87 (64-bit).

    I was wondering whether this is a supported feature (getting a stack trace) or maybe its only available in development builds.
     
  4. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    Any word on this ? here is sample code similar to what we use:
    Code (CSharp):
    1. Application.logMessageReceived     += ReportError;
    2.  
    3. private void ReportError(string logString, string stackTrace, LogType type)
    4. {
    5.     // if type is an exception, logs the error (and stackTrace) to our backend
    6. }
    On development builds, we can get the full stack trace. But for release builds (the ones that are actually released to our players, there's only the log message without a stack trace.

    1. Is this intentional? should mono (managed) stack traces only be available in development builds ?

    2. Why isn't the native (JS) stack trace included in the error?

    3. Is it possible to attempt and reconstruct the source of error from the JS stack trace ?
     
  5. gguonextfloor

    gguonextfloor

    Joined:
    Mar 11, 2016
    Posts:
    3
    Although we are on iOS and Android we have same problem.

    we got no stack trace for Exception Log for release builds.
     
  6. jonas-echterhoff

    jonas-echterhoff

    Unity Technologies

    Joined:
    Aug 18, 2005
    Posts:
    1,666
    1. Managed stack traces require a bunch of embedded managed debug information in the build, which will make the generated code size significantly bigger. On WebGL, we currently only emit this information when using "Full" exception mode, as it makes the code harder to run in constraint memory settings.

    2. You can enable native JS stack traces using http://docs.unity3d.com/ScriptReference/Application-stackTraceLogType.html - these will also work without "Full" exception mode.

    3. I'd say, that depends on the error, but it might give you a good hint in most cases at least.
     
  7. ortin

    ortin

    Joined:
    Jan 13, 2013
    Posts:
    221
    http://blog.nordeus.com/dev-ops/porting-top-eleven-to-unity-webgl.htm
    This article (including comments) may be useful for dealing with exceptions in WebGL.

    NRE:
    Stacktrace reconstruction:
     
  8. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
  9. jonas-echterhoff

    jonas-echterhoff

    Unity Technologies

    Joined:
    Aug 18, 2005
    Posts:
    1,666
    No, what @ortin said will work to make Unity emit a symbol map which can be used to look up stack traces on release builds. It is not necessary to ship this data, you can just use it to look up names when users post minified stack traces.
     
    liortal likes this.
  10. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    @jonas-echterhoff I am still wondering why this doesn't work.

    In the browser, i can see exceptions with the full stack trace:
    upload_2016-7-21_14-3-20.png

    We have the log handler in unity, but we don't receive the whole stack trace (even when StackTraceType is set to Full).
    Moreover, i've tried to set up an error handler as described here: https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html

    It doesn't seem to be called at all.

    Why am i seeing the full stack trace for exceptions in the browser, but not getting this information back in my C# code in Unity ?
     
  11. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    Hello liortal.

    You may encounter incomplete stack traces passed to the Module.errorhandler in Chrome, because by default Chrome has limitation of 10 errors for the stack trace obtained via Error().stack.
    To resolve the issue, add the following Assets/stacktrace.jspre file to your project:
    Code (JavaScript):
    1. Error.stackTraceLimit = 50;
    This will be the default behavior in Unity 5.5
     
  12. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    I will try that. Could you elaborate on what you suggested? i am not sure i completely understood.
    The behaviour i am seeing is that Module.errorhandler is not called at all. Which errors should trigger it ? all errors? including ones that i log from inside my code (e.g: using Debug.Log) ?
     
  13. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    Oh, I see, that is not about incomplete stacktraces then.
    The Module.errorhandler is executed on uncaught JavaScript exception (handled via window.onerror), i.e. at the point where your application can no longer continue working.
    If you are interested in monitoring Debug.Log for example, then you might want to override the _JS_Log_Dump function. Also, Module.printErr might be of some interest. Are there any other events you would like to monitor or can you share the exact usecase?

    P.S. the stacktraces in the console you mentioned above are coming from the console.error, so you can capture all of them by simply overriding the console.error.
     
    Last edited: Jul 21, 2016
  14. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    Thanks for explaining. I have a few follow up questions, if you don't mind :)
    1. We use Application.logMessageReceived. Messages that are sent there do not contain any stack trace. However, if we report an error (e.g: Debug.LogError) it appears in the browser's console with the full stack trace. According to what you said above, these come from console.error ? so why don't we get the entire stack in our Unity handling code as well ?
    2. How do i override _JS_Log_Dump? where is it defined and what does it do?
    3. What is Module.printErr ? should we override that as well ?
    The way our setup works today, is that we hook to Application.logMessageReceived and report anything that is either an Error or an Exception. This will log any uncaught C# exception or any logged error messages and report them so we can keep track of issues our players are facing.

    The problem is that on WebGL, we are only getting the actual error message in these cases. For example - NullReferenceException. This doesn't include any stack trace or any other information, which makes it totally impossible to use for pinpointing exact issues.

    What do you think would be the best fit to listen to all errors / exceptions and be able to report them, the way we do on other platforms ?

    I have no problem with overriding any JS function that is needed, and then send the error back to our generic error reporting method in Unity. It's just that i'd like to know which functions we should override.
     
  15. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    I would probably go with overriding the window.console, because there are a lot of errors that are specific to JavaScript and can not be easily tracked otherwise, for example the error when user does not have access to indexedDB is only displayed in console:
    Code (JavaScript):
    1. if (!Module.indexedDB) {
    2.   console.log("IndexedDB is not available. Data will not persist in cache and PlayerPrefs will not be saved.");
    3. }
    though you might want to track it and send information about this failure to the server.

    Here is an example of how you can override the console:
    Code (JavaScript):
    1. console = new function (console) {
    2.   var self = this, dump = [];
    3.  
    4.   function stackTrace() {
    5.     var err = new Error;
    6.     return '\n' + err.stack;
    7.   }
    8.  
    9.   Object.defineProperty(self, 'log', {value: function(message) {
    10.     dump[dump.length] = '[log] ' + message + stackTrace();
    11.     return console['log'].apply(console, arguments);
    12.   }});
    13.  
    14.   Object.defineProperty(self, 'warn', {value: function(message) {
    15.     dump[dump.length] = '[warn] ' + message + stackTrace();
    16.     return console['warn'].apply(console, arguments);
    17.   }});
    18.  
    19.   Object.defineProperty(self, 'error', {value: function(message) {
    20.     dump[dump.length] = '[error] ' + message + stackTrace();
    21.     return console['error'].apply(console, arguments);
    22.   }});
    23.  
    24.   Object.defineProperty(self, 'original', { get: function() { return console; } });
    25.  
    26.   self.dump = function() {
    27.     return dump.join('\n\n');
    28.   };
    29.    
    30.   ['assert', 'clear', 'count', 'dir', 'dirxml', 'group', 'groupCollapsed', 'groupEnd', 'info', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'timeStamp', 'trace'].forEach(function(name) {
    31.     Object.defineProperty(self, name, { value: function() { return console[name].apply(console, arguments); } });
    32.   });
    33. } (console);
    34.  
    35. var Module = {
    36.   TOTAL_MEMORY: 268435456,
    37.   errorhandler: function(err, url, line) {
    38.     var dump = console.dump();
    39.     alert('Console dump with stacktraces (see console for the complete dump):\n\n' +  dump);
    40.     console.original.log(dump);
    41.   },
    42.   compatibilitycheck: null,
    43.   dataUrl: "Release/game.data",
    44.   codeUrl: "Release/game.js",
    45.   memUrl: "Release/game.mem",
    46. };
    47.  
    You can type console.dump() in the browser console while your build is running and you will see the complete console dump with all the stacktraces logged up to the current moment (no need to wait for application to crash). Use console.original.log() in your code to log directly into console bypassing the dump when logging large objects (including the dump itself). You might want to filter the logged information (for example, you don't really need stacktraces for all the events), so that your final report is small enough for sending to the remote server. The code above overrides log, warn and error methods of the original console, but you can use the same idea to override any other method (just remove the duplicate method name from the bottom array as you can not define the property twice). Let me know if you need any help with this.
     
  16. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    Sorry to revive this thread from the dead :) I have implemented a solution similar to the one suggested above - I override the window.console with my own version that does custom processing (if it's an error - sends it to our backend).

    A couple of issues i've seen:

    1. The stack trace isn't included in the console.error call. I have to manually create it using new Error().stacktrace. I wonder if this is what the browser does to display the msg inside its console window ?

    2. The stack is actually not that useful.. I emit a symbol map during the il2cpp build. So for example, for this stack trace i am able to translate what X4b or similar symbols mean. For example:

    X4b:__Z40DebugStringToFilePostprocessedStacktracePKcS0_S0_iS0_iiiiPFvRK11CppLogEntryE

    V4b:__Z17DebugStringToFilePKciS0_iiiiPFvRK11CppLogEntryE

    (what is this class??)
    aar:__ZN23InterfaceActionInvoker4IiP18Object_t3071478659P8String_tP24ObjectU5BU5D_t1108656482E6InvokeEjP11Il2CppClassPviS1_S3_S5_

    The problem is that these do not have any useful names. I cannot even use the symbol map to trace the code back to where it failed.

    My question is -- is there anything further i could do to decipher these stack traces and understand where they are coming from?
     
  17. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    Yes, not all the stacktraces are useful. For example, some errors might originate outside of your C# script. If you are getting "Error: NullReferenceException" and you are able to consistently reproduce it, then you can make a development build with full exception support enabled. This should give you additional information.

    When you are dealing with the Release stacktrace without full exception support, then you might face some limitations. Though there are some hints:
    use the Error.stackTraceLimit = 50; described above, this will give you the complete stacktrace in Chrome,
    function names can be demangled with for example c++filt on mac, i.e.:
    c++filt __Z17DebugStringToFilePKciS0_iiiiPFvRK11CppLogEntryE
    will give you a nicer
    DebugStringToFile(char const*, int, char const*, int, int, int, int, void (*)(CppLogEntry const&))
     
  18. AlexHell

    AlexHell

    Joined:
    Oct 2, 2014
    Posts:
    167
    Sorry for post in old thread.
    I need method for detect unity crash in JS (for example OutOfMemory, but better - all cases) in WebGL. Later we need to post this error to our server, may be with stackTrace (if can be retreived, but minimal data - is event, what can be sent). And I see what this thread related to console.log / error / etc.
    Could someone provide working example of JS code, which can be pasted to html / js in unity, and some instructions, please :)
    Main question: how to subscribe to OOM and other Exceptions and Errors. The code above with "console" class is not explaining how to subscribe to this, and where a callback function to post our request with event to server.

    @liortal
    could you please explain your workflow, if any exist :)
     
    Last edited: Nov 18, 2018
  19. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    Hi, I did not implement this for our game. If you need help with setting it up I can look into it (send me a PM).
     
  20. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    491
    Sorry for necroing this as well, but I'm facing a similar issue.
    In my situation, I have a webGL build of a project that runs without failing in edge and firefox, but throws an exception at startup in chrome. When I rebuild the project to allow for full exception handling with stacktrace, the project simply works. No trace of any exceptions can be found within the console.
    How is this possible, and how can I resolve it, or at least have a clear log of what's going on?
     
    bagelcode likes this.