describe-stack-events returns a stack's events newest first (Stack Events); reverse() in the query turns them into a timeline. The events of the stack created above:
aws cloudformation describe-stack-events --stack-name booknest-catalog --output text \
--query 'reverse(StackEvents)[].[Timestamp,LogicalResourceId,ResourceStatus]' | cut -c12-17:45:54.482757+00:00 booknest-catalog CREATE_IN_PROGRESS 17:45:54.483404+00:00 BooksTable CREATE_IN_PROGRESS 17:45:57.643687+00:00 BooksTable CREATE_COMPLETE 17:45:57.644089+00:00 booknest-catalog CREATE_COMPLETE
The table took a few seconds on LocalStack 63,725 (timestamps are UTC, cut to the time of day); on AWS 24 a table takes seconds too, and a VPC with a NAT gateway minutes. The wait subcommands poll every 30 seconds for up to an hour, so they add up to 30 seconds after a fast operation. When a stack fails, filter for the cause: --query "StackEvents[?ends_with(ResourceStatus,'FAILED')].[LogicalResourceId,ResourceStatusReason]" and read the oldest failure, since later ones are consequences. A --client-request-token you pass is copied into every event of that operation, which ties events to a pipeline run.