JavaExperienceLoggingFacility.java
package eu.javaexperience.log;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import eu.javaexperience.collection.PublisherCollection;
import eu.javaexperience.io.IOTools;
import eu.javaexperience.io.LocklessPrintWriter;
import eu.javaexperience.parse.ParsePrimitive;
import eu.javaexperience.resource.ReferenceCounted;
import eu.javaexperience.text.Format;
import eu.javaexperience.text.StringTools;
import eu.javaexperience.time.TimeCalc;
public class JavaExperienceLoggingFacility
{
protected static Vector<LogOutput> OUTPUTS = new Vector<>();
public static final LogOutput[] emptyLogOutputArrays = new LogOutput[0];
protected static LoggingDetailLevel lookupDefaultLoglevel()
{
LoggingDetailLevel ret = JvxLoggingFacilityInitialVariables.GET_DEFAULT_LOG_LEVEL.get();
if(null != ret)
{
return ret;
}
return LogLevel.MEASURE;
}
protected static final LoggingDetailLevel DEFAULT_LEVEL = lookupDefaultLoglevel();
public static LoggingDetailLevel getDefaultLogLevel()
{
return DEFAULT_LEVEL;
}
//TODO this logging stuff need a refactor, until move back to LocklessPrintWriter and with it's newline error
protected static LoggerProvider JEX = new LoggerProvider(new LogOutput()
{
@Override
public ReferenceCounted<PrintWriter> getLogOutput() throws IOException
{
PrintWriter lpw = new LocklessPrintWriter(IOTools.nullOutputStream, false)
{
@Override
public void write(char[] csq, int start, int end)
{
LogOutput[] los = OUTPUTS.toArray(emptyLogOutputArrays);
for(LogOutput lo:los)
{
try(ReferenceCounted<PrintWriter> rc_pw = lo.getLogOutput())
{
PrintWriter pw = rc_pw.getSubject();
pw.write(csq, start, end);
pw.flush();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
@Override public void flush() {/*noop*/}
@Override public void close() {/*noop*/}
};
return new ReferenceCounted<PrintWriter>(lpw, 2)
{
@Override
protected void onFree(){/*noop*/}
};
}
});
public static Logger getLogger(LoggableUnitDescriptor descr)
{
{
Logger l = getLoggingFacilityByName(descr.getUnitShortName());
if(null != l)
{
return l;
}
}
{
Logger l = JEX.createLoggerFor(descr);
LoggingDetailLevel lvl = FUTURE_MODULE_LEVEL.get(descr.getUnitShortName());
if(null != lvl)
{
l.setLogLevel(lvl);
}
else
{
lvl = FUTURE_DEFAUL_LEVEL;
if(null != lvl)
{
l.setLogLevel(lvl);
}
}
return l;
}
}
static final Logger LOG = JEX.createLoggerFor(new Loggable("JavaExperienceDefaultLogginFacility", getDefaultLogLevel()));
public static final Logger DEFAULT_LOGGER = new Logger()
{
protected void refuse()
{
throw new RuntimeException("Cannot modify JavaExperienceDefaultLogginFacility");
}
@Override
public void setLogLevel(LoggingDetailLevel level)
{
refuse();
}
@Override
public boolean mayLog(LoggingDetailLevel level)
{
return LOG.mayLog(level);
}
@Override
public void logFormat(LoggingDetailLevel level, String formatString, Object... params)
{
LOG.logFormat(level, formatString, params);
}
@Override
public void logExceptionFormat(LoggingDetailLevel level, Throwable t, String format, Object... params)
{
LOG.logExceptionFormat(level, t, format, params);
}
@Override
public void logException(LoggingDetailLevel level, Throwable t)
{
LOG.logException(level, t);
}
@Override
public void log(LoggingDetailLevel level, String str)
{
LOG.log(level, str);
}
@Override
public LoggingDetailLevel getLogLevel()
{
return LOG.getLogLevel();
}
@Override
public String getFacilityName()
{
return LOG.getFacilityName();
}
};
public static void addLogOutput(LogOutput out)
{
OUTPUTS.add(out);
}
protected static boolean STD_OUT_LOG_ADDED = false;
public static synchronized void addStdOut()
{
if(!STD_OUT_LOG_ADDED)
{
STD_OUT_LOG_ADDED = true;
addLogOutput(LoggingTools.STDOUT_LOG_OUTPUT);
LoggingTools.tryLogSimple(LOG, getDefaultLogLevel(), "JavaExperienceLoggingFacility.addStdOut() called");
}
}
protected static boolean STD_ERR_LOG_ADDED = false;
public static synchronized void addStdErr()
{
if(!STD_ERR_LOG_ADDED)
{
STD_ERR_LOG_ADDED = true;
addLogOutput(LoggingTools.STDERR_LOG_OUTPUT);
LoggingTools.tryLogSimple(LOG, getDefaultLogLevel(), "JavaExperienceLoggingFacility.addStdErr() called");
}
}
private static boolean THREAD_LOCAL_OUTPUT_ADDED = false;
public static synchronized void addThreadLocalHookableLoggerOutput()
{
if(!THREAD_LOCAL_OUTPUT_ADDED)
{
addLogOutput(ThreadLocalHookableLogFacility.LOG_OUTPUT);
LoggingTools.tryLogSimple(LOG, getDefaultLogLevel(), "JavaExperienceLoggingFacility.addThreadLocalHookableLoggerOutput() called");
THREAD_LOCAL_OUTPUT_ADDED = true;
}
}
public static void listIssuedLoggers(Collection<Logger> facilities)
{
JEX.fillActiveLoggers(facilities);
}
protected static Map<String, LoggingDetailLevel> FUTURE_MODULE_LEVEL = new ConcurrentHashMap<>();
protected static LoggingDetailLevel FUTURE_DEFAUL_LEVEL = null;
/**
* Modifies the loglevel of the requested module even if is loaded already.
* */
public static void setFutureModuleDefaultLoglevel(String module, LoggingDetailLevel lvl)
{
if(null != module && null != lvl)
{
FUTURE_MODULE_LEVEL.put(module, lvl);
Logger l = getLoggingFacilityByName(module);
if(null != l)
{
l.setLogLevel(lvl);
}
}
}
public static void setFutureDefaultLoglevel(LoggingDetailLevel lvl)
{
FUTURE_DEFAUL_LEVEL = lvl;
}
public static Logger getLoggingFacilityByName(String name)
{
ArrayList<Logger> lfs = new ArrayList<>();
JEX.fillActiveLoggers(lfs);
for(Logger lf:lfs)
{
if(name.equals(lf.getFacilityName()))
{
return lf;
}
}
return null;
}
public static void loadDefaultFacilityLogLevelsFromPropertyWithPrefix(Properties prop, String prefix)
{
loadDefaultFacilityLogLevelsFromPropertyWithPrefix(prop.entrySet(), prefix);
}
public static void loadDefaultFacilityLogLevelsFromPropertyWithPrefix(Set<Entry<Object, Object>> allPropertySet, String prefix)
{
String pre = prefix+".";
for(Entry<Object, Object> kv:allPropertySet)
{
if(null != kv.getKey() && null != kv.getValue())
{
String k = kv.getKey().toString();
if(k.startsWith(pre))
{
k = StringTools.getSubstringAfterFirstString(k, pre);
if(!k.contains("."))
{
LogLevel lvl = ParsePrimitive.tryParseEnum(LogLevel.class, kv.getValue().toString());
if(null != lvl)
{
JavaExperienceLoggingFacility.setFutureModuleDefaultLoglevel(k, lvl);
}
}
}
}
}
}
static
{
try
{
Runtime.getRuntime().addShutdownHook
(
new Thread()
{
public void run()
{
long jvmStartTime = ManagementFactory.getRuntimeMXBean().getStartTime();
long now = System.currentTimeMillis();
LoggingTools.tryLogFormat
(
LOG,
LogLevel.INFO,
"JavaExperienceLoggingFacility JVM start time: %s, JVM shutdownHook time: %s, full time: %s",
Format.UTC_SQL_TIMESTAMP_MS.format(new Date(jvmStartTime)),
Format.UTC_SQL_TIMESTAMP_MS.format(new Date(now)),
TimeCalc.durationToHourMinSec(now-jvmStartTime)+" h:m:s"
);
};
}
);
}
catch(Throwable t)
{
t.printStackTrace();
}
}
public static void setAllFacilityLoglevel(LogLevel lvl)
{
JEX.fillActiveLoggers(new PublisherCollection<Logger>()
{
@Override
public boolean add(Logger lf)
{
lf.setLogLevel(lvl);
return false;
}
});
}
public static void startLoggingIntoDirectory(File directory, String prefix)
{
if(!directory.exists())
{
directory.mkdirs();
}
addLogOutput(new DayliLogrotaOutput(directory+"/"+prefix));
}
public static void main(String[] args)
{
System.err.println("StdErr");
JavaExperienceLoggingFacility.addStdErr();
LoggingTools.tryLogFormat(LOG, LogLevel.INFO, "Test: `%s`", "value");
}
}