cloud-logging is a multi-module Gradle project providing JVM logging libraries for GCP and Azure, built on SLF4J 2, Logback, and Logback Logstash. It is not a generic logging library — it is specifically designed to produce structured JSON logs consumed by GCP Cloud Logging (via Fluentbit) and Azure Monitor.
# Build all modules
./gradlew build
# Run tests
./gradlew test
# Build a single module (example)
./gradlew :gcp:spring-boot-starter-gcp-web:build
# Check for dependency updates
./gradlew dependencyUpdatesapi/– SLF4JLogger-wrapper (DevOpsLogger) with additional severity levels:errorTellMeTomorrow,errorInterruptMyDinner,errorWakeMeUpRightNowappender/– Core Logback async appender with MDC support and on-demand logging scopegcp/– GCP-specific Spring Boot starters, autoconfiguration, and Stackdriver/Cloud Logging encoderazure/– Azure-specific Spring Boot starters, autoconfiguration, and Azure Monitor encoderrequest-response/– Logbook-based for REST services. Custom gRPC request/response logging.on-demand/– Selective on-demand logging: caches log statements per request and only emits them for failed/slow/flagged requeststrace/– Correlation-id and MDC tracing for HTTP and gRPCmicrometer/– Log severity metrics (GCP and Azure variants)test/– Test utilities: Logback test configuration, JUnit 5 extensionsexamples/– Runnable Spring Boot example applications (web and gRPC, GCP and Azure)bom/– Bill of Materials for consumer dependency management
The gcp/ and azure/ modules are mirrors of each other in structure and feature set. When adding a feature to one, add the equivalent to the other.
Dependency versions are managed centrally in the root build.gradle ext block. The Spring Boot BOM controls most transitive dependency versions (JUnit, Mockito, SLF4J, Logback, Jackson, Micrometer), and non-BOM dependency versions (e.g. logbackLogstashVersion, logbookVersion) are defined explicitly there. Example subprojects (examples/*) may declare plugin versions locally; library subprojects must not.
- Java with Spring Boot 4.x (not 3.x) and Java 25.
- Gradle multi-project build; module names declared in
settings.gradle - Tests use JUnit 5 and Google Truth (
com.google.truth) assertions — not AssertJ or Hamcrest - Machine-readable single-line JSON is the production log format; human-readable formats are test-scope only
- Test artifacts (e.g.
spring-boot-starter-gcp-web-test) must always be added alongside their production counterpart — they configure human-readable output for local development - Never add a
logback.xmlorlogback-spring.xmlmanually — the starters provide these via classpath resources; a second file causes undefined behaviour - Log levels are configured via Spring properties (
logging.level.root,logging.level.<package>)
Logs are written as JSON to stdout/stderr. Fluentbit on GKE forwards them to Cloud Logging as jsonPayload. The encoder (StackdriverLogstashEncoder) maps:
- SLF4J level →
severityfield (notlevel) — recognized by Cloud Logging for log severity filtering messagefield — includes stack traces inline- MDC keys → top-level JSON fields (or OpenTelemetry trace fields
logging.googleapis.com/trace,logging.googleapis.com/spanIdif OTel is on classpath) serviceContext.service— populated fromHOSTNAMEenvironment variable
Important GCP constraints (Fluentbit quirks; lsit is not exhaustive):
- Duplicate field names in
jsonPayloadcause Fluentbit to drop 2–4 seconds of logs from all pods — avoid emitting the same key twice in one log event - Log lines exceeding 256 KB are dropped — truncate large payloads
- Avoid using reserved field names (
message,timestamp) as structured argument keys
External docs:
- GCP Structured Logging
- GCP LogEntry reference
- GCP Log severity levels
- GCP Error Reporting log format
Logs are written as JSON to stdout/stderr and ingested by the Azure Monitor agent. The encoder (AzureLogstashEncoder) adds a serviceContext field populated from the HOSTNAME environment variable.
External docs:
- Azure Monitor Logs overview
- Azure Monitor log standard columns
- Application Insights structured logging
On-demand logging is disabled by default. It must be explicitly enabled:
entur.logging.http.ondemand.enabled=true # for web
entur.logging.grpc.ondemand.enabled=true # for gRPC
It caches all log statements per request and either discards them (happy path) or emits them (failure/slow/debug path). Failure triggers are configurable: HTTP status code, log level, call duration, or a specific HTTP/gRPC header.
- Always test against machine-readable JSON output under the hood, even when the console shows human-readable format during development
- Use
CompositeConsoleOutputControlto toggle output mode within a test:try (Closeable c = CompositeConsoleOutputControl.useHumanReadableJsonEncoder()) { // test code }
- JUnit 5 extensions and Logback test utilities are in
test/test-logback-junit
- Create the module directory and
build.gradle - Register it in
settings.gradleunder the appropriate group (include 'gcp:my-new-module') - If platform-specific, add the equivalent module for the other cloud platform
- Add it to
bom/build.gradleif it is a consumer-facing artifact