JMS Log Handler
angeloimm Oct 14, 2013 5:03 AMHi there
I needed to use JMS in order to remotely log on a server; for the production I'll use EAP 6.0.1 but, for my personal tests, I'm using JBoss AS 7.1.1.Final "Brontes"
I did some researchs and it seems there is no JMS Appender for logging (note I can't configure JBoss in order to use log4j)
So I decided to write my custom Handler.
Here there is the code:
package logging.jms;
import java.util.Properties;
import java.util.logging.ErrorManager;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.Topic;
import javax.naming.Context;
import javax.naming.InitialContext;
public class JMSHandler extends Handler {
private String topicName;
private String connectionFactoryName;
private String initialContextFactory;
private String providedUrl;
private String securityUsername;
private String securityPassword;
private Connection connection;
private MessageProducer publisher;
private Session session;
private Context ctx;
@Override
public void publish(LogRecord record) {
try {
if( isLoggable(record) && initialize() ){
String recordMessage = getFormatter().format(record);
publisher.send(session.createTextMessage(recordMessage));
}
} catch (Exception e) {
reportError("Errore nel processamento del record", e, ErrorManager.GENERIC_FAILURE);
}
}
@Override
public void flush() {
//Nothing to flush
}
@Override
public void close() throws SecurityException {
try {
//Chiudo il publisher
if( publisher != null ){
publisher.close();
}
//Chiudo la sessione
if(session != null){
session.close();
}
//Chiudo la connessione
if( connection != null ){
connection.close();
}
//Chiudo il contesto
if( ctx != null ){
ctx.close();
}
} catch (Exception e) {
reportError("Errore nella chiusura dell'handler", e, ErrorManager.CLOSE_FAILURE);
}
}
private synchronized boolean initialize() throws Exception{
if( publisher == null ){
System.out.println("Inizializzazione jms handler in corso");
ctx = getInitialContext();
System.out.println("Contesto creato");
ConnectionFactory cf = (ConnectionFactory)ctx.lookup(getConnectionFactoryName());
System.out.println("ConnectionFactory creata");
Topic logTopic = (Topic)ctx.lookup(getTopicName());
System.out.println("Topic lookup done");
connection = cf.createConnection();
System.out.println("Connection estabilished");
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
publisher = session.createProducer(logTopic);
connection.start();
System.out.println("Connection started");
}
return true;
}
public String getTopicName() {
return topicName;
}
public void setTopicName(String topicName) {
this.topicName = topicName;
}
public String getConnectionFactoryName() {
return connectionFactoryName;
}
public void setConnectionFactoryName(String connectionFactoryName) {
this.connectionFactoryName = connectionFactoryName;
}
public Context getInitialContext() throws Exception {
Properties p = new Properties( );
p.put(Context.INITIAL_CONTEXT_FACTORY, getInitialContextFactory());
p.put(Context.PROVIDER_URL, getProvidedUrl());
p.put(Context.SECURITY_PRINCIPAL, getSecurityUsername());
p.put(Context.SECURITY_CREDENTIALS, getSecurityPassword());
return new InitialContext(p);
}
public String getProvidedUrl() {
return providedUrl;
}
public void setProvidedUrl(String providedUrl) {
this.providedUrl = providedUrl;
}
public String getInitialContextFactory() {
return initialContextFactory;
}
public void setInitialContextFactory(String initialContextFactory) {
this.initialContextFactory = initialContextFactory;
}
public String getSecurityUsername() {
return securityUsername;
}
public void setSecurityUsername(String securityUsername) {
this.securityUsername = securityUsername;
}
public String getSecurityPassword() {
return securityPassword;
}
public void setSecurityPassword(String securityPassword) {
this.securityPassword = securityPassword;
}
}
Then I created my module.xml file since I want to deploy this handler as a JBoss module. Here there is the file content:
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="loggers"> <resources> <resource-root path="JMSHandler.jar"/> </resources> <dependencies> <module name="org.jboss.remote-naming" /> <module name="org.jboss.logging"/> <module name="org.jboss.remoting3"/> <module name="javax.api"/> <module name="javax.jms.api"/> </dependencies> </module>
I added both the modul.xml and the JMSHandler.jar files in ${JBOSS_HOME}/modules/loggers/main
In my "standalone-full.xml" file I added the following:
<custom-handler name="JMSAppender" class="logging.jms.JMSHandler" module="loggers">
<level name="INFO" />
<formatter>
<pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n" />
</formatter>
<properties>
<property name="topicName" value="jms/topic/logTopic" />
<property name="connectionFactoryName" value="jms/RemoteConnectionFactory" />
<property name="initialContextFactory" value="org.jboss.naming.remote.client.InitialContextFactory" />
<property name="providedUrl" value="remote://localhost:4447" />
<property name="securityUsername" value="xxxx" />
<property name="securityPassword" value="xxxx" />
</properties>
</custom-handler>
It seems to me all correct, but when when I start the server I get this error:
10:44:43,524 INFO [stdout] (ServerService Thread Pool -- 32) Inizializzazione jms handler in corso 10:44:43,538 ERROR [stderr] (ServerService Thread Pool -- 32) java.util.logging.ErrorManager: 0: Errore nel processamento del record 10:44:43,552 ERROR [stderr] (ServerService Thread Pool -- 32) javax.naming.NoInitialContextException: Cannot instantiate class: org.jboss.naming.remote.client.InitialContextFactory [Root exception is java.lang.ClassNotFoundException: org.jboss.naming.remote.client.InitialContextFactory from [Module "org.jboss.as.controller:main" from local module loader @b23210 (roots: /dati/servers/jboss-as-7.1.1.Final/modules)]] 10:44:43,562 INFO [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 37) JBAS010280: Activating Infinispan subsystem. 10:44:43,569 ERROR [stderr] (ServerService Thread Pool -- 32) at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:657) 10:44:43,572 INFO [org.jboss.as.jacorb] (ServerService Thread Pool -- 38) JBAS016300: Activating JacORB Subsystem 10:44:43,576 ERROR [stderr] (ServerService Thread Pool -- 32) at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288) 10:44:43,587 ERROR [stderr] (ServerService Thread Pool -- 32) at javax.naming.InitialContext.init(InitialContext.java:223) 10:44:43,592 ERROR [stderr] (ServerService Thread Pool -- 32) at javax.naming.InitialContext.<init>(InitialContext.java:197)
By looking the error, it seems to me that JBoss is not able in finding the class org.jboss.naming.remote.client.InitialContextFactory but in my module.xml I added the dependency to <module name="org.jboss.remote-naming" /> where I checked and the class is present
Can, kindly, anybody suggest to me where I'm wrong?
Thank you
Angelo