diff --git a/azure_functions_worker/dispatcher.py b/azure_functions_worker/dispatcher.py index eaf43a66..d00b1dd0 100644 --- a/azure_functions_worker/dispatcher.py +++ b/azure_functions_worker/dispatcher.py @@ -29,7 +29,7 @@ from .logging import disable_console_logging, enable_console_logging from .logging import enable_debug_logging_recommendation from .logging import (logger, error_logger, is_system_log_category, - CONSOLE_LOG_PREFIX) + CONSOLE_LOG_PREFIX, format_exception) from .utils.common import get_app_setting, is_envvar_true from .utils.dependency import DependencyManager from .utils.tracing import marshall_exception_trace @@ -745,7 +745,9 @@ def gen(resp_queue): if ex is grpc_req_stream: # Yes, this is how grpc_req_stream iterator exits. return - error_logger.exception('unhandled error in gRPC thread') + error_logger.exception( + 'unhandled error in gRPC thread. Exception: {0}'.format( + format_exception(ex))) raise diff --git a/azure_functions_worker/logging.py b/azure_functions_worker/logging.py index cd8a0be9..2f701d4b 100644 --- a/azure_functions_worker/logging.py +++ b/azure_functions_worker/logging.py @@ -4,6 +4,7 @@ import logging import logging.handlers import sys +import traceback from typing import Optional # Logging Prefixes @@ -20,6 +21,13 @@ error_handler: Optional[logging.Handler] = None +def format_exception(exception): + msg = str(exception) + "\n" + msg += ''.join(traceback.format_exception( + etype=type(exception), value=exception, tb=exception.__traceback__)) + return msg + + def setup(log_level, log_destination): # Since handler and error_handler are moved to the global scope, # before assigning to these handlers, we should define 'global' keyword diff --git a/azure_functions_worker/main.py b/azure_functions_worker/main.py index 3a7e4441..3edf2840 100644 --- a/azure_functions_worker/main.py +++ b/azure_functions_worker/main.py @@ -36,7 +36,7 @@ def main(): from . import logging from ._thirdparty import aio_compat - from .logging import error_logger, logger + from .logging import error_logger, logger, format_exception args = parse_args() logging.setup(log_level=args.log_level, log_destination=args.log_to) @@ -48,8 +48,10 @@ def main(): try: return aio_compat.run(start_async( args.host, args.port, args.worker_id, args.request_id)) - except Exception: - error_logger.exception('unhandled error in functions worker') + except Exception as ex: + error_logger.exception( + 'unhandled error in functions worker: {0}'.format( + format_exception(ex))) raise