We're developing a web application and I'm implementing event logging on the server side. I decided a nice approach would be to extend the Java logging API to log events to a CSV file. I created a java.util.logging.Formatter
class as follows:
public class EventLogCsvFormatter extends Formatter {
private static final SimpleDateFormat SDF = new SimpleDateFormat("MM/dd/yyyy h:mm a");
private static final String[] COL_HEADERS = {"Date/Time", "Source", "Event Type", "Application Context", "Description", "Fields"};
public EventLogCsvFormatter() {
}
@Override
public String getHead(Handler h) {
return String.join(",", COL_HEADERS);
}
@Override
public String format(LogRecord record) {
if (record instanceof EventLogRecord) {
EventLogRecord customLogRecord = (EventLogRecord) record;
String[] fields = customLogRecord.getFields();
List<String> textList = new ArrayList<>();
textList.add(SDF.format(new Date(record.getMillis())));
textList.add(customLogRecord.getSource() != null ? customLogRecord.getSource() : "Not Given");
textList.add(customLogRecord.getEventType() != null ? customLogRecord.getEventType().toString() : "Not Given");
textList.add(customLogRecord.getEventContext() != null ? customLogRecord.getEventContext().toString() : "Not Given");
textList.add(customLogRecord.getMessage());
if (fields != null && fields.length > 0) {
for (String field : fields) {
textList.add(field);
}
}
String retVal = "\n" + String.join(",", textList);
return retVal;
}
return "";
}
}
The idea to implement the getHead() method is to provide the column headers for each CSV file. Note that Java's own XMLFormatter does something similar in returning the XML file header string in its getHead()
method. As it turns out, Java logging does not take into account the append flag when calling getHead(). The append flag basically tells the logger to re-open the existing file and continue logging to it upon startup. Because our test server gets bounced quite a bit, most of the CSV files generated have the column header names in multiple places within the files, not just at the top.
I don't think there's any way around this, since pretty much all of Java logging handler code has private or package scoped fields and methods. So, I can't even write my own custom handler to work here. Is this a bug and I'm SOL? Should I just go ahead and leverage a different logging API (e.g. Log4J)?