Skip to content

Instantly share code, notes, and snippets.

@badalsarkar
Last active November 27, 2020 17:24
Show Gist options
  • Save badalsarkar/ca176a0335131a092618cb9066fc3fee to your computer and use it in GitHub Desktop.
Save badalsarkar/ca176a0335131a092618cb9066fc3fee to your computer and use it in GitHub Desktop.
For blog 2020-11-21-new-feature-butterfly
dependencies {
log4j_api: "org.apache.logging.log4j:log4j-api:2.14.0",
log4j_core:"org.apache.logging.log4j:log4j-core:2.14.0",
// for using SLF4J API with Log4j2
log4j_slf4j_impl: "org.apache.logging.log4j:log4j-slf4j-impl:2.14.0",
// for async log4j2 logging
disruptor:"com.lmax:disruptor:3.3.4",
// this is old framework and will be removed later
logback: "ch.qos.logback:logback-classic:1.1.7",
}
@Test
public void helpTest() throws IOException, URISyntaxException {
ButterflyCliRun run = new ButterflyCliApp().run();
assertEquals(run.getExitStatus(), 0);
// Ensuring run metadata is correct
assertEquals(run.getInputArguments(), new String[]{});
assertEquals(run.getButterflyVersion(), "TEST");
assertNull(run.getErrorMessage());
assertNull(run.getExceptionMessage());
assertEquals(run.getExtensions(), Collections.emptyList());
assertNull(run.getLogFile());
// Capturing the console output
PrintStream systemOut = System.out;
File helpOut = File.createTempFile("butterfly-cli-help-output", null);
PrintStream helpStream = new PrintStream(helpOut);
System.setOut(helpStream);
// Running help option three times (in different ways) to capture console output
assertEquals(new ButterflyCliApp().run().getExitStatus(), 0);
assertEquals(new ButterflyCliApp().run("-h").getExitStatus(), 0);
assertEquals(new ButterflyCliApp().run("-?").getExitStatus(), 0);
// Closing captured console output stream, and restoring original system out
helpStream.close();
System.setOut(systemOut);
// Ensuring console output is as expected
File helpBaselineOut = new File(this.getClass().getResource("/helpOut.txt").toURI());
assertTrue(FileUtils.contentEquals(helpBaselineOut, helpOut), "Generated help differs from test baseline\nTest baseline: " + helpBaselineOut + "\nGenerated result: " + helpOut + "\n");
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<Appenders>
<!-- This line failed a test case -->
<Console name="CONSOLE" target="SYSTEM_OUT">
<PatternLayout pattern="%msg%n" />
</Console>
<Routing name="Routing">
<Routes pattern="$${sys:logFile}">
<Route>
<RandomAccessFile name="File" fileName="${sys:logFile}" immediateFlush="false">
<PatternLayout>
<pattern>[%d{HH:mm:ss.SSS}] [%-4level] %msg%n</pattern>
</PatternLayout>
</RandomAccessFile>
</Route>
</Routes>
</Routing>
</Appenders>
<Loggers>
<AsyncLogger name="com.paypal.butterfly.cli" level="INFO">
<AppenderRef ref="CONSOLE" />
</AsyncLogger>
<AsyncRoot level="ERROR">
<AppenderRef ref="Routing" />
</AsyncRoot>
</Loggers>
</configuration>
public class Log4j2LogConfigurator extends LogConfigurator {
private static final LoggerContext context = (LoggerContext)LogManager.getContext(false);
private static final Configuration config = context.getConfiguration();
private boolean verboseMode = false;
@Override
public void setLoggerLevel(String logger, org.slf4j.event.Level level) {
if(level == null) {
throw new IllegalArgumentException("level argument cannot be null");
}
if(logger==null || logger.length()==0){
throw new IllegalArgumentException("name argument cannot be null");
}
config.getLoggerConfig(logger).setLevel(getLog4j2LogLevel(level));
context.updateLoggers();
}
@Override
public void setLoggerLevel(Class logger, org.slf4j.event.Level level) {
if(level == null) {
throw new IllegalArgumentException("level argument cannot be null");
}
config.getLoggerConfig(LogManager.getLogger(logger).getName()).setLevel(getLog4j2LogLevel(level));
context.updateLoggers();
}
private Level getLog4j2LogLevel(org.slf4j.event.Level slf4jLevel) {
if(slf4jLevel.equals(org.slf4j.event.Level.INFO)) return Level.INFO;
if(slf4jLevel.equals(org.slf4j.event.Level.DEBUG)) return Level.DEBUG;
if(slf4jLevel.equals(org.slf4j.event.Level.WARN)) return Level.WARN;
if(slf4jLevel.equals(org.slf4j.event.Level.ERROR)) return Level.ERROR;
throw new IllegalArgumentException("Unknown log level");
}
@Override
public void setVerboseMode(boolean verboseMode) {
this.verboseMode = verboseMode;
if (verboseMode) {
Layout layout = PatternLayout.newBuilder().withConfiguration(config).withPattern("[%d{HH:mm:ss.SSS}] [%highlight(%level)] %msg%n").build();
Appender consoleAppender = ConsoleAppender.createDefaultAppenderForLayout(layout);
consoleAppender.start();
config.getLoggerConfig("com.paypal.butterfly.cli").removeAppender("CONSOLE");
config.getRootLogger().addAppender(consoleAppender,null,null);
context.updateLoggers();
// } else {
// TODO
}
}
@Override
public void setLogToFile(boolean on) {
config.getRootLogger().removeAppender("FILE");
}
@Override
public boolean isVerboseMode() {
return verboseMode;
}
}
/**
* Log4j2VerboseConfiguratorTest
*
*/
public class Log4j2LogConfiguratorTest extends PowerMockTestCase {
@InjectMocks
private Log4j2LogConfigurator log4j2VerboseConfigurator;
@Mock
private static final Log4jLoggerFactory log4jLoggerFactory = (Log4jLoggerFactory) LoggerFactory.getILoggerFactory();
@Test
public void testVerboseOn() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setDebugMode(true);
Assert.assertTrue(LogManager.getLogger("com.paypal.butterfly").getLevel() == org.apache.logging.log4j.Level.DEBUG);
}
@Test
public void testVerboseOff() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setDebugMode(false);
Assert.assertTrue(LogManager.getLogger("com.paypal.butterfly").getLevel() == org.apache.logging.log4j.Level.INFO);
}
@Test
public void testVerboseOnAndRootLoggerHasConsoleAppender(){
Configuration config = ((LoggerContext)LogManager.getContext(false)).getConfiguration();
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setVerboseMode(true);
LogManager.getLogger("com.paypal.butterfly.cli");
Assert.assertTrue(config.getLoggerConfig("com.paypal.butterfly.cli").getAppenders().isEmpty());
Assert.assertTrue(config.getRootLogger().getAppenders().get("DefaultConsole-2").getName().compareTo("DefaultConsole-2") == 0);
Assert.assertTrue(config.getRootLogger().getAppenders().get("Routing").getName().compareTo("Routing") == 0);
}
@Test
public void testLoggerAsStringAndLogLevelAsInfo() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setLoggerLevel("com.paypal.butterfly.cli", Level.INFO);
Assert.assertTrue(LogManager.getLogger("com.paypal.butterfly.cli").getLevel() == org.apache.logging.log4j.Level.INFO);
}
@Test
public void testChildLogLevelIsInheritedFromParent(){
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setLoggerLevel("com.paypal.butterfly.cli", Level.INFO);
Assert.assertTrue(LogManager.getLogger("com.paypal.butterfly.cli.test").getLevel() == org.apache.logging.log4j.Level.INFO);
}
@Test
public void testLoggerAsStringAndLogLevelAsDebug() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setLoggerLevel("com.paypal.butterfly.cli", Level.DEBUG);
Assert.assertTrue(LogManager.getLogger("com.paypal.butterfly.cli").getLevel() == org.apache.logging.log4j.Level.DEBUG);
}
@Test
public void testLoggerAsStringAndLogLevelAsWarn() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setLoggerLevel("com.paypal.butterfly.cli", Level.WARN);
Assert.assertTrue(LogManager.getLogger("com.paypal.butterfly.cli").getLevel() == org.apache.logging.log4j.Level.WARN);
}
@Test
public void testLoggerAsStringAndLogLevelAsError() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setLoggerLevel("com.paypal.butterfly.cli", Level.ERROR);
Assert.assertTrue(LogManager.getLogger("com.paypal.butterfly.cli").getLevel() == org.apache.logging.log4j.Level.ERROR);
}
@Test
public void testLoggerAsStringAndLogLevelAsInvalid() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
try {
log4j2VerboseConfigurator.setLoggerLevel("com.paypal.butterfly.cli", Level.TRACE);
Assert.assertTrue(false);
} catch (IllegalArgumentException ex) {
Assert.assertTrue(ex.getMessage().equals("Unknown log level"));
}
}
@Test
public void testLoggerAsStringAndLogLevelAsNull() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
try {
log4j2VerboseConfigurator.setLoggerLevel("", null);
Assert.assertFalse(false);
}catch(IllegalArgumentException ex) {
Assert.assertTrue(ex.getMessage().equals("level argument cannot be null"));
}
}
@Test
public void testLoggerAsEmptyStringAndValidLogLevel(){
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
try {
log4j2VerboseConfigurator.setLoggerLevel("", Level.WARN);
Assert.assertFalse(false);
}catch(IllegalArgumentException ex) {
Assert.assertTrue(ex.getMessage().equals("name argument cannot be null"));
}
}
@Test
public void testLoggerAsStringAndLogLevelAsWarnAndLoggerAsNull() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
try {
log4j2VerboseConfigurator.setLoggerLevel((String)null, Level.WARN);
Assert.assertFalse(false);
}catch(IllegalArgumentException ex) {
Assert.assertTrue(ex.getMessage().equals("name argument cannot be null"));
}
}
@Test
public void testLoggerAsClassAndLogLevelAsInfo() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setLoggerLevel(this.getClass(), Level.INFO);
Assert.assertTrue(LogManager.getLogger(this.getClass()).getLevel() == org.apache.logging.log4j.Level.INFO);
}
@Test
public void testLoggerAsClassAndLogLevelAsDebug() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setLoggerLevel(this.getClass(), Level.DEBUG);
Assert.assertTrue(LogManager.getLogger(this.getClass()).getLevel() == org.apache.logging.log4j.Level.DEBUG);
}
@Test
public void testLoggerAsClassAndLevelAsWarn() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setLoggerLevel(this.getClass(), Level.WARN);
Assert.assertTrue(LogManager.getLogger(this.getClass()).getLevel() == org.apache.logging.log4j.Level.WARN);
}
@Test
public void testLoggerAsClassAndLogLevelAsError() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
log4j2VerboseConfigurator.setLoggerLevel(this.getClass(), Level.ERROR);
Assert.assertTrue(LogManager.getLogger(this.getClass()).getLevel() == org.apache.logging.log4j.Level.ERROR);
}
@Test
public void testLoggerAsClassAndLogLevelAsInvalid() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
try {
log4j2VerboseConfigurator.setLoggerLevel(this.getClass(), Level.TRACE);
Assert.assertTrue(false);
} catch (IllegalArgumentException ex) {
Assert.assertTrue(ex.getMessage().equals("Unknown log level"));
}
}
@Test
public void testLoggerAsClassAndLogLevelAsNull() {
Assert.assertNotNull(log4j2VerboseConfigurator);
Assert.assertNotNull(log4jLoggerFactory);
try {
log4j2VerboseConfigurator.setLoggerLevel("", null);
Assert.assertFalse(false);
}catch(IllegalArgumentException ex) {
Assert.assertTrue(ex.getMessage().equals("level argument cannot be null"));
}
}
}
public class LogFileDefiner {
private static final String LOG_FILE_NAME_SYNTAX = "%s_%s.log";
private static final String DEBUG_LOG_FILE_NAME_SYNTAX = "%s_%s_debug.log";
private static final String DEFAULT_LOG_FILE_NAME = String.format(LOG_FILE_NAME_SYNTAX, "butterfly", new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()));
private static String logFileName = DEFAULT_LOG_FILE_NAME;
private static boolean customLogFileNameSet = false;
private static File butterflyHome;
private static File logFile;
public static void setButterflyHome(File butterflyHome) {
LogFileDefiner.butterflyHome = butterflyHome;
}
public static void setLogFileName(File applicationFolder, boolean debug) {
if (!customLogFileNameSet && applicationFolder != null) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
logFileName = String.format((debug ? DEBUG_LOG_FILE_NAME_SYNTAX : LOG_FILE_NAME_SYNTAX), applicationFolder.getName(), simpleDateFormat.format(new Date()));
customLogFileNameSet = true;
}
}
private static void setLogFile() {
logFile = new File(butterflyHome, "logs" + File.separator + logFileName);
}
public static File getLogFile() {
if (logFile == null) {
setLogFile();
}
return logFile;
}
public static void updateLog4jConfigWithLogFile(){
System.setProperty("logFile",LogFileDefiner.getLogFile().getAbsolutePath());
}
}
/**
* Tests for logging
*/
public class LoggerTest{
@Test
public void testLoggingToConsoleWithLevelInfo() throws IOException{
PrintStream originalStdOut= System.out;
ByteArrayOutputStream consoleContent = new ByteArrayOutputStream();
PrintStream printToFile = new PrintStream(consoleContent);
System.setOut(printToFile);
LoggerFactory.getLogger("com.paypal.butterfly.cli").info("Butterfly application transformation tool");
System.setOut(originalStdOut);
printToFile.close();
Assert.assertTrue(consoleContent.toString().compareTo("Butterfly application transformation tool\n")==0);
}
@Test
public void testLoggingToFile() throws IOException {
String fileName = System.getProperty("user.dir") +"/logs/testLoggingToFile.txt";
String testLine ="Butterfly application transformation tool";
System.setProperty("logFile",fileName);
LoggerFactory.getLogger("root").error(testLine);
File logFile = new File(fileName);
Assert.assertTrue(logFile.exists());
Assert.assertTrue(FileUtils.readFileToString(logFile, "UTF-8").contains("Butterfly application transformation tool"));
logFile.delete();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment