Structured JSON logging for Starlette on Google Cloud Run
Project description
starlette-gcp-logging
Structured JSON logging for Starlette services running on Google Cloud Run (or any GCP compute platform).
Provides two components that work together:
GCPFormatter— alogging.Formatterthat serialises every log record as a single-line JSON object understood by Cloud Logging, including severity mapping, source location, and trace/span correlation.GCPRequestLoggingMiddleware— a Starlette middleware that emits one structured log entry per request/response (withhttpRequestmetadata) and propagates trace context to every logger used inside that request viacontextvars— no manual plumbing needed.
Installation
pip install starlette-gcp-logging
Quick start
import logging
from starlette.applications import Starlette
import starlette_gcp_logging
# Wire up the formatter once at startup — all loggers inherit it.
handler = logging.StreamHandler()
handler.setFormatter(starlette_gcp_logging.GCPFormatter()) # project_id auto-detected on GCP
logging.basicConfig(handlers=[handler], level=logging.INFO)
app = Starlette(...)
app.add_middleware(starlette_gcp_logging.GCPRequestLoggingMiddleware)
With uvicorn:
uvicorn myapp:app --log-config /dev/null # let GCPFormatter own the output
Configuration
GCPFormatter(project_id="")
| Parameter | Description |
|---|---|
project_id |
GCP project ID used to build the full trace resource name projects/<id>/traces/<trace_id>. When omitted (the default) it is fetched automatically from the GCP instance metadata server on the first log call and cached for the lifetime of the process. Outside GCP the trace is still written — just without the project prefix. |
Log record fields emitted
| JSON key | Value |
|---|---|
severity |
DEBUG / INFO / WARNING / ERROR / CRITICAL |
message |
Formatted log message |
time |
RFC 3339 UTC timestamp |
logging.googleapis.com/sourceLocation |
file, line, function |
logging.googleapis.com/trace |
Full trace resource name (when a trace ID is present) |
logging.googleapis.com/spanId |
16-char hex span ID |
logging.googleapis.com/traceSampled |
Boolean sampling flag |
exception |
Formatted traceback (when exc_info is set) |
@type |
GCP Error Reporting type URI (when exc_info is set) |
| (extra keys) | Any fields passed via extra={...} to the logger |
GCPRequestLoggingMiddleware(app, *, project_id="", logger_name=..., default_level=logging.INFO)
| Parameter | Description |
|---|---|
project_id |
Same as GCPFormatter. Auto-detected when omitted. |
logger_name |
Logger to write request entries to. Defaults to starlette_gcp_logging.middleware. |
default_level |
Log level for 1xx/2xx/3xx responses. 4xx → WARNING; 5xx → ERROR. |
Trace context extraction
The middleware reads incoming trace headers in this priority order:
traceparent(W3C / OpenTelemetry) — used when an upstream service propagates its own trace. Cloud Run appends its own span to this header, so it is always preferred when present.X-Cloud-Trace-Context— GCP's own header, injected when there is no upstreamtraceparent.
The extracted trace ID and span ID are stored in contextvars for the
duration of the request, so every logger in the call stack automatically picks
them up without any explicit propagation.
Accessing trace context manually
from starlette_gcp_logging import formatter
# Inside a request handler:
print(formatter.request_trace.get()) # "projects/my-project/traces/abc123..."
print(formatter.request_span.get()) # "00f067aa0ba902b7"
Project ID auto-detection
from starlette_gcp_logging import _metadata
project = _metadata.get_project_id() # fetches from metadata server, then cached
Outside GCP (local dev, CI) the metadata request times out after 1 second and an empty string is returned — logging continues to work, just without the project prefix in the trace resource name.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file starlette_gcp_logging-0.0.1-py3-none-any.whl.
File metadata
- Download URL: starlette_gcp_logging-0.0.1-py3-none-any.whl
- Upload date:
- Size: 10.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f250a6bf343e3de2a124e6d3ec85e850bbb60b626e0acc8da14325e65c31580c
|
|
| MD5 |
d0d7c127ae81d649b83e12f319101bca
|
|
| BLAKE2b-256 |
2f0e9554ad8109077d7ee6d686a75d82ee86d5826cb605e60ce91767a316b1fd
|
Provenance
The following attestation bundles were made for starlette_gcp_logging-0.0.1-py3-none-any.whl:
Publisher:
release.yml on DelfinaCare/starlette-gcp-logging
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
starlette_gcp_logging-0.0.1-py3-none-any.whl -
Subject digest:
f250a6bf343e3de2a124e6d3ec85e850bbb60b626e0acc8da14325e65c31580c - Sigstore transparency entry: 1280045637
- Sigstore integration time:
-
Permalink:
DelfinaCare/starlette-gcp-logging@29336a4e7ebbaa186db45d46bb3b4b98ecd360ff -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/DelfinaCare
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@29336a4e7ebbaa186db45d46bb3b4b98ecd360ff -
Trigger Event:
release
-
Statement type: