Dump lambda function output
@@ -47,6 +47,61 @@ def _container_names_by_prefix(prefix: str) -> List[str]:
return containers
+def _lambda_names() -> List[str]:
+ """
+ Return the names of the lambdas that are running in our Localstack instance.
+ """
+
+ # All Localstack lambda containers begin with this prefix; what
+ # remains is the actual lambda's name.
+ #
+ # We always use the us-east-1 region, and don't change the account
+ # ID from Localstack's default of 000000000000; if that ever
+ # changes, this prefix would need to be changed accordingly.
+ lambda_container_prefix="localstack_lambda_arn_aws_lambda_us-east-1_000000000000_function_"
+ containers=_container_names_by_prefix(lambda_container_prefix)
+
+ # Chop off the prefix to get just the names of the lambda functions
+ return [name.replace(lambda_container_prefix, "") for name in containers ]
+
+
+def _dump_lambda_log(lambda_name: str, dir: Path) -> None:
+ """Dump the Cloudwatch logs of the given lambda function from Localstack.
+
+ Requires the AWS CLI to be present, and assumes a running
+ Localstack instance is available at http://localhost:4566.
+
+ These same logs are also available in the Localstack container's
+ log output, but mixed in with the logs of every other lambda. By
+ using this function, we can isolate them.
+
+ Note, however, that these logs will be only what the lambda
+ function itself outputs during its execution. There will still be
+ important information in the Localstack logs concerning how the
+ functions are *invoked* that may be useful in debugging issues.
+
+ """
+ destination = dir / f"{lambda_name}_lambda.log"
+ logging.info(f"Dumping logs for '{lambda_name}' lambda function to '{destination}'")
+ with open(destination, "wb") as out_stream:
+ subprocess.run(
+ [
+ "aws",
+ "--endpoint-url=http://localhost:4566",
+ "logs",
+ "tail",
+ f"/aws/lambda/{lambda_name}"
+ ],
+ stdout=out_stream,
+ env={
+ "PATH": os.environ["PATH"],
+ # "test" is the value assumed by Localstack
+ "AWS_ACCESS_KEY_ID": "test",
+ "AWS_SECRET_ACCESS_KEY": "test"
+ }
+ )
+
+
def _dump_docker_log(container_name: str, dir: Path) -> None:
"""
run `docker logs` and dump to $DIR/$CONTAINER_NAME.log
@@ -73,6 +128,8 @@ def dump_all_logs(compose_project: str) -> None:
os.makedirs(ARTIFACTS_PATH, exist_ok=True)
for container in containers:
_dump_docker_log(container_name=container, dir=ARTIFACTS_PATH)
+ for lambda_fn in _lambda_names():
+ _dump_lambda_log(lambda_fn, dir=ARTIFACTS_PATH)
def dump_volume(compose_project: Optional[str], volume_name: str) -> None:
