diff --git a/json/classic/src/main/java/ch/qos/logback/contrib/json/classic/CustomKeysJsonLayout.java b/json/classic/src/main/java/ch/qos/logback/contrib/json/classic/CustomKeysJsonLayout.java
new file mode 100644
index 0000000..9f347ad
--- /dev/null
+++ b/json/classic/src/main/java/ch/qos/logback/contrib/json/classic/CustomKeysJsonLayout.java
@@ -0,0 +1,133 @@
+/**
+ * Copyright (C) 2016, The logback-contrib developers. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under
+ * either the terms of the Eclipse Public License v1.0 as published by
+ * the Eclipse Foundation
+ *
+ * or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ */
+package ch.qos.logback.contrib.json.classic;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A CustomKeysJsonLayout provides an option to specify custom key names for the keys defined in {@link JsonLayout}.
+ * For example a key 'loggerName' can be used instead of the default 'logger'.
+ *
+ * @author Matej Lazar
+ */
+public class CustomKeysJsonLayout extends JsonLayout {
+
+ protected Map customAttrNames = new HashMap();
+
+ public CustomKeysJsonLayout() {
+ super();
+ }
+
+ @Override
+ public void add(String fieldName, boolean field, String value, Map map) {
+ super.add(getCustomOrDefault(fieldName), field, value, map);
+ }
+
+ @Override
+ public void addTimestamp(String key, boolean field, long timeStamp, Map map) {
+ super.addTimestamp(getCustomOrDefault(key), field, timeStamp, map);
+ }
+
+ @Override
+ public void addMap(String key, boolean field, Map mapValue, Map map) {
+ super.addMap(getCustomOrDefault(key), field, mapValue, map);
+ }
+
+ @Override
+ protected void addThrowableInfo(String fieldName, boolean field, ILoggingEvent value, Map map) {
+ super.addThrowableInfo(getCustomOrDefault(fieldName), field, value, map);
+ }
+
+ protected String getCustomOrDefault(String key) {
+ if (customAttrNames.containsKey(key)) {
+ return customAttrNames.get(key);
+ } else {
+ return key;
+ }
+ }
+
+ public String getTimestampAttrName() {
+ return customAttrNames.get(TIMESTAMP_ATTR_NAME);
+ }
+
+ public void setTimestampAttrName(String timestampAttrName) {
+ customAttrNames.put(TIMESTAMP_ATTR_NAME, timestampAttrName);
+ }
+
+ public String getLevelAttrName() {
+ return customAttrNames.get(LEVEL_ATTR_NAME);
+ }
+
+ public void setLevelAttrName(String levelAttrName) {
+ customAttrNames.put(LEVEL_ATTR_NAME, levelAttrName);
+ }
+
+ public String getThreadAttrName() {
+ return customAttrNames.get(THREAD_ATTR_NAME);
+ }
+
+ public void setThreadAttrName(String threadAttrName) {
+ customAttrNames.put(THREAD_ATTR_NAME, threadAttrName);
+ }
+
+ public String getMdcAttrName() {
+ return customAttrNames.get(MDC_ATTR_NAME);
+ }
+
+ public void setMdcAttrName(String mdcAttrName) {
+ customAttrNames.put(MDC_ATTR_NAME, mdcAttrName);
+ }
+
+ public String getLoggerAttrName() {
+ return customAttrNames.get(LOGGER_ATTR_NAME);
+ }
+
+ public void setLoggerAttrName(String loggerAttrName) {
+ customAttrNames.put(LOGGER_ATTR_NAME, loggerAttrName);
+ }
+
+ public String getFormattedMessageAttrName() {
+ return customAttrNames.get(FORMATTED_MESSAGE_ATTR_NAME);
+ }
+
+ public void setFormattedMessageAttrName(String formattedMessageAttrName) {
+ customAttrNames.put(FORMATTED_MESSAGE_ATTR_NAME, formattedMessageAttrName);
+ }
+
+ public String getMessageAttrName() {
+ return customAttrNames.get(MESSAGE_ATTR_NAME);
+ }
+
+ public void setMessageAttrName(String messageAttrName) {
+ customAttrNames.put(MESSAGE_ATTR_NAME, messageAttrName);
+ }
+
+ public String getContextAttrName() {
+ return customAttrNames.get(CONTEXT_ATTR_NAME);
+ }
+
+ public void setContextAttrName(String contextAttrName) {
+ customAttrNames.put(CONTEXT_ATTR_NAME, contextAttrName);
+ }
+
+ public String getExceptionAttrName() {
+ return customAttrNames.get(EXCEPTION_ATTR_NAME);
+ }
+
+ public void setExceptionAttrName(String exceptionAttrName) {
+ customAttrNames.put(EXCEPTION_ATTR_NAME, exceptionAttrName);
+ }
+}
diff --git a/json/classic/src/test/input/json/customKeysJsonLayout.xml b/json/classic/src/test/input/json/customKeysJsonLayout.xml
new file mode 100644
index 0000000..8b722e2
--- /dev/null
+++ b/json/classic/src/test/input/json/customKeysJsonLayout.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+ myLoggerName
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/ContextUtil.java b/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/ContextUtil.java
new file mode 100644
index 0000000..acbf868
--- /dev/null
+++ b/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/ContextUtil.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2016, The logback-contrib developers. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under
+ * either the terms of the Eclipse Public License v1.0 as published by
+ * the Eclipse Foundation
+ *
+ * or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ */
+package ch.qos.logback.contrib.json.classic;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+
+/**
+ * @author Matej Lazar
+ */
+public class ContextUtil {
+
+ public static void reconfigure(LoggerContext context, String file) throws JoranException {
+ context.reset();
+ JoranConfigurator jc = new JoranConfigurator();
+ jc.setContext(context);
+ jc.doConfigure(file);
+ }
+}
diff --git a/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/CustomKeysJsonLayoutTest.java b/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/CustomKeysJsonLayoutTest.java
new file mode 100644
index 0000000..8e93e96
--- /dev/null
+++ b/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/CustomKeysJsonLayoutTest.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2016, The logback-contrib developers. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under
+ * either the terms of the Eclipse Public License v1.0 as published by
+ * the Eclipse Foundation
+ *
+ * or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ */
+package ch.qos.logback.contrib.json.classic;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.ConsoleAppender;
+import ch.qos.logback.core.Layout;
+import ch.qos.logback.core.encoder.LayoutWrappingEncoder;
+import ch.qos.logback.core.joran.spi.JoranException;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.slf4j.Logger.ROOT_LOGGER_NAME;
+
+/**
+ * @author Matej Lazar
+ */
+public class CustomKeysJsonLayoutTest {
+ private LoggerContext context = new LoggerContext();
+
+ @Test
+ public void shouldProduceJsonWithCustomKey() throws IOException, JoranException {
+ ContextUtil.reconfigure(context, "src/test/input/json/customKeysJsonLayout.xml");
+ String message = "Firestarter.";
+ Logger logger = context.getLogger(ROOT_LOGGER_NAME);
+ ILoggingEvent logEvent = new LoggingEvent("my.class.name", logger, Level.INFO, message, null, null);
+
+ ConsoleAppender appender = (ConsoleAppender) logger.getAppender("STR_LIST");
+ LayoutWrappingEncoder encoder = (LayoutWrappingEncoder) appender.getEncoder();
+ Layout customKeysJsonLayout = encoder.getLayout();
+
+ String log = customKeysJsonLayout.doLayout(logEvent);
+
+ assertThat(log, containsString(String.format("%s=%s", "myLoggerName", logger.getName())));
+ assertThat(log, containsString(String.format("%s=%s", JsonLayout.LEVEL_ATTR_NAME, Level.INFO)));
+ assertThat(log, containsString(String.format("%s=%s", JsonLayout.FORMATTED_MESSAGE_ATTR_NAME, message)));
+ }
+}
\ No newline at end of file
diff --git a/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/JsonLayoutTest.java b/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/JsonLayoutTest.java
index 1732b64..8e3d861 100644
--- a/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/JsonLayoutTest.java
+++ b/json/classic/src/test/java/ch/qos/logback/contrib/json/classic/JsonLayoutTest.java
@@ -15,10 +15,8 @@
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
-import ch.qos.logback.core.joran.spi.JoranException;
import org.junit.Test;
import org.slf4j.LoggerFactory;
@@ -39,13 +37,6 @@ public class JsonLayoutTest {
private LoggerContext context = new LoggerContext();
- private void configure(String file) throws JoranException {
- context.reset();
- JoranConfigurator jc = new JoranConfigurator();
- jc.setContext(context);
- jc.doConfigure(file);
- }
-
@Test
public void addToJsonMap() throws Exception {
Map map = new LinkedHashMap();
@@ -102,7 +93,7 @@ public void addMapToJsonMap() throws Exception {
@Test
public void jsonLayout() throws Exception {
- configure("src/test/input/json/jsonLayout.xml");
+ ContextUtil.reconfigure(context, "src/test/input/json/jsonLayout.xml");
String loggerName = "ROOT";
String message = "Info message";
String debugMessage = "Debug message";