Repository navigation
Stream form submission logs to the submission events table - #2326
Merged
Merged
Conversation
CloudWatch Logs batches several log events into one gzipped record, but the Firehose stream needs one JSON object per record. The Lambda is invoked by CloudWatch Logs, maps each event onto the table schema and puts each one to the stream as its own record. An event that cannot be mapped onto the table schema is logged and skipped, so that it does not fail the rest of its batch. If Firehose rejects records the invocation fails; Lambda retries it and then writes it to the error bucket. Co-Authored-By: Claude <noreply@anthropic.com>
The health pipeline will set the transform Lambda's retries and failure destination. The deployer role's Lambda permissions do not include the event invoke config actions. The Lambda's role is already covered by the submission events roles statement. The statement is in forms_infra_1 with the stream's because forms_infra_2 is close to the 6,144 character managed policy limit.
A subscription filter on the forms-runner log group invokes the Lambda with form_submission and form_preview_submission log events, which is what feeds the Firehose stream and so the submission_events table. It takes the second and last subscription filter slot on the log group; the first sends logs to Splunk.
The specs need a Gemfile and spec directory next to the handler, so the archive now packages only transform.rb rather than the whole directory. Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
Cross-service delivery and failed-invocation recovery need end-to-end validation in AWS.
No open issues 🎉
What changed in this PR
Connects forms-runner submission logs to the existing Firehose stream and submission events table.
Changes:
- Adds a CloudWatch Logs subscription and Lambda that emits one record per submission.
- Configures permissions, retries, and failed-invocation storage.
- Adds transformation tests and integrates them into
make spec.
| File | Description |
|---|---|
| Makefile | Runs analytics Lambda specs. |
| infra/modules/deployer-access/policy.tf | Allows managing Lambda invoke configuration. |
| infra/modules/analytics/subscription-filter.tf | Routes submission logs to Lambda. |
| infra/modules/analytics/main.tf | Defines function and source log group names. |
| infra/modules/analytics/lambda/transform.rb | Maps log events and batches Firehose writes. |
| infra/modules/analytics/lambda/spec/transform_spec.rb | Tests mapping, batching, and failure handling. |
| infra/modules/analytics/lambda/spec/spec_helper.rb | Configures SDK stubs and RSpec. |
| infra/modules/analytics/lambda/Gemfile.lock | Locks development and test dependencies. |
| infra/modules/analytics/lambda/Gemfile | Declares development and test dependencies. |
| infra/modules/analytics/lambda/.ruby-version | Pins local Ruby version. |
| infra/modules/analytics/lambda/.gitignore | Ignores vendored dependencies. |
| infra/modules/analytics/lambda.tf | Provisions Lambda, permissions, and failure destination. |
| infra/modules/analytics/error-bucket.tf | Documents Lambda error-bucket usage. |
| infra/modules/analytics/.gitignore | Ignores generated Lambda archives. |
Review effort: Balanced
theseanything
marked this pull request as draft
October 20, 2026 09:17
theseanything
marked this pull request as ready for review
October 20, 2026 14:51
whi-tw
approved these changes
Oct 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What problem does this pull request solve?
The submission events Firehose stream and S3 table are in place, but nothing feeds them yet. This adds a subscription filter on the forms-runner log group that sends
form_submissionandform_preview_submissionevents to a Lambda. The Lambda maps each event onto the table schema and puts it onto the stream as its own record, because Firehose's Iceberg destination accepts only one JSON object per record.If Firehose rejects records, the invocation fails. Lambda retries it twice, then writes it to the analytics error bucket. Retries and CloudWatch Logs' at-least-once delivery mean the table can contain duplicates, so queries should count distinct
submission_referencevalues. Submissions to preview and test forms are kept and should be excluded at query time.This filter uses the second and last subscription filter slot on the forms-runner log group; the first sends logs to Splunk.
Replaces #2313.
Things to consider when reviewing
Reminders
If you've made changes to the deployer role (files in
modules/deployer-access):make <environment> forms/account applyon the relevant environments (dev,stagingand/orprod)apply-forms-terraform-<environment>pipelines have run successfully