JMSQueueAppender の使用方法を調べようとしていましたが、同じ方法に関する適切な指示がありませんでした。少し試行錯誤した後、log4j (独自の JMSQueueAppender クラス) を使用して JMSQueueAppender を構成することができました。
以下は、log4j.properties ファイルの構成です。
log4j.rootLogger=INFO, stdout, jms
## Be sure that ActiveMQ messages are not logged to 'jms' appender
log4j.logger.org.apache.activemq=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c - %m%n
## Configure 'jms' appender. You'll also need jndi.properties file in order to make it work
log4j.appender.jms=com.util.JMSQueueAppender
log4j.appender.jms.initialContextFactory=org.apache.activemq.jndi.ActiveMQInitialContextFactory
log4j.appender.jms.providerUrl=tcp://localhost:61616
log4j.appender.jms.queueBindingName=myQueue
log4j.appender.jms.queueConnectionFactoryBindingName=QueueConnectionFactory
jndi.properties ファイルは次のようになります (プロジェクト ディレクトリの classpath に配置する必要があることに注意してください。それは src ディレクトリに配置する必要があります)。
queue.myQueue=myQueue
JMSQueueAppender クラスは次のようになります (このコードでは、パッケージ構造 com.util にあります)。
public class JMSQueueAppender extends AppenderSkeleton {
protected QueueConnection queueConnection;
protected QueueSession queueSession;
protected QueueSender queueSender;
protected Queue queue;
String initialContextFactory;
String providerUrl;
String queueBindingName;
String queueConnectionFactoryBindingName;
public
JMSQueueAppender() {
}
/**
* The <b>InitialContextFactory</b> option takes a string value.
* Its value, along with the <b>ProviderUrl</b> option will be used
* to get the InitialContext.
*/
public void setInitialContextFactory(String initialContextFactory) {
this.initialContextFactory = initialContextFactory;
}
/**
* Returns the value of the <b>InitialContextFactory</b> option.
*/
public String getInitialContextFactory() {
return initialContextFactory;
}
/**
* The <b>ProviderUrl</b> option takes a string value.
* Its value, along with the <b>InitialContextFactory</b> option will be used
* to get the InitialContext.
*/
public void setProviderUrl(String providerUrl) {
this.providerUrl = providerUrl;
}
/**
* Returns the value of the <b>ProviderUrl</b> option.
*/
public String getProviderUrl() {
return providerUrl;
}
/**
* The <b>QueueConnectionFactoryBindingName</b> option takes a
* string value. Its value will be used to lookup the appropriate
* <code>QueueConnectionFactory</code> from the JNDI context.
*/
public void setQueueConnectionFactoryBindingName(String queueConnectionFactoryBindingName) {
this.queueConnectionFactoryBindingName = queueConnectionFactoryBindingName;
}
/**
* Returns the value of the <b>QueueConnectionFactoryBindingName</b> option.
*/
public String getQueueConnectionFactoryBindingName() {
return queueConnectionFactoryBindingName;
}
/**
* The <b>QueueBindingName</b> option takes a
* string value. Its value will be used to lookup the appropriate
* destination <code>Queue</code> from the JNDI context.
*/
public void setQueueBindingName(String queueBindingName) {
this.queueBindingName = queueBindingName;
}
/**
Returns the value of the <b>QueueBindingName</b> option.
*/
public String getQueueBindingName() {
return queueBindingName;
}
/**
* Overriding this method to activate the options for this class
* i.e. Looking up the Connection factory ...
*/
public void activateOptions() {
QueueConnectionFactory queueConnectionFactory;
try {
Context ctx = getInitialContext();
queueConnectionFactory = (QueueConnectionFactory) ctx.lookup(queueConnectionFactoryBindingName);
queueConnection = queueConnectionFactory.createQueueConnection();
queueSession = queueConnection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) ctx.lookup(queueBindingName);
queueSender = queueSession.createSender(queue);
queueConnection.start();
ctx.close();
} catch(Exception e) {
errorHandler.error("Error while activating options for appender named ["+name+
"].", e, ErrorCode.GENERIC_FAILURE);
}
}
protected InitialContext getInitialContext() throws NamingException {
try {
Hashtable ht = new Hashtable();
//Populate property hashtable with data to retrieve the context.
ht.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
ht.put(Context.PROVIDER_URL, providerUrl);
return (new InitialContext(ht));
} catch (NamingException ne) {
LogLog.error("Could not get initial context with ["+initialContextFactory + "] and [" + providerUrl + "].");
throw ne;
}
}
protected boolean checkEntryConditions() {
String fail = null;
if(this.queueConnection == null) {
fail = "No QueueConnection";
} else if(this.queueSession == null) {
fail = "No QueueSession";
} else if(this.queueSender == null) {
fail = "No QueueSender";
}
if(fail != null) {
errorHandler.error(fail +" for JMSQueueAppender named ["+name+"].");
return false;
} else {
return true;
}
}
/**
* Close this JMSQueueAppender. Closing releases all resources used by the
* appender. A closed appender cannot be re-opened.
*/
public synchronized // avoid concurrent append and close operations
void close() {
if(this.closed)
return;
LogLog.debug("Closing appender ["+name+"].");
this.closed = true;
try {
if(queueSession != null)
queueSession.close();
if(queueConnection != null)
queueConnection.close();
} catch(Exception e) {
LogLog.error("Error while closing JMSQueueAppender ["+name+"].", e);
}
// Help garbage collection
queueSender = null;
queueSession = null;
queueConnection = null;
}
/**
* This method called by {@link AppenderSkeleton#doAppend} method to
* do most of the real appending work. The LoggingEvent will be
* be wrapped in an ObjectMessage to be put on the JMS queue.
*/
public void append(LoggingEvent event) {
if(!checkEntryConditions()) {
return;
}
try {
ObjectMessage msg = queueSession.createObjectMessage();
msg.setObject(event);
queueSender.send(msg);
} catch(Exception e) {
errorHandler.error("Could not send message in JMSQueueAppender ["+name+"].", e,
ErrorCode.GENERIC_FAILURE);
}
}
public boolean requiresLayout() {
return false;
}
}
Ans キュー リスナ クラスは次のようになります。
public class MyLogQueueListener implements MessageListener {
public MyLogQueueListener() throws Exception {
// create a logTopic topic consumer
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection conn = factory.createConnection();
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
Destination destination = sess.createQueue("myQueue");
// Create a MessageConsumer from the Session to the Topic or Queue
MessageConsumer consumer = sess.createConsumer(destination);
consumer.setMessageListener(this);
// log a message
Logger log = Logger.getLogger(MyLogQueueListener.class);
log.info("Test log");
// clean up
Thread.sleep(1000000);
consumer.close();
sess.close();
conn.close();
System.exit(1);
}
public static void main(String[] args) throws Exception {
new MyLogQueueListener();
}
public void onMessage(Message message) {
try {
// receive log event in your consumer
LoggingEvent event = (LoggingEvent)((ActiveMQObjectMessage)message).getObject();
System.out.println("Queue: Received log [" + event.getLevel() + "]: "+ event.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
上記のものをセットアップして機能させるのに2日かかりました。JMSQueueAppender を使用しようとしている人にとって、これが何らかの助けになることを願っています。(Web に JMSQueueAppender コードを投稿した人に特に感謝します)。