
com.arpitos.framework.infra.OrganisedLog Maven / Gradle / Ivy
// Copyright <2018>
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package com.arpitos.framework.infra;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import com.arpitos.framework.Enums.TestStatus;
import com.arpitos.framework.FWStatic_Store;
import com.arpitos.framework.SystemProperties;
import com.arpitos.framework.Version;
/**
* This class is responsible for initialising all log streams which may require
* during test suit execution
*/
class OrganisedLog {
private org.apache.logging.log4j.core.Logger generalLogger;
private org.apache.logging.log4j.core.Logger summaryLogger;
private String logBaseDir = "./reporting";
/**
* Class Constructor
*
*
* {
* @code
* OrganisedLog logger = new OrganisedLog("./reporting/A123456789", "com.arpitos.test", true);
* }
*
*
* @param logDirPath
* Log base directory absolute or reference path
* @param testCaseFQCN
* Test case fully qualified class name (Example :
* com.test.unit.Abc)
* @param enableLogDecoration
* Enables/disable log decoration (Time-stamp, source package,
* thread number etc..)
* @param enableTextLog
* Enables/disable text log
* @param enableHTMLLog
* Enable/disable HTML log
*/
public OrganisedLog(String logDirPath, String testCaseFQCN, boolean enableLogDecoration, boolean enableTextLog, boolean enableHTMLLog) {
// System.setProperty("log4j.configurationFile",
// "./conf/log4j2.properties");
// Log Base Dir = logDir + testCaseFQCN
setLogBaseDir(logDirPath + File.separator + testCaseFQCN);
LoggerContext loggerContext = dynamicallyConfigureLog4J(getLogBaseDir(), testCaseFQCN + "_" + System.currentTimeMillis(), enableLogDecoration,
enableTextLog, enableHTMLLog);
setGeneralLogger(loggerContext.getLogger("TestLog"));
setSummaryLogger(loggerContext.getLogger("Summary"));
printMendatoryInfo();
printUsefulInfo();
}
/**
* Append test summary to summary report
*
* @param status
* Test status
* @param strTestFQCN
* Test fully qualified class name (Example : com.test.unit.Abc)
* @param bugTrackingNumber
* BugTracking Number
* @param passCount
* Current passed test count
* @param failCount
* Current failed test count
* @param skipCount
* Current skipped test count
* @param ktfCount
* Current known to fail test count
* @param testDuration
* Test duration
*/
public void appendSummaryReport(TestStatus status, String strTestFQCN, String bugTrackingNumber, long passCount, long failCount, long skipCount,
long ktfCount, long testDuration) {
long hours = TimeUnit.MILLISECONDS.toHours(testDuration);
long minutes = TimeUnit.MILLISECONDS.toMinutes(testDuration) - TimeUnit.HOURS.toMinutes(hours);
long seconds = TimeUnit.MILLISECONDS.toSeconds(testDuration) - TimeUnit.HOURS.toSeconds(hours) - TimeUnit.MINUTES.toSeconds(minutes);
long millis = testDuration - TimeUnit.HOURS.toMillis(hours) - TimeUnit.MINUTES.toMillis(minutes) - TimeUnit.SECONDS.toMillis(seconds);
String testTime = String.format("duration:%3d:%2d:%2d.%2d", hours, minutes, seconds, millis).replace(" ", "0");
String testStatus = String.format("%-" + 4 + "s", status.getEnumName(status.getValue()));
String testName = String.format("%-" + 100 + "s", strTestFQCN).replace(" ", ".");
String JiraRef = String.format("%-" + 15 + "s", bugTrackingNumber);
String PassCount = String.format("%-" + 4 + "s", passCount);
String FailCount = String.format("%-" + 4 + "s", failCount);
String SkipCount = String.format("%-" + 4 + "s", skipCount);
String KTFCount = String.format("%-" + 4 + "s", ktfCount);
getSummaryLogger().info(testStatus + " = " + testName + " " + JiraRef + " P:" + PassCount + " F:" + FailCount + " S:" + SkipCount + " K:"
+ KTFCount + " " + testTime);
}
/** Disable Logging */
public void disableGeneralLog() {
getGeneralLogger().setLevel(Level.OFF);
}
/** Enable Logging */
public void enableGeneralLog() {
getGeneralLogger().setLevel(getLoglevelFromXML());
}
/**
* Get all error log files relevant to current context (Includes .txt and
* .html files)
*
* @return List of Error log files relevant to current context
*/
public List getCurrentErrorLogFiles() {
List textLog = new ArrayList();
List htmlLog = new ArrayList();
getFilesFromGeneralLogAppenders("error-log-text", textLog);
getFilesFromGeneralLogAppenders("error-log-html", htmlLog);
List mergedList = new ArrayList<>();
if (null != textLog) {
mergedList.addAll(textLog);
}
if (null != htmlLog) {
mergedList.addAll(htmlLog);
}
return mergedList;
}
/**
* Get all log files relevant to current context (Includes .txt and .html
* files)
*
* @return List of log files relevant to current context
*/
public List getCurrentGeneralLogFiles() {
List textLog = new ArrayList();
List htmlLog = new ArrayList();
getFilesFromGeneralLogAppenders("all-log-text", textLog);
getFilesFromGeneralLogAppenders("all-log-html", htmlLog);
List mergedList = new ArrayList<>();
if (null != textLog) {
mergedList.addAll(textLog);
}
if (null != htmlLog) {
mergedList.addAll(htmlLog);
}
return mergedList;
}
/**
* Get all summary log files relevant to current context (Includes .txt and
* .html files)
*
* @return List of summary log files relevant to current context
*/
public List getCurrentSummaryLogFiles() {
List textLog = new ArrayList();
List htmlLog = new ArrayList();
getFilesFromSummaryLogAppenders("summary-log-text", textLog);
getFilesFromSummaryLogAppenders("summary-log-html", htmlLog);
List mergedList = new ArrayList<>();
if (null != textLog) {
mergedList.addAll(textLog);
}
if (null != htmlLog) {
mergedList.addAll(htmlLog);
}
return mergedList;
}
/**
* Provides list of current general log files attached to provided appender
* name
*
* @param appenderName
* Appender Name
* @param textLog
* File List
*/
private void getFilesFromGeneralLogAppenders(String appenderName, List textLog) {
Map appenders = getGeneralLogger().getAppenders();
Iterator> it = appenders.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
getGeneralLogger().trace(pair.getKey() + "=" + pair.getValue());
if (pair.getValue() instanceof RollingFileAppender) {
if (appenderName.equals(pair.getValue().getName())) {
String appender = ((RollingFileAppender) pair.getValue()).getFileName();
textLog.add(new File(appender));
getGeneralLogger().trace(((RollingFileAppender) pair.getValue()).getFileName());
}
}
}
}
/**
* Provides list of current summary log files attached to provided appender
* name
*
* @param appenderName
* Appender Name
* @param textLog
* File List
*/
private void getFilesFromSummaryLogAppenders(String appenderName, List logFiles) {
Map appenders = getSummaryLogger().getAppenders();
Iterator> it = appenders.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
if (pair.getValue() instanceof RollingFileAppender) {
if (appenderName.equals(pair.getValue().getName())) {
logFiles.add(new File(((RollingFileAppender) pair.getValue()).getFileName()));
}
}
}
}
/**
* Dynamically Generates and applies Log4J configuration XML as per test
* suit requirement
*
* @param fileroot
* Log file root directory
* @param fileName
* Log file name
* @param enableLogDecoration
* Enable/disable log decoration (Time-stamp, source package,
* thread number etc..)
* @param enableTextLog
* Enables/disable text log
* @param enableHTMLLog
* Enable/disable HTML log
* @return {@code LoggerContext}
*
* @see LoggerContext
*/
private static LoggerContext dynamicallyConfigureLog4J(String fileroot, String fileName, boolean enableLogDecoration, boolean enableTextLog,
boolean enableHTMLLog) {
if (!fileroot.endsWith("/") || !fileroot.endsWith("\\")) {
fileroot = fileroot + File.separator;
}
ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel(Level.WARN);
builder.setConfigurationName("RollingBuilder");
// Log Layout with timestamp
LayoutComponentBuilder logFileLayout = builder.newLayout("PatternLayout");
if (enableLogDecoration) {
/*
* @formatter:off
*
* [%-5level] = Log level upto 5 char max
* [%d{yyyy-MM-dd_HH:mm:ss.SSS}] = Date and time
* [%t] = Thread number
* [%F] = File where logs are coming from
* [%M] = Method which generated log
* [%c{-1}] = ClassName which issued logCommand
* %msg = Actual msg to be logged
* %n = new line
* %throwable = log exception
*
* @formatter:on
*/
logFileLayout.addAttribute("pattern", "[%-5level][%d{yyyy-MM-dd_HH:mm:ss.SSS}][%t][%F][%M][%c{1}] - %msg%n%throwable");
} else {
logFileLayout.addAttribute("pattern", "%msg%n%throwable");
}
// Log Layout without decoration
LayoutComponentBuilder summaryFileLayout = builder.newLayout("PatternLayout");
summaryFileLayout.addAttribute("pattern", "%msg%n%throwable");
// HTML Log Layout for logs
LayoutComponentBuilder htmlLogFileLayout = builder.newLayout("HTMLLayout");
htmlLogFileLayout.addAttribute("title", "Test Logs");
// expensive if enabled
htmlLogFileLayout.addAttribute("locationInfo", false);
htmlLogFileLayout.addAttribute("fontSize", "small");
// HTML Log Layout for summary
LayoutComponentBuilder htmlSummaryFileLayout = builder.newLayout("HTMLLayout");
htmlSummaryFileLayout.addAttribute("title", "Test Summary");
// expensive if enabled
htmlSummaryFileLayout.addAttribute("locationInfo", false);
htmlLogFileLayout.addAttribute("fontSize", "small");
// File size based rollver Trigger Policy
ComponentBuilder> triggeringPolicy = builder.newComponent("Policies");
triggeringPolicy.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "1MB"));
// create a console appender
{
AppenderComponentBuilder appenderBuilder1 = builder.newAppender("console-log", "CONSOLE");
appenderBuilder1.addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
appenderBuilder1.add(logFileLayout);
builder.add(appenderBuilder1);
}
// create a rolling file appender for logs
{
// Text
AppenderComponentBuilder appenderBuilder2 = builder.newAppender("all-log-text", "RollingFile");
appenderBuilder2.addAttribute("fileName", fileroot + fileName + "-all.log");
appenderBuilder2.addAttribute("filePattern", fileroot + fileName + "-all-%d{yyyy-MM-dd_HH.mm.ss.SSS}.log");
appenderBuilder2.add(logFileLayout);
appenderBuilder2.addComponent(triggeringPolicy);
if (enableTextLog) {
builder.add(appenderBuilder2);
}
// HTML
AppenderComponentBuilder appenderBuilder3 = builder.newAppender("all-log-html", "RollingFile");
appenderBuilder3.addAttribute("fileName", fileroot + fileName + "-all.html");
appenderBuilder3.addAttribute("filePattern", fileroot + fileName + "-all-%d{yyyy-MM-dd_HH.mm.ss.SSS}.html");
appenderBuilder3.add(htmlLogFileLayout);
appenderBuilder3.addComponent(triggeringPolicy);
if (enableHTMLLog) {
builder.add(appenderBuilder3);
}
}
// create a rolling file appender for error
{
// Text
AppenderComponentBuilder appenderBuilder4 = builder.newAppender("error-log-text", "RollingFile");
appenderBuilder4.addAttribute("fileName", fileroot + fileName + "-error.log");
appenderBuilder4.addAttribute("filePattern", fileroot + fileName + "-error-%d{yyyy-MM-dd_HH.mm.ss.SSS}.log");
appenderBuilder4.add(logFileLayout);
appenderBuilder4.addComponent(triggeringPolicy);
if (enableTextLog) {
builder.add(appenderBuilder4);
}
// HTML
AppenderComponentBuilder appenderBuilder5 = builder.newAppender("error-log-html", "RollingFile");
appenderBuilder5.addAttribute("fileName", fileroot + fileName + "-error.html");
appenderBuilder5.addAttribute("filePattern", fileroot + fileName + "-error-%d{yyyy-MM-dd_HH.mm.ss.SSS}.html");
appenderBuilder5.add(htmlLogFileLayout);
appenderBuilder5.addComponent(triggeringPolicy);
if (enableHTMLLog) {
builder.add(appenderBuilder5);
}
}
// create a rolling file appender for summary
{
// Text
AppenderComponentBuilder appenderBuilder6 = builder.newAppender("summary-log-text", "RollingFile");
appenderBuilder6.addAttribute("fileName", fileroot + fileName + "-summary.log");
appenderBuilder6.addAttribute("filePattern", fileroot + fileName + "-summary-%d{yyyy-MM-dd_HH.mm.ss.SSS}.log");
appenderBuilder6.add(summaryFileLayout);
appenderBuilder6.addComponent(triggeringPolicy);
if (enableTextLog) {
builder.add(appenderBuilder6);
}
// HTML
AppenderComponentBuilder appenderBuilder7 = builder.newAppender("summary-log-html", "RollingFile");
appenderBuilder7.addAttribute("fileName", fileroot + fileName + "-summary.html");
appenderBuilder7.addAttribute("filePattern", fileroot + fileName + "-summary-%d{yyyy-MM-dd_HH.mm.ss.SSS}.html");
appenderBuilder7.add(htmlSummaryFileLayout);
appenderBuilder7.addComponent(triggeringPolicy);
if (enableHTMLLog) {
builder.add(appenderBuilder7);
}
}
{
// create the new logger
Level loglevel = getLoglevelFromXML();
LoggerComponentBuilder loggerBuilder1 = builder.newLogger("TestLog", loglevel);
loggerBuilder1.addAttribute("additivity", false);
AppenderRefComponentBuilder appendRef1 = builder.newAppenderRef("console-log");
appendRef1.addAttribute("level", Level.ALL);
AppenderRefComponentBuilder appendRef2 = builder.newAppenderRef("all-log-text");
appendRef2.addAttribute("level", Level.ALL);
AppenderRefComponentBuilder appendRef3 = builder.newAppenderRef("all-log-html");
appendRef3.addAttribute("level", Level.ALL);
AppenderRefComponentBuilder appendRef4 = builder.newAppenderRef("error-log-text");
appendRef4.addAttribute("level", Level.ERROR);
AppenderRefComponentBuilder appendRef5 = builder.newAppenderRef("error-log-html");
appendRef5.addAttribute("level", Level.ERROR);
loggerBuilder1.add(appendRef1);
if (enableTextLog) {
loggerBuilder1.add(appendRef2);
loggerBuilder1.add(appendRef4);
}
if (enableHTMLLog) {
loggerBuilder1.add(appendRef3);
loggerBuilder1.add(appendRef5);
}
builder.add(loggerBuilder1);
// create the new logger
LoggerComponentBuilder loggerBuilder2 = builder.newLogger("Summary", Level.DEBUG);
loggerBuilder2.addAttribute("additivity", false);
AppenderRefComponentBuilder appendRef11 = builder.newAppenderRef("summary-log-text");
appendRef11.addAttribute("level", Level.ALL);
AppenderRefComponentBuilder appendRef12 = builder.newAppenderRef("summary-log-html");
appendRef12.addAttribute("level", Level.ALL);
if (enableTextLog) {
loggerBuilder2.add(appendRef11);
}
if (enableHTMLLog) {
loggerBuilder2.add(appendRef12);
}
builder.add(loggerBuilder2);
RootLoggerComponentBuilder rootlogggerBuilder = builder.newRootLogger(Level.ALL);
rootlogggerBuilder.addAttribute("additivity", false);
AppenderRefComponentBuilder appendRef0 = builder.newAppenderRef("console-log");
rootlogggerBuilder.add(appendRef0);
builder.add(rootlogggerBuilder);
}
// System.out.println(builder.toXmlConfiguration().toString());
LoggerContext loggerContext = Configurator.initialize(builder.build());
// Print logger xml to log file
loggerContext.getLogger("TestLog").trace(builder.toXmlConfiguration().toString());
return loggerContext;
}
/**
* Returns Log Level Enum value based on Framework configuration set in XML
* file
*
* @see Level
*
* @return
*/
private static Level getLoglevelFromXML() {
if (FWStatic_Store.context.getFrameworkConfig().getLogLevel().equals("info")) {
return Level.INFO;
}
if (FWStatic_Store.context.getFrameworkConfig().getLogLevel().equals("all")) {
return Level.ALL;
}
if (FWStatic_Store.context.getFrameworkConfig().getLogLevel().equals("fatal")) {
return Level.FATAL;
}
if (FWStatic_Store.context.getFrameworkConfig().getLogLevel().equals("trace")) {
return Level.TRACE;
}
if (FWStatic_Store.context.getFrameworkConfig().getLogLevel().equals("warn")) {
return Level.WARN;
}
if (FWStatic_Store.context.getFrameworkConfig().getLogLevel().equals("debug")) {
return Level.DEBUG;
}
return Level.DEBUG;
}
/**
* Prints Organisation details to each log files
*/
private void printMendatoryInfo() {
//@formatter:off
String organisationInfo = "\n************************************ Header Start ******************************************"
+"\nOrganisation_Name : " + FWStatic_Store.context.getFrameworkConfig().getOrganisation_Name()
+"\nOrganisation_Country : " + FWStatic_Store.context.getFrameworkConfig().getOrganisation_Country()
+"\nOrganisation_Address : " + FWStatic_Store.context.getFrameworkConfig().getOrganisation_Address()
+"\nOrganisation_Phone : " + FWStatic_Store.context.getFrameworkConfig().getOrganisation_Contact_Number()
+"\nOrganisation_Email : " + FWStatic_Store.context.getFrameworkConfig().getOrganisation_Email()
+"\nOrganisation_Website : " + FWStatic_Store.context.getFrameworkConfig().getOrganisation_Website()
+"\n************************************ Header End ********************************************";
//@formatter:on
if (FWStatic_Store.context.getFrameworkConfig().isEnableBanner()) {
getGeneralLogger().info(Banner.getBanner());
getSummaryLogger().info(Banner.getBanner());
}
if (FWStatic_Store.context.getFrameworkConfig().isEnableOrganisationInfo()) {
getGeneralLogger().info(organisationInfo);
getSummaryLogger().info(organisationInfo);
}
}
/**
* Print selected System Info to log file
*
* @param generalLogger
*/
public void printUsefulInfo() {
SystemProperties sysProp = FWStatic_Store.context.getSystemProperties();
Logger logger = getGeneralLogger();
// @formatter:off
logger.debug("\nTest FrameWork Info");
logger.debug("* Arpitos version => " + Version.id());
logger.debug("* Java Runtime Environment version => " + sysProp.getJavaRuntimeEnvironmentVersion());
logger.debug("* Java Virtual Machine specification version => " + sysProp.getJavaVirtualMachineSpecificationVersion());
logger.debug("* Java Runtime Environment specification version => " + sysProp.getJavaRuntimeEnvironmentSpecificationVersion());
logger.debug("* Java class path => " + sysProp.getJavaClassPath());
logger.debug("* List of paths to search when loading libraries => " + sysProp.getListofPathstoSearchWhenLoadingLibraries());
logger.debug("* Operating system name => " + sysProp.getOperatingSystemName());
logger.debug("* Operating system architecture => " + sysProp.getOperatingSystemArchitecture());
logger.debug("* Operating system version => " + sysProp.getOperatingSystemVersion());
logger.debug("* File separator (\"/\" on UNIX) => " + sysProp.getFileSeparator());
logger.debug("* Path separator (\":\" on UNIX) => " + sysProp.getPathSeparator());
logger.debug("* User's account name => " + sysProp.getUserAccountName());
logger.debug("* User's home directory => " + sysProp.getUserHomeDir());
// @formatter:on
}
/**
* Get {@code Logger} object which is responsible for logging raw and error
* logs
*
* @return General Logger
*/
public org.apache.logging.log4j.core.Logger getGeneralLogger() {
return generalLogger;
}
private void setGeneralLogger(org.apache.logging.log4j.core.Logger generalLogger) {
this.generalLogger = generalLogger;
}
/**
* Get {@code Logger} object which is responsible for logging summary logs
*
* @return Summary Logger
*/
public org.apache.logging.log4j.core.Logger getSummaryLogger() {
return summaryLogger;
}
private void setSummaryLogger(org.apache.logging.log4j.core.Logger summaryLogger) {
this.summaryLogger = summaryLogger;
}
/** Returns Log Files Base Directory */
public String getLogBaseDir() {
return logBaseDir;
}
/** Sets Log Files Base Directory */
public void setLogBaseDir(String logBaseDir) {
this.logBaseDir = logBaseDir;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy