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 */ 017package org.apache.activemq.transport; 018 019import org.apache.activemq.broker.jmx.AnnotatedMBean; 020import org.apache.activemq.broker.jmx.ManagementContext; 021import org.apache.activemq.util.IOExceptionSupport; 022import org.apache.activemq.util.LogWriterFinder; 023import org.slf4j.Logger; 024import org.slf4j.LoggerFactory; 025import java.io.IOException; 026import javax.management.ObjectName; 027 028import static org.apache.activemq.TransportLoggerSupport.defaultJmxPort; 029 030/** 031 * Singleton class to create TransportLogger objects. 032 * When the method getInstance() is called for the first time, 033 * a TransportLoggerControlMBean is created and registered. 034 * This MBean permits enabling and disabling the logging for 035 * all TransportLogger objects at once. 036 * 037 * @author David Martin Clavo david(dot)martin(dot)clavo(at)gmail.com 038 * 039 * @see TransportLoggerControlMBean 040 */ 041public class TransportLoggerFactory { 042 043 private static final Logger LOG = LoggerFactory.getLogger(TransportLoggerFactory.class); 044 045 private static TransportLoggerFactory instance; 046 private static int lastId=0; 047 private static final LogWriterFinder logWriterFinder = new LogWriterFinder("META-INF/services/org/apache/activemq/transport/logwriters/"); 048 049 /** 050 * LogWriter that will be used if none is specified. 051 */ 052 public static String defaultLogWriterName = "default"; 053 /** 054 * If transport logging is enabled, it will be possible to control 055 * the transport loggers or not based on this value 056 */ 057 private static boolean defaultDynamicManagement = false; 058 /** 059 * If transport logging is enabled, the transport loggers will initially 060 * output or not depending on this value. 061 * This setting only has a meaning if 062 */ 063 private static boolean defaultInitialBehavior = true; 064 065 private boolean transportLoggerControlCreated = false; 066 private ManagementContext managementContext; 067 private ObjectName objectName; 068 069 /** 070 * Private constructor. 071 */ 072 private TransportLoggerFactory() { 073 } 074 075 /** 076 * Returns a TransportLoggerFactory object which can be used to create TransportLogger objects. 077 * @return a TransportLoggerFactory object 078 */ 079 public static synchronized TransportLoggerFactory getInstance() { 080 if (instance == null) { 081 instance = new TransportLoggerFactory(); 082 } 083 return instance; 084 } 085 086 public void stop() { 087 try { 088 if (this.transportLoggerControlCreated) { 089 this.managementContext.unregisterMBean(this.objectName); 090 this.managementContext.stop(); 091 this.managementContext = null; 092 } 093 } catch (Exception e) { 094 LOG.error("TransportLoggerFactory could not be stopped, reason: " + e, e); 095 } 096 097 } 098 099 /** 100 * Creates a TransportLogger object, that will be inserted in the Transport Stack. 101 * Uses the default initial behavior, the default log writer, and creates a new 102 * log4j object to be used by the TransportLogger. 103 * @param next The next Transport layer in the Transport stack. 104 * @return A TransportLogger object. 105 * @throws IOException 106 */ 107 public TransportLogger createTransportLogger(Transport next) throws IOException { 108 int id = getNextId(); 109 return createTransportLogger(next, id, createLog(id), defaultLogWriterName, defaultDynamicManagement, defaultInitialBehavior, defaultJmxPort); 110 } 111 112 /** 113 * Creates a TransportLogger object, that will be inserted in the Transport Stack. 114 * Uses the default initial behavior and the default log writer. 115 * @param next The next Transport layer in the Transport stack. 116 * @param log The log4j log that will be used by the TransportLogger. 117 * @return A TransportLogger object. 118 * @throws IOException 119 */ 120 public TransportLogger createTransportLogger(Transport next, Logger log) throws IOException { 121 return createTransportLogger(next, getNextId(), log, defaultLogWriterName, defaultDynamicManagement, defaultInitialBehavior, defaultJmxPort); 122 } 123 124 /** 125 * Creates a TransportLogger object, that will be inserted in the Transport Stack. 126 * Creates a new log4j object to be used by the TransportLogger. 127 * @param next The next Transport layer in the Transport stack. 128 * @param startLogging Specifies if this TransportLogger should be initially active or not. 129 * @param logWriterName The name or the LogWriter to be used. Different log writers can output 130 * logs with a different format. 131 * @return A TransportLogger object. 132 * @throws IOException 133 */ 134 public TransportLogger createTransportLogger(Transport next, String logWriterName, 135 boolean useJmx, boolean startLogging, int jmxport) throws IOException { 136 int id = -1; // new default to single logger 137 // allow old behaviour with incantation 138 if (!useJmx && jmxport != defaultJmxPort) { 139 id = getNextId(); 140 } 141 return createTransportLogger(next, id, createLog(id), logWriterName, useJmx, startLogging, jmxport); 142 } 143 144 145 146 /** 147 * Creates a TransportLogger object, that will be inserted in the Transport Stack. 148 * @param next The next Transport layer in the Transport stack. 149 * @param id The id of the transport logger. 150 * @param log The log4j log that will be used by the TransportLogger. 151 * @param logWriterName The name or the LogWriter to be used. Different log writers can output 152 * @param dynamicManagement Specifies if JMX will be used to switch on/off the TransportLogger to be created. 153 * @param startLogging Specifies if this TransportLogger should be initially active or not. Only has a meaning if 154 * dynamicManagement = true. 155 * @param jmxPort the port to be used by the JMX server. It should only be different from 1099 (broker's default JMX port) 156 * when it's a client that is using Transport Logging. In a broker, if the port is different from 1099, 2 JMX servers will 157 * be created, both identical, with all the MBeans. 158 * @return A TransportLogger object. 159 * @throws IOException 160 */ 161 public TransportLogger createTransportLogger(Transport next, int id, Logger log, 162 String logWriterName, boolean dynamicManagement, boolean startLogging, int jmxport) throws IOException { 163 try { 164 LogWriter logWriter = logWriterFinder.newInstance(logWriterName); 165 if (id == -1) { 166 logWriter.setPrefix(String.format("%08X: ", getNextId())); 167 } 168 TransportLogger tl = new TransportLogger (next, log, startLogging, logWriter); 169 if (dynamicManagement) { 170 synchronized (this) { 171 if (!this.transportLoggerControlCreated) { 172 this.createTransportLoggerControl(jmxport); 173 } 174 } 175 TransportLoggerView tlv = new TransportLoggerView(tl, next.toString(), id, this.managementContext); 176 tl.setView(tlv); 177 } 178 return tl; 179 } catch (Throwable e) { 180 throw IOExceptionSupport.create("Could not create log writer object for: " + logWriterName + ", reason: " + e, e); 181 } 182 } 183 184 synchronized private static int getNextId() { 185 return ++lastId; 186 } 187 188 private static Logger createLog(int id) { 189 return LoggerFactory.getLogger(TransportLogger.class.getName()+".Connection" + (id > 0 ? ":"+id : "" )); 190 } 191 192 /** 193 * Starts the management context. 194 * Creates and registers a TransportLoggerControl MBean which enables the user 195 * to enable/disable logging for all transport loggers at once. 196 */ 197 private void createTransportLoggerControl(int port) { 198 try { 199 this.managementContext = new ManagementContext(); 200 this.managementContext.setConnectorPort(port); 201 this.managementContext.start(); 202 } catch (Exception e) { 203 LOG.error("Management context could not be started, reason: " + e, e); 204 } 205 206 try { 207 this.objectName = new ObjectName(this.managementContext.getJmxDomainName()+":"+ "Type=TransportLoggerControl"); 208 AnnotatedMBean.registerMBean(this.managementContext, new TransportLoggerControl(this.managementContext),this.objectName); 209 210 this.transportLoggerControlCreated = true; 211 212 } catch (Exception e) { 213 LOG.error("TransportLoggerControlMBean could not be registered, reason: " + e, e); 214 } 215 } 216 217}