pkout
pkout

Reputation: 6736

AWS Lambda not showing cause Exception stacktrace in Python 3.8

I deployed the following code to an AWS Lambda using runtime Python 3.8.

try:
    raise Exception('my exception')
except Exception as e:
    raise ValueError('my exception 2') from e

In CloudWatch, I expect to see exception chaining like this:

Traceback (most recent call last):
  File "/var/task/handler.py", line 2, in <module>
    raise Exception('my exception')
Exception: my exception

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/var/task/handler.py", line 4, in <module>
    raise ValueError('my exception 2') from e
ValueError: my exception 2

Instead, I see only the first exception reported in CloudWatch like this:

[ERROR] ValueError: my exception 2
Traceback (most recent call last):
  File "/var/task/handler.py", line 21, in pevm_import_budget_file
    raise ValueError('my exception 2') from e

Why isn't the direct cause exception from the from statement showing in the log?

Upvotes: 8

Views: 6383

Answers (2)

pkout
pkout

Reputation: 6736

Another solution that I prefer is printing the stack trace to stderr and raising a generic error so that the program terminates. Example:

import logging, traceback, sys

class ProgramError(Exception):
    def __init__(self, msg='There should be more of exception traceback above.', **kwargs):
        super(ProgramError, self).__init__(msg, **kwargs)


def log_exception():
    exc_type, exc_value, exc_traceback = sys.exc_info()
    logging.error(''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)))


try:
    raise Exception('my exception')
except Exception as e:
    log_exception()
    raise ProgramError()

This produces CloudWatch output like this:

2020-06-02T06:08:57.340000+00:00 2020/06/02/[$LATEST]df0f5bb977b443f9889a809f0d1affa4 START RequestId: e609f118-75d9-4cc7-81fe-44036d492814 Version: $LATEST
2020-06-02T06:08:57.341000+00:00 2020/06/02/[$LATEST]df0f5bb977b443f9889a809f0d1affa4 [ERROR]   2020-06-02T06:08:57.341Z    e609f118-75d9-4cc7-81fe-44036d492814    Traceback (most recent call last):
  File "/var/task/handler.py", line 35, in testfile
    raise Exception('my exception')
Exception: my exception
2020-06-02T06:08:57.342000+00:00 2020/06/02/[$LATEST]df0f5bb977b443f9889a809f0d1affa4 [ERROR] ProgramError: There should be more of exception traceback above.
Traceback (most recent call last):
  File "/var/task/handler.py", line 38, in testfile
    raise ProgramError()
2020-06-02T06:08:57.343000+00:00 2020/06/02/[$LATEST]df0f5bb977b443f9889a809f0d1affa4 END RequestId: e609f118-75d9-4cc7-81fe-44036d492814
2020-06-02T06:08:57.343000+00:00 2020/06/02/[$LATEST]df0f5bb977b443f9889a809f0d1affa4 REPORT RequestId: e609f118-75d9-4cc7-81fe-44036d492814    Duration: 2.71 ms   Billed Duration: 100 ms Memory Size: 256 MB Max Memory Used: 95 MB  Init Duration: 1297.82 ms

If there is a chain of exceptions leading up to Exception, they will get listed and separated by The above exception was the direct cause of the following exception:.

Thank you @Paradigm for the inspiration for this! Hopefully AWS fixes support for from soon so we don't have to do workarounds like this.

Upvotes: 1

Paradigm
Paradigm

Reputation: 2026

The behavior you mention is expected and I have seen the same as well. It seems Lambda does not support chained exceptions currently. However, to get around this, you could add in your own logger to capture the exceptions.

For example, using traceback to retrieve the exception stack:

import traceback

def lambda_handler(event, context):
    try:
        try:
            raise Exception('my exception')
        except Exception as e1:
            raise ValueError('my exception 2')
    except Exception as e2:
        traceback.print_exception(type(e2), value=e2, tb=e2.__traceback__)

    return {}

And the CloudWatch logs look like:

Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 6, in lambda_handler
    raise Exception('my exception')
Exception: my exception

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 8, in lambda_handler
    raise ValueError('my exception 2')
ValueError: my exception 2

Upvotes: 8

Related Questions