Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to cef.ExceptHook #383

Open
cztomczak opened this issue Aug 3, 2017 · 3 comments
Open

Improvements to cef.ExceptHook #383

cztomczak opened this issue Aug 3, 2017 · 3 comments

Comments

@cztomczak
Copy link
Owner

cztomczak commented Aug 3, 2017

Current implementation of cef.ExceptHook has some issues.

During testing on Mac I noticed that exception handler may get called multiple times in some cases. This is because except hook calls some some CEF Python procedures like cef.Shutdown() and these may do subsequent calls to close browser and run some message loop. Except hook should save the original exception message and on subsequent recursive call it should print that message and exit immediately.

Another issue is that after displaying exception message there are still running shutdown procedures that may cause displaying of lots of log messages, thus the original exception message gets lost and you need to scroll and find it. After shutdown procedures have executed the exception message should be displayed once again.

See also Issue #387 ("ExceptHook error file should be configurable").

@cztomczak
Copy link
Owner Author

Recently there were already some fixes to cef.ExceptHook to fix issues with exception message not being displayed at all. See Issue #382 for details.

@cztomczak
Copy link
Owner Author

cztomczak commented Aug 3, 2017

Here is an improved ExceptHook as Python code - can be copied and modified arbitrarily in user's app:

from cefpython3 import cefpython as cef
import traceback
import codecs
import time
import os
import wx

# Globals
g_ExceptHook_called = False
g_ExceptHook_original_msg = ""


def ExceptHook(exc_type, exc_value, exc_trace):
    """Global except hook to exit app cleanly on error.
    This hook does the following: in case of exception write it to
    the "error.log" file, display it to the console, shutdown CEF
    and exit application immediately by ignoring "finally" (_exit()).
    """

    # Sometimes calling CEF shutdown procedures may cause another
    # exception and in such case let's kill the process immediately
    # and display the original exception message.
    global g_ExceptHook_called
    global g_ExceptHook_original_msg
    if g_ExceptHook_called:
        print("[excepthook.py] ExceptHook called recursively, ignoring"
              " and shutting down Python process immediately")
        print("[excepthook.py] Original exception below:")
        print("\n" + g_ExceptHook_original_msg)
        # noinspection PyProtectedMember
        os._exit(1)
        return
    g_ExceptHook_called = True

    # Print exception
    print("[excepthook.py] Catched exception:")
    msg = "".join(traceback.format_exception(exc_type, exc_value,
                                             exc_trace))

    # Log the error to a file
    error_file = cef.GetAppPath("error.log")
    encoding = cef.GetAppSetting("string_encoding") or "utf-8"
    if type(msg) == bytes:
        msg = msg.decode(encoding=encoding, errors="replace")
    try:
        with codecs.open(error_file, mode="a", encoding=encoding) as fp:
            fp.write("\n[%s] %s\n" % (
                    time.strftime("%Y-%m-%d %H:%M:%S"), msg))
    except:
        print("[excepthook.py] WARNING: failed writing to error file: %s" % (
                error_file))

    # Convert error message to ascii before printing, otherwise
    # you may get error like this:
    # | UnicodeEncodeError: 'charmap' codec can't encode characters
    msg = msg.encode("ascii", errors="replace")
    msg = msg.decode("ascii", errors="replace")
    g_ExceptHook_original_msg = msg
    print("\n"+msg)

    # There is a strange bug on Mac. Sometimes except message is not
    # printed if QuitMessageLoop and Shutdown were called before the print
    # message above. See Issue #382 for details.
    print("[excepthook.py] Shutdown CEF processes cleanly")
    cef.QuitMessageLoop()
    cef.Shutdown()

    # Display the exception message once again as the CEF procedures
    # above might have generated lots of logs and the exception message
    # is lost among those. Note that this block of code may not be
    # called in some cases. Sometimes CefShutdown will just exit
    # process immediately. This seems to happen when throwing an error
    # in KeyboardHandler.OnKeyEvent on Mac.
    print("[excepthook.py] Original exception below:")
    print("\n" + msg)

    # Exit process immediately.
    # noinspection PyProtectedMember
    os._exit(1)

@cztomczak
Copy link
Owner Author

On Windows when running pywin32.py example exception message/traceback is not displayed at all, here are the logs:

C:\github\cefpython\examples>python pywin32.py --multi-threaded
[pywin32.py] Message loop mode: CEF multi-threaded (best performance)
[pywin32.py] CEF Python 57.1
[pywin32.py] Python 2.7.13 32bit
[pywin32.py] pywin32 221
[CEF Python] ExceptHook: catched exception, will shutdown CEF

The exception occured during a call to create_browser.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant