/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.dlect.controller;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.StreamHandler;
import org.dlect.controller.data.DatabaseHandler;
import org.dlect.encryption.DatabaseKeyHandler;
import org.dlect.model.helper.CommonSettingNames;
import org.dlect.model.helper.ThreadLocalDateFormat;
import org.dlect.update.ApplicationInformation;
import static com.google.common.base.Strings.padEnd;
/**
*
* @author lee
*/
public class DLectLoggingHandler extends StreamHandler {
private static final ThreadLocalDateFormat OUTPUT_FORMAT = new ThreadLocalDateFormat("yyyy-MM-dd'T'HH-mm-ss.SSSS");
public DLectLoggingHandler() {
super(getLoggingOutputStream(), new DLectLogFormatter());
}
public static OutputStream getLoggingOutputStream() {
try {
return new FileOutputStream(DatabaseHandler.getLoggingFile());
} catch (FileNotFoundException ex) {
return System.out;
}
}
private static class DLectLogFormatter extends Formatter {
private static final ImmutableList<String> CENSORED_KEYWORDS = ImmutableList.of(CommonSettingNames.USERNAME,
CommonSettingNames.PASSWORD,
DatabaseKeyHandler.AES_KEY_SETTING_NAME);
private static final int width = 120;
private static final int mainWidth = width - 4;
public DLectLogFormatter() {
}
private String formatCheckedMessage(LogRecord record) {
String msg = formatMessage(record);
for (String ck : CENSORED_KEYWORDS) {
if (msg.contains(ck)) {
return "This message contained private information and as a result was censured to prevent "
+ "data breaches. The censured key word was: " + ck;
}
}
return msg;
}
@Override
public String getHead(Handler h) {
StringBuilder b = new StringBuilder(500);
b.append(padCenter("DLect Log", width, '#')).append('\n');
b.append("# ").append(padCenter("", mainWidth, ' ')).append(" #\n");
b.append("# ").append(padCenter("Started At " + OUTPUT_FORMAT.format(new Date()), mainWidth, ' ')).append(" #\n");
b.append("# ").append(padCenter("", mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("DLect Version: " + ApplicationInformation.APPLICATION_VERSION, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("Java Version: " + ApplicationInformation.JAVA_VERSION, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("OS Type: " + ApplicationInformation.OS_TYPE, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("OS Version: " + ApplicationInformation.OS_VERSON, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("OS Arch: " + ApplicationInformation.OS_ARCHITECTURE, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padCenter("", mainWidth, ' ')).append(" #\n");
b.append(padCenter("", width, '#')).append("\n\n");
return b.toString();
}
@Override
public String getTail(Handler h) {
StringBuilder b = new StringBuilder(500);
b.append("\n\n");
b.append(padCenter("", width, '#')).append('\n');
b.append("# ").append(padCenter("", mainWidth, ' ')).append(" #\n");
b.append("# ").append(padCenter("Completed At " + OUTPUT_FORMAT.format(new Date()), mainWidth, ' ')).append(" #\n");
b.append("# ").append(padCenter("", mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("DLect Version: " + ApplicationInformation.APPLICATION_VERSION, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("Java Version: " + ApplicationInformation.JAVA_VERSION, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("OS Type: " + ApplicationInformation.OS_TYPE, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("OS Version: " + ApplicationInformation.OS_VERSON, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padEnd("OS Arch: " + ApplicationInformation.OS_ARCHITECTURE, mainWidth, ' ')).append(" #\n");
b.append("# ").append(padCenter("", mainWidth, ' ')).append(" #\n");
b.append(padCenter("End DLect Log", width, '#')).append('\n');
return b.toString();
}
private String padCenter(String toPad, int length, char padding) {
if (toPad.length() == 0) {
return Strings.repeat(String.valueOf(padding), length);
}
int size = (length - toPad.length()) / 2;
String pad = Strings.repeat(String.valueOf(padding), size);
String padded = pad + toPad + pad;
if (padded.length() == length - 1) {
padded = padding + padded;
}
return padded;
}
private String createTrace(Throwable thrown) {
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {
pw.println();
thrown.printStackTrace(pw);
}
return sw.toString();
}
@Override
public String format(LogRecord record) {
StringBuilder b = new StringBuilder(300);
b.append('>').append(OUTPUT_FORMAT.format(record.getMillis()));
b.append('|').append(record.getLevel());
b.append('|').append(record.getLoggerName());
b.append('|').append(record.getSourceClassName());
b.append('|').append(record.getSourceMethodName());
b.append('<').append('\n');
b.append(padLines(formatCheckedMessage(record), " ")).append("\n");
Throwable thrown = record.getThrown();
if (thrown != null) {
b.append(padLines(createTrace(thrown), " "));
}
return b.toString();
}
private String padLines(String msg, String padWith) {
if (msg.isEmpty()) {
return padWith;
}
String[] split = msg.split("\n");
if (split.length == 1) {
return padWith + split[0];
}
StringBuilder b = new StringBuilder(msg.length() + padWith.length() * split.length);
for (String string : split) {
b.append(padWith).append(string).append('\n');
}
return b.substring(0, b.length() - 1);
}
}
}