115115 * Logging (defaults to {@code true}).
116116 * <li>{@code com.google.cloud.logging.LoggingHandler.redirectToStdout} is a boolean flag that
117117 * opts-in redirecting the output of the handler to STDOUT instead of ingesting logs to Cloud
118- * Logging using Logging API (defaults to {@code true }). Redirecting logs can be used in
118+ * Logging using Logging API (defaults to {@code false }). Redirecting logs can be used in
119119 * Google Cloud environments with installed logging agent to delegate log ingestions to the
120120 * agent. Redirected logs are formatted as one line Json string following the structured
121- * logging guidelines.
121+ * logging guidelines. This flag is deprecated; use {@code
122+ * com.google.cloud.logging.LoggingHandler.logTarget} instead.
123+ * <li>{@code com.google.cloud.logging.LoggingHandler.logTarget} is an enumeration controlling log
124+ * routing (defaults to {@code CLOUD_LOGGING}). If set to STDOUT or STDERR, logs will be
125+ * printed to the corresponding stream in the Json format that can be parsed by the logging
126+ * agent. If set to CLOUD_LOGGING, logs will be sent directly to the Google Cloud Logging API.
122127 * </ul>
123128 *
124129 * <p>To add a {@code LoggingHandler} to an existing {@link Logger} and be sure to avoid infinite
@@ -136,6 +141,16 @@ public class LoggingHandler extends Handler {
136141 private static final String LEVEL_NAME_KEY = "levelName" ;
137142 private static final String LEVEL_VALUE_KEY = "levelValue" ;
138143
144+ /** Where to send logs. */
145+ public enum LogTarget {
146+ /** Sends logs to the Cloud Logging API. */
147+ CLOUD_LOGGING ,
148+ /** Sends JSON-formatted logs to stdout, for use with the Google Cloud logging agent. */
149+ STDOUT ,
150+ /** Sends JSON-formatted logs to stderr, for use with the Google Cloud logging agent. */
151+ STDERR
152+ }
153+
139154 private final List <LoggingEnhancer > enhancers ;
140155 private final LoggingOptions loggingOptions ;
141156
@@ -152,7 +167,7 @@ public class LoggingHandler extends Handler {
152167 private volatile Level flushLevel ;
153168
154169 private volatile Boolean autoPopulateMetadata ;
155- private volatile Boolean redirectToStdout ;
170+ private volatile LogTarget logTarget ;
156171
157172 private final WriteOption [] defaultWriteOptions ;
158173
@@ -243,7 +258,13 @@ public LoggingHandler(
243258 Boolean f1 = loggingOptions .getAutoPopulateMetadata ();
244259 Boolean f2 = config .getAutoPopulateMetadata ();
245260 autoPopulateMetadata = isTrueOrNull (f1 ) && isTrueOrNull (f2 );
246- redirectToStdout = firstNonNull (config .getRedirectToStdout (), Boolean .FALSE );
261+ logTarget =
262+ config
263+ .getLogTarget ()
264+ .orElse (
265+ firstNonNull (config .getRedirectToStdout (), Boolean .FALSE )
266+ ? LogTarget .STDOUT
267+ : LogTarget .CLOUD_LOGGING );
247268 String logName = log != null ? log : config .getLogName ();
248269 MonitoredResource resource =
249270 firstNonNull (
@@ -310,18 +331,24 @@ public void publish(LogRecord record) {
310331 if (logEntry != null ) {
311332 try {
312333 Iterable <LogEntry > logEntries =
313- redirectToStdout
314- ? Instrumentation . populateInstrumentationInfo ( ImmutableList .of (logEntry )). y ( )
315- : ImmutableList .of (logEntry );
334+ logTarget == LogTarget . CLOUD_LOGGING
335+ ? ImmutableList .of (logEntry )
336+ : Instrumentation . populateInstrumentationInfo ( ImmutableList .of (logEntry )). y ( );
316337 if (autoPopulateMetadata ) {
317338 logEntries =
318339 logging .populateMetadata (
319340 logEntries , getMonitoredResource (), "com.google.cloud.logging" , "java" );
320341 }
321- if (redirectToStdout ) {
322- logEntries .forEach (log -> System .out .println (log .toStructuredJsonString ()));
323- } else {
324- logging .write (logEntries , defaultWriteOptions );
342+ switch (logTarget ) {
343+ case STDOUT :
344+ logEntries .forEach (log -> System .out .println (log .toStructuredJsonString ()));
345+ break ;
346+ case STDERR :
347+ logEntries .forEach (log -> System .err .println (log .toStructuredJsonString ()));
348+ break ;
349+ case CLOUD_LOGGING :
350+ logging .write (logEntries , defaultWriteOptions );
351+ break ;
325352 }
326353 } catch (RuntimeException ex ) {
327354 getErrorManager ().error (null , ex , ErrorManager .WRITE_FAILURE );
@@ -425,13 +452,37 @@ public Boolean getAutoPopulateMetadata() {
425452 * Enable/disable redirection to STDOUT. If set to {@code true}, logs will be printed to STDOUT in
426453 * the Json format that can be parsed by the logging agent. If set to {@code false}, logs will be
427454 * ingested to Cloud Logging by calling Logging API.
455+ *
456+ * <p>This method is mutually exclusive with {@link #setLogTarget()}.
457+ *
458+ * @deprecated Use {@link #setLogTarget()}.
428459 */
460+ @ Deprecated
429461 public void setRedirectToStdout (boolean value ) {
430- this .redirectToStdout = value ;
462+ this .logTarget = value ? LogTarget . STDOUT : LogTarget . CLOUD_LOGGING ;
431463 }
432464
465+ /*
466+ * @deprecated Use {@link #getLogTarget()}.
467+ */
468+ @ Deprecated
433469 public Boolean getRedirectToStdout () {
434- return redirectToStdout ;
470+ return this .logTarget == LogTarget .STDOUT ;
471+ }
472+
473+ /**
474+ * Configure the destination for ingested logs. If set to STDOUT or STDERR, logs will be printed
475+ * to the corresponding stream in the Json format that can be parsed by the logging agent. If set
476+ * to CLOUD_LOGGING, logs will be sent directly to the Google Cloud Logging API.
477+ *
478+ * <p>This method is mutually exclusive with {@link #setRedirectToStdout()}.
479+ */
480+ public void setLogTarget (LogTarget value ) {
481+ this .logTarget = value ;
482+ }
483+
484+ public LogTarget getLogTarget () {
485+ return logTarget ;
435486 }
436487
437488 /**
0 commit comments