You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2017/06/01 03:04:51 UTC

logging-log4j2 git commit: [LOG4J2-1294] The JMS Appender should use a JMS MapMessage for a Log4j MapMessage.

Repository: logging-log4j2
Updated Branches:
  refs/heads/master dc26e2387 -> e89ac6e5b


[LOG4J2-1294] The JMS Appender should use a JMS MapMessage for a Log4j
MapMessage.

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/e89ac6e5
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/e89ac6e5
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/e89ac6e5

Branch: refs/heads/master
Commit: e89ac6e5b16d15497c12758665dbbfb1534eb13d
Parents: dc26e23
Author: Gary Gregory <gg...@apache.org>
Authored: Wed May 31 20:04:48 2017 -0700
Committer: Gary Gregory <gg...@apache.org>
Committed: Wed May 31 20:04:48 2017 -0700

----------------------------------------------------------------------
 .../appender/mom/activemq/JmsAppenderIT.java    | 222 +++++++++++--------
 .../log4j/core/appender/mom/JmsManager.java     |  37 +++-
 .../log4j/core/layout/MessageLayout.java        |  66 ++++++
 src/changes/changes.xml                         |   3 +
 4 files changed, 229 insertions(+), 99 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e89ac6e5/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIT.java
----------------------------------------------------------------------
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIT.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIT.java
index 4e03e46..b0bf594 100644
--- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIT.java
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/mom/activemq/JmsAppenderIT.java
@@ -17,11 +17,16 @@
 
 package org.apache.logging.log4j.core.appender.mom.activemq;
 
+import static org.junit.Assert.assertEquals;
+
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+
 import javax.jms.JMSException;
 import javax.jms.Message;
 import javax.jms.MessageConsumer;
@@ -31,114 +36,145 @@ import javax.jms.ObjectMessage;
 import org.apache.activemq.jndi.ActiveMQInitialContextFactory;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.categories.Appenders;
+import org.apache.logging.log4j.core.Layout;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.appender.mom.JmsAppender;
 import org.apache.logging.log4j.core.appender.mom.JmsManager;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.layout.MessageLayout;
 import org.apache.logging.log4j.core.layout.SerializedLayout;
 import org.apache.logging.log4j.core.net.JndiManager;
+import org.apache.logging.log4j.message.MapMessage;
 import org.apache.logging.log4j.message.SimpleMessage;
-import org.junit.AfterClass;
+import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import static org.junit.Assert.*;
-
 /**
  * Integration test for JmsAppender using an embedded ActiveMQ broker.
  */
 @Category(Appenders.Jms.class)
 public class JmsAppenderIT {
 
-    private static final String KEY_SERIALIZABLE_PACKAGES = "org.apache.activemq.SERIALIZABLE_PACKAGES";
-
-    private static JmsManager jmsManager;
-
-    private JmsAppender appender;
-
-    @BeforeClass
-    public static void setUpClass() {
-        System.setProperty(KEY_SERIALIZABLE_PACKAGES,
-                "org.apache.logging.log4j.core.impl,org.apache.logging.log4j.util,org.apache.logging.log4j,java.rmi");
-        final Properties additional = new Properties();
-        additional.setProperty("queue.TestQueue", "TestQueue");
-        final JndiManager jndiManager = JndiManager.getJndiManager(ActiveMQInitialContextFactory.class.getName(),
-            "vm://localhost?broker.persistent=false", null, null, null, additional);
-        jmsManager = JmsManager.getJmsManager("JmsManager", jndiManager, "ConnectionFactory", "TestQueue", null, null);
-    }
-
-    @AfterClass
-    public static void tearDownClass() {
-        jmsManager.close();
-        System.getProperties().remove(KEY_SERIALIZABLE_PACKAGES);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        // @formatter:off
-        appender = JmsAppender.newBuilder().
-            setName("JmsAppender").
-            setLayout(SerializedLayout.createLayout()).
-            setIgnoreExceptions(true).
-            setJmsManager(jmsManager).
-            build();
-        // @formatter:off
-        appender.start();
-    }
-
-    @Test
-    public void testLogToQueue() throws Exception {
-        final int messageCount = 100;
-        final MessageConsumer messageConsumer = jmsManager.createMessageConsumer();
-        final JmsQueueConsumer consumer = new JmsQueueConsumer(messageCount);
-        messageConsumer.setMessageListener(consumer);
-        final String messageText = "Hello, World!";
-        final String loggerName = this.getClass().getName();
-        for (int i = 0; i < messageCount; i++) {
-            final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName(loggerName) //
-                    .setLoggerFqcn(loggerName).setLevel(Level.INFO) //
-                    .setMessage(new SimpleMessage(messageText)).setThreadName(Thread.currentThread().getName()) //
-                    .setTimeMillis(System.currentTimeMillis()).build();
-            appender.append(event);
-        }
-        consumer.awaitAndAssertAllMessagesConsumed();
-    }
-
-    private static class JmsQueueConsumer implements MessageListener {
-
-        private final int messageCount;
-        private final CountDownLatch countDownLatch;
-        private final Collection<LogEvent> events;
-
-        private JmsQueueConsumer(final int messageCount) {
-            this.messageCount = messageCount;
-            this.countDownLatch = new CountDownLatch(messageCount);
-            this.events = new ArrayList<>(messageCount);
-        }
-
-        @Override
-        public void onMessage(final Message message) {
-            try {
-                consume((ObjectMessage) message);
-            } catch (final JMSException e) {
-                e.printStackTrace();
-            }
-        }
-
-        private void consume(final ObjectMessage message) throws JMSException {
-            try {
-                final LogEvent event = (LogEvent) message.getObject();
-                events.add(event);
-            } finally {
-                countDownLatch.countDown();
-            }
-        }
-
-        public void awaitAndAssertAllMessagesConsumed() throws InterruptedException {
-            countDownLatch.await(5, TimeUnit.SECONDS);
-            assertEquals(messageCount, events.size());
-        }
-    }
+	private static final String KEY_SERIALIZABLE_PACKAGES = "org.apache.activemq.SERIALIZABLE_PACKAGES";
+
+	private JmsManager jmsManager;
+
+	private JmsAppender appender;
+
+	@Before
+	public void setUpClass() {
+		System.setProperty(KEY_SERIALIZABLE_PACKAGES,
+				"org.apache.logging.log4j.core.impl,org.apache.logging.log4j.util,org.apache.logging.log4j,java.rmi");
+		final Properties additional = new Properties();
+		additional.setProperty("queue.TestQueue", "TestQueue");
+		final JndiManager jndiManager = JndiManager.getJndiManager(ActiveMQInitialContextFactory.class.getName(),
+				"vm://localhost?broker.persistent=false", null, null, null, additional);
+		jmsManager = JmsManager.getJmsManager("JmsManager", jndiManager, "ConnectionFactory", "TestQueue", null, null);
+	}
+
+	@After
+	public void tearDownClass() {
+		jmsManager.close();
+		System.getProperties().remove(KEY_SERIALIZABLE_PACKAGES);
+	}
+
+	private void setUp(Layout<?> layout) throws Exception {
+		// @formatter:off
+		appender = JmsAppender.newBuilder()
+				.setName("JmsAppender")
+				.setLayout(layout)
+				.setIgnoreExceptions(true)
+				.setJmsManager(jmsManager)
+				.build();
+		// @formatter:off
+		appender.start();
+	}
+
+	@Test
+	public void testLogMapMessageToQueue() throws Exception {
+		setUp(MessageLayout.createLayout());
+		final int messageCount = 100;
+		final MessageConsumer messageConsumer = jmsManager.createMessageConsumer();
+		final JmsQueueConsumer consumer = new JmsQueueConsumer(messageCount, javax.jms.MapMessage.class);
+		messageConsumer.setMessageListener(consumer);
+		final String messageText = "Hello, World!";
+		final String loggerName = this.getClass().getName();
+		for (int i = 0; i < messageCount; i++) {
+			Map<String, String> map = new HashMap<>();
+			map.put("messageText", messageText);
+			map.put("threadName", Thread.currentThread().getName());
+			final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName(loggerName) //
+					.setLoggerFqcn(loggerName).setLevel(Level.INFO) //
+					.setMessage(new MapMessage(map)) //
+					.setTimeMillis(System.currentTimeMillis()).build();
+			appender.append(event);
+		}
+		consumer.awaitAndAssertAllMessagesConsumed();
+	}
+
+	@Test
+	public void testLogObjectMessageToQueue() throws Exception {
+		setUp(SerializedLayout.createLayout());
+		final int messageCount = 100;
+		final MessageConsumer messageConsumer = jmsManager.createMessageConsumer();
+		final JmsQueueConsumer consumer = new JmsQueueConsumer(messageCount, ObjectMessage.class);
+		messageConsumer.setMessageListener(consumer);
+		final String messageText = "Hello, World!";
+		final String loggerName = this.getClass().getName();
+		for (int i = 0; i < messageCount; i++) {
+			final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName(loggerName) //
+					.setLoggerFqcn(loggerName).setLevel(Level.INFO) //
+					.setMessage(new SimpleMessage(messageText)).setThreadName(Thread.currentThread().getName()) //
+					.setTimeMillis(System.currentTimeMillis()).build();
+			appender.append(event);
+		}
+		consumer.awaitAndAssertAllMessagesConsumed();
+	}
+
+	private static class JmsQueueConsumer implements MessageListener {
+
+		private final int messageCount;
+		private final Class<? extends Message> messageClass;
+		private final CountDownLatch countDownLatch;
+		private final Collection<Object> events;
+
+		private JmsQueueConsumer(final int messageCount, Class<? extends Message> messageClass) {
+			this.messageCount = messageCount;
+			this.messageClass = messageClass;
+			this.countDownLatch = new CountDownLatch(messageCount);
+			this.events = new ArrayList<>(messageCount);
+		}
+
+		@Override
+		public void onMessage(final Message message) {
+			try {
+				try {
+					final Object event;
+					Assert.assertTrue(String.format("Expected type '%s' to be an instance of %s", message.getClass(), messageClass),
+							messageClass.isAssignableFrom(message.getClass()));
+					if (message instanceof ObjectMessage) {
+						event = ((ObjectMessage) message).getObject();
+					} else if (message instanceof javax.jms.MapMessage) {
+						event = message;
+					} else {
+						Assert.fail("Unexpected Message type: " + message);
+						event = null;
+					}
+					events.add(event);
+				} finally {
+					countDownLatch.countDown();
+				}
+			} catch (final JMSException e) {
+				e.printStackTrace();
+			}
+		}
+
+		public void awaitAndAssertAllMessagesConsumed() throws InterruptedException {
+			countDownLatch.await(5, TimeUnit.SECONDS);
+			assertEquals(messageCount, events.size());
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e89ac6e5/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
index 4ff0f05..db47743 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java
@@ -18,12 +18,14 @@
 package org.apache.logging.log4j.core.appender.mom;
 
 import java.io.Serializable;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 import javax.jms.Connection;
 import javax.jms.ConnectionFactory;
 import javax.jms.Destination;
 import javax.jms.JMSException;
+import javax.jms.MapMessage;
 import javax.jms.Message;
 import javax.jms.MessageConsumer;
 import javax.jms.MessageProducer;
@@ -107,13 +109,23 @@ public class JmsManager extends AbstractManager {
     }
 
     /**
-     * Creates a TextMessage or ObjectMessage from a Serializable object. For instance, when using a text-based
-     * {@link org.apache.logging.log4j.core.Layout} such as {@link org.apache.logging.log4j.core.layout.PatternLayout},
-     * the {@link org.apache.logging.log4j.core.LogEvent} message will be serialized to a String. When using a
-     * layout such as {@link org.apache.logging.log4j.core.layout.SerializedLayout}, the LogEvent message will be
-     * serialized as a Java object.
+     * Creates a TextMessage, MapMessage, or ObjectMessage from a Serializable object.
+     * <p>
+     * For instance, when using a text-based {@link org.apache.logging.log4j.core.Layout} such as
+     * {@link org.apache.logging.log4j.core.layout.PatternLayout}, the {@link org.apache.logging.log4j.core.LogEvent}
+     * message will be serialized to a String.
+     * </p>
+     * <p>
+     * When using a layout such as {@link org.apache.logging.log4j.core.layout.SerializedLayout}, the LogEvent message
+     * will be serialized as a Java object.
+     * </p>
+     * <p>
+     * When using a layout such as {@link org.apache.logging.log4j.core.layout.MessageLayout} and the LogEvent message
+     * is a Log4j MapMessage, the message will be serialized as a JMS MapMessage.
+     * </p>
      *
-     * @param object The LogEvent or String message to wrap.
+     * @param object
+     *            The LogEvent or String message to wrap.
      * @return A new JMS message containing the provided object.
      * @throws JMSException
      */
@@ -121,9 +133,22 @@ public class JmsManager extends AbstractManager {
         if (object instanceof String) {
             return this.session.createTextMessage((String) object);
         }
+        else if (object instanceof org.apache.logging.log4j.message.MapMessage) {
+            return map((org.apache.logging.log4j.message.MapMessage) object, this.session.createMapMessage());
+        }
         return this.session.createObjectMessage(object);
     }
 
+    private MapMessage map(org.apache.logging.log4j.message.MapMessage log4jMapMessage, MapMessage jmsMapMessage)
+            throws JMSException {
+        // Call getData() only once.
+        final Map<String, String> data = log4jMapMessage.getData();
+        for (Map.Entry<String, String> entry : data.entrySet()) {
+            jmsMapMessage.setString(entry.getKey(), entry.getValue());
+        }
+        return jmsMapMessage;
+    }
+
     @Override
     protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
         boolean closed = true;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e89ac6e5/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MessageLayout.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MessageLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MessageLayout.java
new file mode 100644
index 0000000..9adb8ee
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/MessageLayout.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.logging.log4j.core.layout;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.message.Message;
+
+/**
+ * Formats a {@link LogEvent} in its {@link Message} form.
+ * <p>
+ * Useful in combination with a JMS Appender to map a Log4j {@link org.apache.logging.log4j.message.MapMessage} to a JMS
+ * {@link javax.jms.MapMessage}.
+ * </p>
+ */
+@Plugin(name = "MessageLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
+public class MessageLayout extends AbstractLayout<Message> {
+
+    public MessageLayout(Configuration configuration, byte[] header, byte[] footer) {
+        super(configuration, header, footer);
+    }
+
+    public MessageLayout() {
+        super(null, null, null);
+    }
+
+    @Override
+    public byte[] toByteArray(LogEvent event) {
+        return null;
+    }
+
+    @Override
+    public Message toSerializable(LogEvent event) {
+        return event.getMessage();
+    }
+
+    @Override
+    public String getContentType() {
+        return null;
+    }
+
+    @PluginFactory
+    public static Layout<?> createLayout() {
+        return new MessageLayout();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e89ac6e5/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 3863f37..4936876 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -73,6 +73,9 @@
       <action issue="LOG4J2-1860" dev="mikes" type="add">
         Shortcut to add Property and KeyValuePair component in ConfigurationBuilder.
       </action>
+      <action issue="LOG4J2-1294" dev="ggregory" type="add">
+        The JMS Appender should use a JMS MapMessage for a Log4j MapMessage.
+      </action>
       <action issue="LOG4J2-1868" dev="ggregory" type="update">
         Update ZeroMQ's JeroMQ from 0.3.6 to 0.4.0.
       </action>