package biz.paluch.logging.gelf; import static biz.paluch.logging.RuntimeContainerProperties.getProperty; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Properties; import biz.paluch.logging.gelf.intern.Closer; /** * Field with reference to the log event. * * @author Mark Paluch */ public class LogMessageField implements MessageField { public static final String VERBOSE_LOGGING_PROPERTY = "logstash-gelf.LogMessageField.verbose"; private static final String DEFAULT_MAPPING = "default-logstash-fields.properties"; private static final boolean VERBOSE_LOGGING = Boolean.parseBoolean(getProperty(VERBOSE_LOGGING_PROPERTY, "false")); /** * Named references to common log event fields. */ public static enum NamedLogField { Time("Time"), Severity("Severity"), ThreadName("Thread"), SourceClassName("SourceClassName"), SourceSimpleClassName( "SourceSimpleClassName"), SourceMethodName("SourceMethodName"), SourceLineNumber("SourceLineNumber"), Server( "Server"), LoggerName("LoggerName"), Marker("Marker"), NDC("NDC"); private final String fieldName; NamedLogField(String fieldName) { this.fieldName = fieldName; } public String getFieldName() { return fieldName; } public static NamedLogField byName(String name) { for (NamedLogField namedLogField : values()) { if (namedLogField.name().equalsIgnoreCase(name)) { return namedLogField; } } return null; } } private String name; private NamedLogField namedLogField; public LogMessageField(String name, NamedLogField namedLogField) { this.namedLogField = namedLogField; this.name = name; } public NamedLogField getNamedLogField() { return namedLogField; } @Override public String getName() { return name; } public static List<LogMessageField> getDefaultMapping(NamedLogField... supportedFields) { return getDefaultMapping(true, supportedFields); } public static List<LogMessageField> getDefaultMapping(boolean readFromDefaultsFile, NamedLogField... supportedFields) { List<LogMessageField> result = new ArrayList<LogMessageField>(); List<NamedLogField> supportedLogFields = Arrays.asList(supportedFields); if (readFromDefaultsFile) { InputStream is = null; try { is = getStream(); if (is == null) { verboseLog("No " + DEFAULT_MAPPING + " resource present, using defaults"); } else { Properties p = new Properties(); p.load(is); if (!p.isEmpty()) { loadFields(p, result, supportedLogFields); } } } catch (IOException e) { verboseLog("Could not parse " + DEFAULT_MAPPING + " resource, using defaults: " + e.getMessage()); } finally { Closer.close(is); } } if (result.isEmpty()) { verboseLog("Default mapping is empty. Using " + NamedLogField.class.getName() + " fields"); for (NamedLogField namedLogField : NamedLogField.values()) { if (supportedLogFields.contains(namedLogField)) { result.add(new LogMessageField(namedLogField.fieldName, namedLogField)); } } } verboseLog("Default field mapping: " + result); return result; } private static void verboseLog(String message) { if (VERBOSE_LOGGING) { System.out.println(message); } } private static void loadFields(Properties p, List<LogMessageField> result, List<NamedLogField> supportedLogFields) { for (Map.Entry<Object, Object> entry : p.entrySet()) { String targetName = entry.getKey().toString(); String sourceFieldName = entry.getValue().toString(); NamedLogField namedLogField = NamedLogField.byName(sourceFieldName); if (namedLogField != null && supportedLogFields.contains(namedLogField)) { result.add(new LogMessageField(targetName, namedLogField)); } } } private static InputStream getStream() { Thread thread = Thread.currentThread(); InputStream is = LogMessageField.class.getResourceAsStream(DEFAULT_MAPPING); if (is == null && thread.getContextClassLoader() != null) { is = thread.getContextClassLoader().getResourceAsStream(DEFAULT_MAPPING); } return is; } @Override public String toString() { final StringBuffer sb = new StringBuffer(); sb.append(getClass().getSimpleName()); sb.append(" [name='").append(name).append('\''); sb.append(", namedLogField=").append(namedLogField); sb.append(']'); return sb.toString(); } }