Skip to content
This repository was archived by the owner on Feb 6, 2026. It is now read-only.

Commit c8b0ee8

Browse files
authored
chore: update README (#814)
Add short description about automatic metadata population and redirection of JUL logs to stdout to README. Refactor code by reversing the use of 'appendComma' parameter's value and renaming `populateMetadata?` vars to make the logic more verbose.
1 parent f9bda3d commit c8b0ee8

3 files changed

Lines changed: 68 additions & 9 deletions

File tree

.readme-partials.yaml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,62 @@ custom_content: |
134134
```
135135
com.google.cloud.examples.logging.snippets.AddLoggingHandler.handlers=com.google.cloud.logging.LoggingHandler
136136
```
137+
138+
#### Alternative way to ingest logs in Google Cloud managed environments
139+
140+
If you use Java logger with the Cloud Logging Handler, you can configure the handler to output logs to `stdout` using
141+
the [structured logging Json format](https://cloud.google.com/logging/docs/structured-logging#special-payload-fields).
142+
To do this, add `com.google.cloud.logging.LoggingHandler.redirectToStdout=true` to the logger configuration file.
143+
You can use this configuration when running applications in Google Cloud managed environments such as AppEngine, Cloud Run,
144+
Cloud Function or GKE. The logger agent installed on these environments can capture STDOUT and ingest it into Cloud Logging.
145+
The agent can parse structured logs printed to STDOUT and capture additional log metadata beside the log payload.
146+
The parsed information includes severity, source location, user labels, http request and tracing information.
147+
148+
#### Auto-population of log entrys' metadata
149+
150+
LogEntry object metadata information such as [monitored resource](https://cloud.google.com/logging/docs/reference/v2/rest/v2/MonitoredResource),
151+
[Http request](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#HttpRequest) or
152+
[source location](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogEntrySourceLocation)
153+
are automatically populated with information that the library retrieves from the execution context.
154+
The library populates only empty (set to `null`) LogEntry fields.
155+
This behavior in the `Logging` instance can be opted out via `LoggingOptions`.
156+
Call `LoggingOptions.Builder.setAutoPopulateMetadata(false)` to configure logging options to opt-out the metadata auto-population.
157+
Cloud Logging handler can be configured to opt-out automatic population of the metadata using the logger configuration.
158+
To disable the metadata auto-population add `com.google.cloud.logging.LoggingHandler.autoPopulateMetadata=false`
159+
to the logger configuration file.
160+
161+
The auto-population logic populates source location _only_ for log entries with `Severity.DEBUG` severity.
162+
The execution context of the Http request and tracing information is maintained by `ContextHandler` class.
163+
The context is managed in the scope of the thread.
164+
If you do not use thread pools for multi-threading the `ContextHandler` can be configured to propagate the context
165+
to the scope of the child threads.
166+
To enable this add `com.google.cloud.logging.ContextHandler.useInheritedContext=true` to the logger configuration file.
167+
The library provides two methods to update the context:
168+
169+
* Manually set the context. You can use the following methods of the `Context.Builder` to set the context information.
170+
Use the method `setRequest()` to setup the `HttpRequest` instance or `setRequestUrl()`, `setRequestMethod()`,
171+
`setReferer() `, `setRemoteIp()` and `setServerIp()` to setup the fields of the `HttpRequest`.
172+
The trace and span Ids can be set directly using `setTraceId()` and `setSpanId()` respectively.
173+
Alternatively it can be parsed from the W3C tracing context header using `loadW3CTraceParentContext()` or
174+
from the Google Cloud tracing context header using `loadCloudTraceContext()`.
175+
176+
```java
177+
Context context = Context.newBuilder().setHttpRequest(request).setTrace(traceId).setSpanId(spanId).build();
178+
(new ContextHandler()).setCurrentContext(context);
179+
```
180+
181+
* Using [servlet initializer](https://github.com/googleapis/java-logging-servlet-initializer).
182+
If your application uses a Web server based on Jakarta servlets (e.g. Jetty or Tomcat), you can add the servlet initializer
183+
package to your WAR. The package implements a service provider interface (SPI) for
184+
[javax.servlet.ServletContainerInitializer](https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContainerInitializer.html)
185+
and filters all servlet requests to automatically capture the execution context of the servlet request and store it using
186+
`ContextHandler` class. The stored `Context` class instances are used to populate Http request and tracing information.
187+
If you use Maven, to use the servlet initializer add the following dependency to your BOM:
188+
189+
```xml
190+
<dependency>
191+
<groupId>com.google.cloud</groupId>
192+
<artifactId>google-cloud-logging-servlet-initializer</artifactId>
193+
</dependency>
194+
```
195+

google-cloud-logging/src/main/java/com/google/cloud/logging/LogEntry.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -653,15 +653,15 @@ public StructuredLogFormatter appendField(String name, Object value, boolean app
653653
checkNotNull(name);
654654
if (value != null) {
655655
builder.append(gson.toJson(name)).append(":").append(gson.toJson(value));
656-
if (!appendComma) {
656+
if (appendComma) {
657657
builder.append(",");
658658
}
659659
}
660660
return this;
661661
}
662662

663663
public StructuredLogFormatter appendField(String name, Object value) {
664-
return appendField(name, value, false);
664+
return appendField(name, value, true);
665665
}
666666

667667
/**
@@ -677,7 +677,7 @@ public StructuredLogFormatter appendDict(Map<String, Object> value, boolean appe
677677
// append json object without brackets
678678
if (json.length() > 1) {
679679
builder.append(json.substring(0, json.length() - 1).substring(1));
680-
if (!appendComma) {
680+
if (appendComma) {
681681
builder.append(",");
682682
}
683683
}
@@ -710,10 +710,10 @@ public String toStructuredJsonString() {
710710
.appendField("logging.googleapis.com/trace", trace)
711711
.appendField("logging.googleapis.com/trace_sampled", traceSampled);
712712
if (payload.getType() == Type.STRING) {
713-
formatter.appendField("message", payload.getData(), true);
713+
formatter.appendField("message", payload.getData(), false);
714714
} else if (payload.getType() == Type.JSON) {
715715
Payload.JsonPayload jsonPayload = (Payload.JsonPayload) payload;
716-
formatter.appendDict(jsonPayload.getDataAsMap(), true);
716+
formatter.appendDict(jsonPayload.getDataAsMap(), false);
717717
}
718718
builder.append("}");
719719
return builder.toString();

google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -848,12 +848,12 @@ public void write(Iterable<LogEntry> logEntries, WriteOption... options) {
848848

849849
try {
850850
final Map<Option.OptionType, ?> writeOptions = optionMap(options);
851-
final Boolean populateMetadata1 = getOptions().getAutoPopulateMetadata();
852-
final Boolean populateMetadata2 =
851+
final Boolean logingOptionsPopulateFlag = getOptions().getAutoPopulateMetadata();
852+
final Boolean writeOptionPopulateFlga =
853853
WriteOption.OptionType.AUTO_POPULATE_METADATA.get(writeOptions);
854854

855-
if (populateMetadata2 == Boolean.TRUE
856-
|| (populateMetadata2 == null && populateMetadata1 == Boolean.TRUE)) {
855+
if (writeOptionPopulateFlga == Boolean.TRUE
856+
|| (writeOptionPopulateFlga == null && logingOptionsPopulateFlag == Boolean.TRUE)) {
857857
final MonitoredResource sharedResourceMetadata = RESOURCE.get(writeOptions);
858858
logEntries =
859859
populateMetadata(logEntries, sharedResourceMetadata, this.getClass().getName());

0 commit comments

Comments
 (0)