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