prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [FEATURE] Print full stacktrace on error
  See discussion on [discussion forum](https://discourse.bokeh.org/t/debugging-recommendations/3934)
  
  **Is your feature request related to a problem? Please describe.**
  My underlying application is getting very big and when running into problems the debugging takes me a lot of time. 
  
  For example I now just get the line:
  2019-08-26 13:57:29,620 error handling message Message ‘EVENT’ (revision 1) content: ‘{“event_name”:“button_click”,“event_values”:{“model_id”:“1027”}}’: ValueError(‘Wrong number of items passed 2, placement implies 1’)
  
  **Describe the solution you'd like**
  My desired solution is to see the stacktrace which includes the file and line of the source of the error.
  
  @bryevdv pointed me to the protocol_handler.py script
  
  **Describe alternatives you've considered**
  The alternative is to set debug level, but I only want error handling improved, not have a full log. Also, I want the error to show directly, because I may not know how to reproduce it on a running server.
  
  PR created
  
  **Additional context**
  I am not worried about the log getting too long. Errors should in general not occur, they should be fixed or at least be caught in case they are acceptable
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `bokeh/server/protocol_handler.py`
  Content:
  ```
  1 #-----------------------------------------------------------------------------
  2 # Copyright (c) 2012 - 2019, Anaconda, Inc., and Bokeh Contributors.
  3 # All rights reserved.
  4 #
  5 # The full license is in the file LICENSE.txt, distributed with this software.
  6 #-----------------------------------------------------------------------------
  7 ''' Encapsulate handling of all Bokeh Protocol messages a Bokeh server may
  8 receive.
  9 
  10 '''
  11 
  12 #-----------------------------------------------------------------------------
  13 # Boilerplate
  14 #-----------------------------------------------------------------------------
  15 from __future__ import absolute_import, division, print_function, unicode_literals
  16 
  17 import logging
  18 log = logging.getLogger(__name__)
  19 
  20 #-----------------------------------------------------------------------------
  21 # Imports
  22 #-----------------------------------------------------------------------------
  23 
  24 # Standard library imports
  25 
  26 # External imports
  27 from tornado import gen
  28 
  29 # Bokeh imports
  30 from .session import ServerSession
  31 from ..protocol.exceptions import ProtocolError
  32 
  33 #-----------------------------------------------------------------------------
  34 # Globals and constants
  35 #-----------------------------------------------------------------------------
  36 
  37 __all__ = (
  38     'ProtocolHandler',
  39 )
  40 
  41 #-----------------------------------------------------------------------------
  42 # General API
  43 #-----------------------------------------------------------------------------
  44 
  45 class ProtocolHandler(object):
  46     ''' A Bokeh server may be expected to receive any of the following protocol
  47     messages:
  48 
  49     * ``EVENT``
  50     * ``PATCH-DOC``
  51     * ``PULL-DOC-REQ``
  52     * ``PUSH-DOC``
  53     * ``SERVER-INFO-REQ``
  54 
  55     The job of ``ProtocolHandler`` is to direct incoming messages to the right
  56     specialized handler for each message type. When the server receives a new
  57     message on a connection it will call ``handler`` with the message and the
  58     connection that the message arrived on. Most messages are ultimately
  59     handled by the ``ServerSession`` class, but some simpler messages types
  60     such as ``SERVER-INFO-REQ`` may be handled directly by ``ProtocolHandler``.
  61 
  62     Any unexpected messages will result in a ``ProtocolError``.
  63 
  64     '''
  65 
  66     def __init__(self):
  67         self._handlers = dict()
  68 
  69         self._handlers['PULL-DOC-REQ'] = ServerSession.pull
  70         self._handlers['PUSH-DOC'] = ServerSession.push
  71         self._handlers['PATCH-DOC'] = ServerSession.patch
  72         self._handlers['SERVER-INFO-REQ'] = self._server_info_req
  73         self._handlers['EVENT'] = ServerSession.event
  74 
  75     @gen.coroutine
  76     def handle(self, message, connection):
  77         ''' Delegate a received message to the appropriate handler.
  78 
  79         Args:
  80             message (Message) :
  81                 The message that was receive that needs to be handled
  82 
  83             connection (ServerConnection) :
  84                 The connection that received this message
  85 
  86         Raises:
  87             ProtocolError
  88 
  89         '''
  90 
  91         handler = self._handlers.get((message.msgtype, message.revision))
  92 
  93         if handler is None:
  94             handler = self._handlers.get(message.msgtype)
  95 
  96         if handler is None:
  97             raise ProtocolError("%s not expected on server" % message)
  98 
  99         try:
  100             work = yield handler(message, connection)
  101         except Exception as e:
  102             log.error("error handling message %r: %r", message, e)
  103             log.debug("  message header %r content %r", message.header, message.content, exc_info=1)
  104             work = connection.error(message, repr(e))
  105         raise gen.Return(work)
  106 
  107     @gen.coroutine
  108     def _server_info_req(self, message, connection):
  109         raise gen.Return(connection.protocol.create('SERVER-INFO-REPLY', message.header['msgid']))
  110 
  111 #-----------------------------------------------------------------------------
  112 # Dev API
  113 #-----------------------------------------------------------------------------
  114 
  115 #-----------------------------------------------------------------------------
  116 # Private API
  117 #-----------------------------------------------------------------------------
  118 
  119 #-----------------------------------------------------------------------------
  120 # Code
  121 #-----------------------------------------------------------------------------
  122
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/bokeh/server/protocol_handler.py b/bokeh/server/protocol_handler.py
  --- a/bokeh/server/protocol_handler.py
  +++ b/bokeh/server/protocol_handler.py
  @@ -99,8 +99,8 @@
           try:
               work = yield handler(message, connection)
           except Exception as e:
  -            log.error("error handling message %r: %r", message, e)
  -            log.debug("  message header %r content %r", message.header, message.content, exc_info=1)
  +            log.error("error handling message\n message: %r \n error: %r",
  +                      message, e, exc_info=True)
               work = connection.error(message, repr(e))
           raise gen.Return(work)
  
verification_info: {"golden_diff": "diff --git a/bokeh/server/protocol_handler.py b/bokeh/server/protocol_handler.py\n--- a/bokeh/server/protocol_handler.py\n+++ b/bokeh/server/protocol_handler.py\n@@ -99,8 +99,8 @@\n         try:\n             work = yield handler(message, connection)\n         except Exception as e:\n-            log.error(\"error handling message %r: %r\", message, e)\n-            log.debug(\"  message header %r content %r\", message.header, message.content, exc_info=1)\n+            log.error(\"error handling message\\n message: %r \\n error: %r\",\n+                      message, e, exc_info=True)\n             work = connection.error(message, repr(e))\n         raise gen.Return(work)\n", "issue": "[FEATURE] Print full stacktrace on error\nSee discussion on [discussion forum](https://discourse.bokeh.org/t/debugging-recommendations/3934)\r\n\r\n**Is your feature request related to a problem? Please describe.**\r\nMy underlying application is getting very big and when running into problems the debugging takes me a lot of time. \r\n\r\nFor example I now just get the line:\r\n2019-08-26 13:57:29,620 error handling message Message \u2018EVENT\u2019 (revision 1) content: \u2018{\u201cevent_name\u201d:\u201cbutton_click\u201d,\u201cevent_values\u201d:{\u201cmodel_id\u201d:\u201c1027\u201d}}\u2019: ValueError(\u2018Wrong number of items passed 2, placement implies 1\u2019)\r\n\r\n**Describe the solution you'd like**\r\nMy desired solution is to see the stacktrace which includes the file and line of the source of the error.\r\n\r\n@bryevdv pointed me to the protocol_handler.py script\r\n\r\n**Describe alternatives you've considered**\r\nThe alternative is to set debug level, but I only want error handling improved, not have a full log. Also, I want the error to show directly, because I may not know how to reproduce it on a running server.\r\n\r\nPR created\r\n\r\n**Additional context**\r\nI am not worried about the log getting too long. Errors should in general not occur, they should be fixed or at least be caught in case they are acceptable\n", "before_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2019, Anaconda, Inc., and Bokeh Contributors.\n# All rights reserved.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n#-----------------------------------------------------------------------------\n''' Encapsulate handling of all Bokeh Protocol messages a Bokeh server may\nreceive.\n\n'''\n\n#-----------------------------------------------------------------------------\n# Boilerplate\n#-----------------------------------------------------------------------------\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport logging\nlog = logging.getLogger(__name__)\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\n# Standard library imports\n\n# External imports\nfrom tornado import gen\n\n# Bokeh imports\nfrom .session import ServerSession\nfrom ..protocol.exceptions import ProtocolError\n\n#-----------------------------------------------------------------------------\n# Globals and constants\n#-----------------------------------------------------------------------------\n\n__all__ = (\n    'ProtocolHandler',\n)\n\n#-----------------------------------------------------------------------------\n# General API\n#-----------------------------------------------------------------------------\n\nclass ProtocolHandler(object):\n    ''' A Bokeh server may be expected to receive any of the following protocol\n    messages:\n\n    * ``EVENT``\n    * ``PATCH-DOC``\n    * ``PULL-DOC-REQ``\n    * ``PUSH-DOC``\n    * ``SERVER-INFO-REQ``\n\n    The job of ``ProtocolHandler`` is to direct incoming messages to the right\n    specialized handler for each message type. When the server receives a new\n    message on a connection it will call ``handler`` with the message and the\n    connection that the message arrived on. Most messages are ultimately\n    handled by the ``ServerSession`` class, but some simpler messages types\n    such as ``SERVER-INFO-REQ`` may be handled directly by ``ProtocolHandler``.\n\n    Any unexpected messages will result in a ``ProtocolError``.\n\n    '''\n\n    def __init__(self):\n        self._handlers = dict()\n\n        self._handlers['PULL-DOC-REQ'] = ServerSession.pull\n        self._handlers['PUSH-DOC'] = ServerSession.push\n        self._handlers['PATCH-DOC'] = ServerSession.patch\n        self._handlers['SERVER-INFO-REQ'] = self._server_info_req\n        self._handlers['EVENT'] = ServerSession.event\n\n    @gen.coroutine\n    def handle(self, message, connection):\n        ''' Delegate a received message to the appropriate handler.\n\n        Args:\n            message (Message) :\n                The message that was receive that needs to be handled\n\n            connection (ServerConnection) :\n                The connection that received this message\n\n        Raises:\n            ProtocolError\n\n        '''\n\n        handler = self._handlers.get((message.msgtype, message.revision))\n\n        if handler is None:\n            handler = self._handlers.get(message.msgtype)\n\n        if handler is None:\n            raise ProtocolError(\"%s not expected on server\" % message)\n\n        try:\n            work = yield handler(message, connection)\n        except Exception as e:\n            log.error(\"error handling message %r: %r\", message, e)\n            log.debug(\"  message header %r content %r\", message.header, message.content, exc_info=1)\n            work = connection.error(message, repr(e))\n        raise gen.Return(work)\n\n    @gen.coroutine\n    def _server_info_req(self, message, connection):\n        raise gen.Return(connection.protocol.create('SERVER-INFO-REPLY', message.header['msgid']))\n\n#-----------------------------------------------------------------------------\n# Dev API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Private API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Code\n#-----------------------------------------------------------------------------\n", "path": "bokeh/server/protocol_handler.py"}], "after_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2012 - 2019, Anaconda, Inc., and Bokeh Contributors.\n# All rights reserved.\n#\n# The full license is in the file LICENSE.txt, distributed with this software.\n#-----------------------------------------------------------------------------\n''' Encapsulate handling of all Bokeh Protocol messages a Bokeh server may\nreceive.\n\n'''\n\n#-----------------------------------------------------------------------------\n# Boilerplate\n#-----------------------------------------------------------------------------\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport logging\nlog = logging.getLogger(__name__)\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\n# Standard library imports\n\n# External imports\nfrom tornado import gen\n\n# Bokeh imports\nfrom .session import ServerSession\nfrom ..protocol.exceptions import ProtocolError\n\n#-----------------------------------------------------------------------------\n# Globals and constants\n#-----------------------------------------------------------------------------\n\n__all__ = (\n    'ProtocolHandler',\n)\n\n#-----------------------------------------------------------------------------\n# General API\n#-----------------------------------------------------------------------------\n\nclass ProtocolHandler(object):\n    ''' A Bokeh server may be expected to receive any of the following protocol\n    messages:\n\n    * ``EVENT``\n    * ``PATCH-DOC``\n    * ``PULL-DOC-REQ``\n    * ``PUSH-DOC``\n    * ``SERVER-INFO-REQ``\n\n    The job of ``ProtocolHandler`` is to direct incoming messages to the right\n    specialized handler for each message type. When the server receives a new\n    message on a connection it will call ``handler`` with the message and the\n    connection that the message arrived on. Most messages are ultimately\n    handled by the ``ServerSession`` class, but some simpler messages types\n    such as ``SERVER-INFO-REQ`` may be handled directly by ``ProtocolHandler``.\n\n    Any unexpected messages will result in a ``ProtocolError``.\n\n    '''\n\n    def __init__(self):\n        self._handlers = dict()\n\n        self._handlers['PULL-DOC-REQ'] = ServerSession.pull\n        self._handlers['PUSH-DOC'] = ServerSession.push\n        self._handlers['PATCH-DOC'] = ServerSession.patch\n        self._handlers['SERVER-INFO-REQ'] = self._server_info_req\n        self._handlers['EVENT'] = ServerSession.event\n\n    @gen.coroutine\n    def handle(self, message, connection):\n        ''' Delegate a received message to the appropriate handler.\n\n        Args:\n            message (Message) :\n                The message that was receive that needs to be handled\n\n            connection (ServerConnection) :\n                The connection that received this message\n\n        Raises:\n            ProtocolError\n\n        '''\n\n        handler = self._handlers.get((message.msgtype, message.revision))\n\n        if handler is None:\n            handler = self._handlers.get(message.msgtype)\n\n        if handler is None:\n            raise ProtocolError(\"%s not expected on server\" % message)\n\n        try:\n            work = yield handler(message, connection)\n        except Exception as e:\n            log.error(\"error handling message\\n message: %r \\n error: %r\",\n                      message, e, exc_info=True)\n            work = connection.error(message, repr(e))\n        raise gen.Return(work)\n\n    @gen.coroutine\n    def _server_info_req(self, message, connection):\n        raise gen.Return(connection.protocol.create('SERVER-INFO-REPLY', message.header['msgid']))\n\n#-----------------------------------------------------------------------------\n# Dev API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Private API\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Code\n#-----------------------------------------------------------------------------\n", "path": "bokeh/server/protocol_handler.py"}]}