blob: 701087ae1dff229b8891780009458f63f28b8ee3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.beam.sdk.options;
import static org.apache.beam.vendor.guava.v20_0.com.google.common.base.Preconditions.checkNotNull;
import com.fasterxml.jackson.annotation.JsonCreator;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.beam.sdk.annotations.Experimental;
/** Options that are used to control configuration of the SDK harness. */
@Experimental
@Description("Options that are used to control configuration of the SDK harness.")
public interface SdkHarnessOptions extends PipelineOptions {
/** The set of log levels that can be used in the SDK harness. */
enum LogLevel {
/** Special level used to turn off logging. */
OFF,
/** LogLevel for logging error messages. */
ERROR,
/** LogLevel for logging warning messages. */
WARN,
/** LogLevel for logging informational messages. */
INFO,
/** LogLevel for logging diagnostic messages. */
DEBUG,
/** LogLevel for logging tracing messages. */
TRACE
}
/** This option controls the default log level of all loggers without a log level override. */
@Description("Controls the default log level of all loggers without a log level override.")
@Default.Enum("INFO")
LogLevel getDefaultSdkHarnessLogLevel();
void setDefaultSdkHarnessLogLevel(LogLevel logLevel);
/**
* This option controls the log levels for specifically named loggers.
*
* <p>Later options with equivalent names override earlier options.
*
* <p>See {@link SdkHarnessLogLevelOverrides} for more information on how to configure logging on
* a per {@link Class}, {@link Package}, or name basis. If used from the command line, the
* expected format is {"Name":"LogLevel",...}, further details on {@link
* SdkHarnessLogLevelOverrides#from}.
*/
@Description(
"This option controls the log levels for specifically named loggers. "
+ "The expected format is {\"Name\":\"LogLevel\",...}. The SDK harness supports a logging "
+ "hierarchy based off of names that are '.' separated. For example, by specifying the value "
+ "{\"a.b.c.Foo\":\"DEBUG\"}, the logger for the class 'a.b.c.Foo' will be configured to "
+ "output logs at the DEBUG level. Similarly, by specifying the value {\"a.b.c\":\"WARN\"}, "
+ "all loggers underneath the 'a.b.c' package will be configured to output logs at the WARN "
+ "level. System.out and System.err levels are configured via loggers of the corresponding "
+ "name. Also, note that when multiple overrides are specified, the exact name followed by "
+ "the closest parent takes precedence.")
SdkHarnessLogLevelOverrides getSdkHarnessLogLevelOverrides();
void setSdkHarnessLogLevelOverrides(SdkHarnessLogLevelOverrides value);
/**
* Defines a log level override for a specific class, package, or name.
*
* <p>The SDK harness supports a logging hierarchy based off of names that are "." separated. It
* is a common pattern to have the logger for a given class share the same name as the class
* itself. Given the classes {@code a.b.c.Foo}, {@code a.b.c.Xyz}, and {@code a.b.Bar}, with
* loggers named {@code "a.b.c.Foo"}, {@code "a.b.c.Xyz"}, and {@code "a.b.Bar"} respectively, we
* can override the log levels:
*
* <ul>
* <li>for {@code Foo} by specifying the name {@code "a.b.c.Foo"} or the {@link Class}
* representing {@code a.b.c.Foo}.
* <li>for {@code Foo}, {@code Xyz}, and {@code Bar} by specifying the name {@code "a.b"} or the
* {@link Package} representing {@code a.b}.
* <li>for {@code Foo} and {@code Bar} by specifying both of their names or classes.
* </ul>
*
* <p>{@code System.out} and {@code System.err} messages are configured via loggers of the
* corresponding name. Note that by specifying multiple overrides, the exact name followed by the
* closest parent takes precedence.
*/
class SdkHarnessLogLevelOverrides extends HashMap<String, LogLevel> {
/**
* Overrides the default log level for the passed in class.
*
* <p>This is equivalent to calling {@link #addOverrideForName(String, LogLevel)} and passing in
* the {@link Class#getName() class name}.
*/
public SdkHarnessLogLevelOverrides addOverrideForClass(Class<?> klass, LogLevel logLevel) {
checkNotNull(klass, "Expected class to be not null.");
addOverrideForName(klass.getName(), logLevel);
return this;
}
/**
* Overrides the default log level for the passed in package.
*
* <p>This is equivalent to calling {@link #addOverrideForName(String, LogLevel)} and passing in
* the {@link Package#getName() package name}.
*/
public SdkHarnessLogLevelOverrides addOverrideForPackage(Package pkg, LogLevel logLevel) {
checkNotNull(pkg, "Expected package to be not null.");
addOverrideForName(pkg.getName(), logLevel);
return this;
}
/**
* Overrides the default log logLevel for the passed in name.
*
* <p>Note that because of the hierarchical nature of logger names, this will override the log
* logLevel of all loggers that have the passed in name or a parent logger that has the passed
* in name.
*/
public SdkHarnessLogLevelOverrides addOverrideForName(String name, LogLevel logLevel) {
checkNotNull(name, "Expected name to be not null.");
checkNotNull(
logLevel, "Expected logLevel to be one of %s.", Arrays.toString(LogLevel.values()));
put(name, logLevel);
return this;
}
/**
* Expects a map keyed by logger {@code Name}s with values representing {@code LogLevel}s. The
* {@code Name} generally represents the fully qualified Java {@link Class#getName() class
* name}, or fully qualified Java {@link Package#getName() package name}, or custom logger name.
* The {@code LogLevel} represents the log level and must be one of {@link LogLevel}.
*/
@JsonCreator
public static SdkHarnessLogLevelOverrides from(Map<String, String> values) {
checkNotNull(values, "Expected values to be not null.");
SdkHarnessLogLevelOverrides overrides = new SdkHarnessLogLevelOverrides();
for (Map.Entry<String, String> entry : values.entrySet()) {
try {
overrides.addOverrideForName(entry.getKey(), LogLevel.valueOf(entry.getValue()));
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
String.format(
"Unsupported log level '%s' requested for %s. Must be one of %s.",
entry.getValue(), entry.getKey(), Arrays.toString(LogLevel.values())));
}
}
return overrides;
}
}
}