001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 018package org.apache.logging.log4j.core.appender.mom; 019 020import java.io.Serializable; 021import javax.jms.JMSException; 022import javax.jms.Message; 023import javax.jms.MessageProducer; 024 025import org.apache.logging.log4j.core.Appender; 026import org.apache.logging.log4j.core.Filter; 027import org.apache.logging.log4j.core.Layout; 028import org.apache.logging.log4j.core.LogEvent; 029import org.apache.logging.log4j.core.appender.AbstractAppender; 030import org.apache.logging.log4j.core.appender.AppenderLoggingException; 031import org.apache.logging.log4j.core.config.Node; 032import org.apache.logging.log4j.core.config.plugins.Plugin; 033import org.apache.logging.log4j.core.config.plugins.PluginAliases; 034import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; 035import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 036import org.apache.logging.log4j.core.config.plugins.PluginElement; 037import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; 038import org.apache.logging.log4j.core.layout.SerializedLayout; 039import org.apache.logging.log4j.core.net.JndiManager; 040 041/** 042 * Generic JMS Appender plugin for both queues and topics. This Appender replaces the previous split ones. However, 043 * configurations set up for the 2.0 version of the JMS appenders will still work. 044 */ 045@Plugin(name = "JMS", category = Node.CATEGORY, elementType = Appender.ELEMENT_TYPE, printObject = true) 046@PluginAliases({"JMSQueue", "JMSTopic"}) 047public class JmsAppender extends AbstractAppender { 048 049 private final JmsManager manager; 050 private final MessageProducer producer; 051 052 protected JmsAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout, 053 final boolean ignoreExceptions, final JmsManager manager) 054 throws JMSException { 055 super(name, filter, layout, ignoreExceptions); 056 this.manager = manager; 057 this.producer = this.manager.createMessageProducer(); 058 } 059 060 @Override 061 public void append(final LogEvent event) { 062 try { 063 final Message message = this.manager.createMessage(getLayout().toSerializable(event)); 064 message.setJMSTimestamp(event.getTimeMillis()); 065 this.producer.send(message); 066 } catch (final JMSException e) { 067 throw new AppenderLoggingException(e); 068 } 069 } 070 071 @Override 072 public void stop() { 073 this.manager.release(); 074 super.stop(); 075 } 076 077 @PluginBuilderFactory 078 public static Builder newBuilder() { 079 return new Builder(); 080 } 081 082 public static class Builder implements org.apache.logging.log4j.core.util.Builder<JmsAppender> { 083 084 @PluginBuilderAttribute 085 @Required(message = "A name for the JmsAppender must be specified") 086 private String name; 087 088 @PluginBuilderAttribute 089 private String factoryName; 090 091 @PluginBuilderAttribute 092 private String providerUrl; 093 094 @PluginBuilderAttribute 095 private String urlPkgPrefixes; 096 097 @PluginBuilderAttribute 098 private String securityPrincipalName; 099 100 @PluginBuilderAttribute(sensitive = true) 101 private String securityCredentials; 102 103 @PluginBuilderAttribute 104 @Required(message = "A javax.jms.ConnectionFactory JNDI name must be specified") 105 private String factoryBindingName; 106 107 @PluginBuilderAttribute 108 @PluginAliases({"queueBindingName", "topicBindingName"}) 109 @Required(message = "A javax.jms.Destination JNDI name must be specified") 110 private String destinationBindingName; 111 112 @PluginBuilderAttribute 113 private String username; 114 115 @PluginBuilderAttribute(sensitive = true) 116 private String password; 117 118 @PluginElement("Layout") 119 private Layout<? extends Serializable> layout = SerializedLayout.createLayout(); 120 121 @PluginElement("Filter") 122 private Filter filter; 123 124 @PluginBuilderAttribute 125 private boolean ignoreExceptions = true; 126 127 private Builder() { 128 } 129 130 public Builder setName(final String name) { 131 this.name = name; 132 return this; 133 } 134 135 public Builder setFactoryName(final String factoryName) { 136 this.factoryName = factoryName; 137 return this; 138 } 139 140 public Builder setProviderUrl(final String providerUrl) { 141 this.providerUrl = providerUrl; 142 return this; 143 } 144 145 public Builder setUrlPkgPrefixes(final String urlPkgPrefixes) { 146 this.urlPkgPrefixes = urlPkgPrefixes; 147 return this; 148 } 149 150 public Builder setSecurityPrincipalName(final String securityPrincipalName) { 151 this.securityPrincipalName = securityPrincipalName; 152 return this; 153 } 154 155 public Builder setSecurityCredentials(final String securityCredentials) { 156 this.securityCredentials = securityCredentials; 157 return this; 158 } 159 160 public Builder setFactoryBindingName(final String factoryBindingName) { 161 this.factoryBindingName = factoryBindingName; 162 return this; 163 } 164 165 public Builder setDestinationBindingName(final String destinationBindingName) { 166 this.destinationBindingName = destinationBindingName; 167 return this; 168 } 169 170 public Builder setUsername(final String username) { 171 this.username = username; 172 return this; 173 } 174 175 public Builder setPassword(final String password) { 176 this.password = password; 177 return this; 178 } 179 180 public Builder setLayout(final Layout<? extends Serializable> layout) { 181 this.layout = layout; 182 return this; 183 } 184 185 public Builder setFilter(final Filter filter) { 186 this.filter = filter; 187 return this; 188 } 189 190 public Builder setIgnoreExceptions(final boolean ignoreExceptions) { 191 this.ignoreExceptions = ignoreExceptions; 192 return this; 193 } 194 195 @Override 196 public JmsAppender build() { 197 final JndiManager jndiManager = JndiManager.getJndiManager(factoryName, providerUrl, urlPkgPrefixes, 198 securityPrincipalName, securityCredentials, null); 199 final JmsManager jmsManager = JmsManager.getJmsManager(name, jndiManager, factoryBindingName, 200 destinationBindingName, username, password); 201 try { 202 return new JmsAppender(name, filter, layout, ignoreExceptions, jmsManager); 203 } catch (final JMSException e) { 204 LOGGER.error("Error creating JmsAppender [{}].", name, e); 205 return null; 206 } 207 } 208 } 209 210}