Customize the Java SDK logger
Customize log information from the Optimizely Feature Experimentation Java SDK for debugging experiments.
The logger captures details about your experiments, making it easier for you to debug them. You can customize where the log information is stored and choose the types of data you want to track.
Java SDK does not enable logging functionality by default. To improve your experience setting up the SDK and configuring your production environment, you should include a SLF4J implementation in your dependencies. For the Java SDK, use an SLF4J implementation.
To improve your experience setting up the SDK and configuring your production environment, pass in a logger for your Optimizely client. See the following code sample.
Warning
Due to a recently announced security exploit in the Log4J library, upgrade to version 2.16.0 or higher if you are using it with the SDK. View Apache's documentation on the Log4j vulnerability for information.
Add Log4j dependency to Gradle file
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.20.0'
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.20.0'
implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.20.0'
Add log4j2.properties to your resources directory
// Set the root logger level to INFO and its appender to the console
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
// Specify the loggers
rootLogger.level = debug
rootLogger.appenderRef.stdout.ref = STDOUT
Use logback for finer control over logging, such as adjusting the logging level per package or setting the logging destination.
implementation 'ch.qos.logback:logback-classic:1.1.7'
Save the logback.xml
file in your resources directory. The following is a code sample for capturing Optimizely Feature Experimentation log levels and redirecting them. It routes debug logs to error messages, which are then sent to a different log appender.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<appender name="MEMORY" class="com.optimizely.intellij.plugin.utils.LogAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="com.optimizely" level="debug" additivity="false">
<appender-ref ref="MEMORY"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
You can also set logging levels for any Optimizely package, giving you control over log granularity. In the following example, set the log level for the highest-level package, com.optimizely
:
<logger name="com.optimizely" level="debug" />
The following sample shows you how to write a custom appender rather than using one of the many default appenders:
public class LogAppender extends AppenderBase<ILoggingEvent> {
int counter = 0;
public static AtomicBoolean captureLogging = new AtomicBoolean(false);
public static List<String> logs = Collections.synchronizedList(new ArrayList<String>());
PatternLayoutEncoder encoder;
@Override
public void start() {
if (this.encoder == null) {
addError("No encoder set for the appender named ["+ name +"].");
return;
}
try {
encoder.init(System.out);
} catch (IOException e) {
}
super.start();
}
public static void clearLogs() {
synchronized (logs) {
logs.clear();
}
}
public void append(ILoggingEvent event) {
// output the events as formatted by our layout
try {
this.encoder.doEncode(event);
if (captureLogging.get()) {
synchronized (logs) {
logs.add(event.getFormattedMessage());
}
}
} catch (IOException e) {
}
// prepare for next event
counter++;
}
public PatternLayoutEncoder getEncoder() {
return encoder;
}
public void setEncoder(PatternLayoutEncoder encoder) {
this.encoder = encoder;
}
}
Log levels
The following list shows the log levels for the Java SDK.
- ERROR – Logs events that prevent feature flags from working properly, such as an invalid data file during initialization or incorrect feature keys. These issues require user intervention to fix.
- WARN – Logs events that do not prevent feature flags from working properly but may cause unexpected results, such as future API deprecation, improper logger or error handler settings, and nil values from getters.
- INFO – Logs key events to illustrate the lifecycle of an API call, such as when a decision or tracking starts and succeeds.
- DEBUG – Logs extra information related to errors that aid Optimizely in debugging, like when a feature flag is not running or a user is not included in a rollout.
Updated 12 days ago