Hi,
Could you please help me on migrating from log4j to logback. I am using a layout and appender.
What I was trying to do is create a different log file for each thread.
I really appreciate any help from anyone.
Thank you so much in advance.
Below is my codes:
Log4j version of the layout:
package com.selenium.reporting;
import java.io.*;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;
import org.apache.commons.lang3.StringEscapeUtils;
public
class ReportNGTestLayout
extends PatternLayout {
public ConcurrentHashMap<String, String>
threadTestName =
new ConcurrentHashMap<String, String>();
public
int
consoleLevel = Level.DEBUG_INT;
public String
reportParentFolder =
"test-output";
public String
executionDate;
@Override
public String format(LoggingEvent event) {
String logline =
"";
String logFileName;
String logPrefix;
String consolePrefix;
// Get test name by thread id
String testName =
threadTestName.get(Long.toString(Thread.currentThread().getId()));
String curThreadName = Thread.currentThread().getName();
if (testName ==
null) {
// log to a file by thread name, if no test name
consolePrefix = logPrefix =
" " + curThreadName +
" : ";
logFileName = Paths.get(reportParentFolder,
"main.log").toString();
}
else {
// log to <test name>.log file
logFileName = Paths.get(reportParentFolder,
"DetailReport",
"Attachments", testName +
".log").toString();
logPrefix =
" : ";
if (!curThreadName.contains("pool") && !curThreadName.equalsIgnoreCase("TestNG"))
logPrefix = logPrefix +
"[" + curThreadName +
"] ";
consolePrefix = testName + logPrefix;
}
// Console output
if (event.getLevel().toInt() >=
consoleLevel) {
if (event.getLevel().toInt() >
consoleLevel)
consolePrefix += event.getLevel() +
" : ";
String consoleMessage =
new SimpleDateFormat("HH:mm:ss.SSS ").format(new
Date(event.timeStamp))
+ consolePrefix + event.getMessage();
if (event.getLevel().toInt() >= Level.INFO_INT)
consoleMessage =
"\n" + consoleMessage;
System.out.println(consoleMessage);
}
if (!reportParentFolder.isEmpty()){
// Create log file if needed
File logFile =
new File(logFileName);
if (!logFile.exists()){
try {
File parentFolder =
new File(logFile.getParent());
parentFolder.mkdirs();
logFile.createNewFile();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Append to log file
try(PrintWriter out =
new PrintWriter(new BufferedWriter(new
FileWriter(logFile, true)))) {
out.println(new
SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
.format(new
Date(event.timeStamp)) +
" [" + event.getLevel() +
"]" +
logPrefix +
event.getMessage());
}
catch (IOException e) {
e.printStackTrace();
}
}
// Append to old report if INFO message
if (event.getLevel().toInt() == Level.INFO_INT)
{
String newMsg = StringEscapeUtils.escapeHtml3(event.getMessage()
.toString());
Throwable t =
null;
ThrowableInformation ti = event.getThrowableInformation();
if (ti !=
null) {
t = ti.getThrowable();
}
LoggingEvent encodedEvent =
new LoggingEvent(
event.fqnOfCategoryClass,
Logger.getLogger(event
.getLoggerName()), event.timeStamp,
event.getLevel(), newMsg, t);
String baseFmt =
super.format(encodedEvent).replace("@{{",
"<")
.replace("@}}",
">");
logline =
"<div class=step" +
"event.level.toString()" +
">"
+ baseFmt +
"</div><br/>";
}
return logline;
}
}
Logback version of the layout:
It is the same as the Log4j version but the only difference is I am extending
ch.qos.logback.classic.PatternLayout and I use ILoggingEvent in the format instead of LoggingEvent.
//@Override
public String format(ILoggingEvent
event) {
Log4j version of the appender:
package com.selenium.reporting;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.testng.Reporter;
public
class TestNGAppender
extends AppenderSkeleton {
public TestNGAppender(String name) {
super();
setName(name);
}
@Override
protected
void append(LoggingEvent event) {
String logMessage =
layout.format(event);
if (!logMessage.isEmpty()) {
Reporter.log(logMessage);
String[] thorwableCrap = event.getThrowableStrRep();
if (thorwableCrap !=
null) {
Reporter.log(thorwableCrap.toString());
}
}
}
@Override
public
void close() {
}
@Override
public
boolean requiresLayout() {
return
true;
}
}
Logback version of the appender:
package com.selenium.reporting;
import org.testng.Reporter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
public
class TestNGAppender
extends AppenderBase<ILoggingEvent> {
public TestNGAppender(String
name) {
super();
setName(name);
}
//@Override
protected
void append(ILoggingEvent
event) {
String
logMessage =
this.layout.format(event); =è
in here layout cannot be resolved. How can I access the format method in the ReportNGTestLayout class?
if (!logMessage.isEmpty()) {
Reporter.log(logMessage);
}
}
@Override
public
void stop() {
}
/* @Override
public boolean requiresLayout() {
return true;
}*/
}
This is how I setup the appender and layout in the logger:
Logger
rootLogger = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
TestNGAppender
testNGAppender =
new TestNGAppender("TestNG");
ReportNGTestLayout
logLayout =
new ReportNGTestLayout();
logLayout.executionDate =
new SimpleDateFormat("MM-dd-yyyy-HH-mm").format(new
Date());
logLayout.reportParentFolder = Paths.get(System.getProperty("reportRootPath"),
logLayout.executionDate).toString();
logLayout.consoleLevel = Level.toLevel(logLevel.toUpperCase(),
Level.DEBUG).toInt();
testNGAppender.setLayout(logLayout);
è
I am also having an error on this line. The method setLayout(ReportNGTestLayout) is undefined for the type TestNGAppender
testNGAppender.start();
rootLogger.addAppender(testNGAppender);
logger.debug("Log4j appender configuration is successful !!");
----------------------------
This message (including any attachments) contains confidential information intended for a specific individual and purpose, and is protected by law. If you are not the intended recipient of this e-mail (even if the e-mail address above is yours), (i) you may
not use, copy or retransmit it, (ii) please delete this message and (iii) please notify the sender immediately. Any disclosure, copying, or distribution of this message or the taking of any action based on it, is strictly prohibited.
----------------------------
----------------------------
This message (including any
attachments) contains confidential information intended for a specific
individual and purpose, and is protected by law. If you are not the intended
recipient of this e-mail (even if the e-mail address above is yours), (i) you
may not use, copy or retransmit it, (ii) please delete this message and (iii)
please notify the sender immediately. Any disclosure, copying, or distribution
of this message or the taking of any action based on it, is strictly
prohibited.
----------------------------