Event Logging
Architecture
Request flow and component boundaries for Event Logging
Event Logging is a narrow ConnectRPC service with a write-first execution path: normalize the request, persist one Spanner row, then optionally forward the accepted event to Statsig.
System context
Internal caller
-> Cloud Run IAM
-> Event Logging (ConnectRPC / ASGI)
-> Protovalidate request checks
-> Request normalization
-> Spanner NestEventLog write
-> Optional Statsig forward
-> Existing export path to BigQuery / SigmaRequest flow
- A caller invokes
events.v1.EventLoggingService/LogEvent. - Cloud Run IAM authenticates the request before it reaches the app.
AuthInterceptorextractsx-goog-authenticated-user-*headers into caller context for service-managed audit metadata and logs.ProtoValidationInterceptorenforces protobuf-level rules such as required event name and max top-level metadata keys.normalize_log_event_request()trims strings, resolves caller-suppliedevent_typeandactor_id, defaultsevent_ts, generates a service-ownedevent_id, reserves_eventLog, and enforces the 64 KiB serialized metadata cap.SpannerEventLogRepositorywrites a single row toNestEventLog, storing request-backedevent_typeandactor_idwhen present.- If
forward_to_statsigresolved totrue, the service forwards the stored event to Statsig using a stable service principal (service:eventsby default). - The handler returns the generated
event_idonly when the whole operation succeeds.
Key design choices
event_idis service-generated, not caller-supplied. The current implementation uses UUID strings that fit theSTRING(36)table key.event_tsandingested_atmean different things.event_tsis logical event time;ingested_atis write time.- Auth-derived caller identity and request-supplied
actor_idare distinct. The request field populates the row column, while the interceptor populates_eventLog.callerfor audit context. - Statsig forwarding is a side effect after persistence, not part of the write transaction.
- Internal-only access is enforced outside the app. The interceptor records caller identity, but the auth gate is Cloud Run IAM.
Main components
services/events/main.py: ASGI entrypoint and lifespan bridge.services/events/core/runtime.py: managed Spanner and Statsig dependencies.services/events/core/handlers/event_logging_handler.py: thin Connect handler.services/events/core/service.py: write-first orchestration.services/events/core/normalization.py: request-to-domain normalization.services/events/core/repository.py: Spanner repository.services/events/core/adapters/statsig_forwarder.py: Statsig client and payload mapping.
Last updated on