/*
* Copyright (C) 2015 Commerce Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.commercehub.logging.log4j;
import net.minidev.json.JSONObject;
import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
/**
* This class is intentionally not thread-safe. Don't share an instance of this Layout across multiple Appenders. Don't
* share instances of the Appenders that use this Layout across multiple Loggers.
*/
public class LogstashEventLayout extends Layout {
private static final int version = 1;
private final SimpleDateFormat simpleDateFormat;
private String userFields;
private Map<String, String> userFieldsMap = new HashMap<>();
private boolean userFieldsNeedToBeParsed = false;
private String host;
public LogstashEventLayout() {
simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
host = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
host = "unknown";
}
}
@Override
public String format(LoggingEvent loggingEvent) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("@version", version);
jsonObject.put("@timestamp", simpleDateFormat.format(new Date(loggingEvent.getTimeStamp())));
jsonObject.put("logger_full", loggingEvent.getLoggerName());
jsonObject.put("level", loggingEvent.getLevel().toString());
jsonObject.put("message", loggingEvent.getRenderedMessage());
jsonObject.put("mdc", loggingEvent.getProperties());
jsonObject.put("thread", loggingEvent.getThreadName());
jsonObject.put("host", host);
handleLoggerSimpleName(loggingEvent, jsonObject);
handleThrowableInformation(loggingEvent, jsonObject);
jsonObject.putAll(getUserFieldsMap());
return jsonObject.toString();
}
private void handleLoggerSimpleName(LoggingEvent loggingEvent, JSONObject jsonObject) {
String loggerName = loggingEvent.getLoggerName();
if (loggerName != null) {
jsonObject.put("logger_simple", loggerName.substring(loggerName.lastIndexOf('.') + 1));
}
}
private void handleThrowableInformation(LoggingEvent loggingEvent, JSONObject jsonObject) {
ThrowableInformation throwableInformation = loggingEvent.getThrowableInformation();
if (throwableInformation != null) {
//noinspection ThrowableResultOfMethodCallIgnored
Throwable throwable = throwableInformation.getThrowable();
if (throwable != null) {
Map<String, String> exceptionMap = new HashMap<>();
String canonicalName = throwable.getClass().getCanonicalName();
if (canonicalName != null) {
exceptionMap.put("class", canonicalName);
}
String message = throwable.getMessage();
if (message != null) {
exceptionMap.put("message", message);
}
String[] throwableStrReps = throwableInformation.getThrowableStrRep();
if (throwableStrReps != null) {
StringBuilder stringBuilder = new StringBuilder();
for (String throwableStrRep : throwableStrReps) {
stringBuilder.append(throwableStrRep);
stringBuilder.append("\n");
}
exceptionMap.put("stacktrace", stringBuilder.toString());
}
jsonObject.put("exception", exceptionMap);
}
}
}
public Map<String, String> getUserFieldsMap() {
if (userFieldsNeedToBeParsed) {
userFieldsMap = new HashMap<>();
parseUserFields();
}
return userFieldsMap;
}
private void parseUserFields() {
String userFields = this.userFields;
if (userFields != null) {
String[] userFieldPairs = userFields.split(",");
for (String userFieldPair : userFieldPairs) {
String[] splitUserFieldPair = userFieldPair.split(":", 2);
String userFieldKey = splitUserFieldPair[0];
String userFieldValue = splitUserFieldPair[1];
if ((userFieldKey != null) && (userFieldValue != null)) {
userFieldsMap.put(userFieldKey, userFieldValue);
}
}
}
}
@Override
public boolean ignoresThrowable() {
return false;
}
@Override
public void activateOptions() {
}
@SuppressWarnings("UnusedDeclaration")
public void setUserFields(String userFields) {
this.userFields = userFields;
userFieldsNeedToBeParsed = true;
}
@SuppressWarnings("UnusedDeclaration")
public void setHost(String host) {
this.host = host;
}
}