001 // Copyright 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.hivemind.management.log4j; 016 017 import java.util.Enumeration; 018 import java.util.Iterator; 019 import java.util.List; 020 021 import javax.management.InstanceAlreadyExistsException; 022 import javax.management.JMException; 023 import javax.management.MBeanAttributeInfo; 024 import javax.management.MBeanOperationInfo; 025 import javax.management.MBeanParameterInfo; 026 import javax.management.ObjectName; 027 028 import org.apache.hivemind.ApplicationRuntimeException; 029 import org.apache.hivemind.management.ObjectNameBuilder; 030 import org.apache.hivemind.management.mbeans.AbstractDynamicMBean; 031 import org.apache.hivemind.util.StringUtils; 032 import org.apache.log4j.LogManager; 033 import org.apache.log4j.Logger; 034 import org.apache.log4j.helpers.OptionConverter; 035 import org.apache.log4j.spi.LoggerRepository; 036 import org.apache.oro.text.regex.MalformedPatternException; 037 import org.apache.oro.text.regex.Pattern; 038 import org.apache.oro.text.regex.Perl5Compiler; 039 import org.apache.oro.text.regex.Perl5Matcher; 040 041 /** 042 * MBean that manages MBeans for Log4j Loggers. New MBeans can be added by specifying the Logger 043 * name or a logger pattern. Each MBean allows managing level and appenders of a single logger. Uses 044 * the LoggerDynamicMBean from the log4j library. Similar to 045 * {@link org.apache.log4j.jmx.HierarchyDynamicMBean} but implements the hivemind ObjectName scheme 046 * by using ObjectNameBuilder service. 047 * 048 * @author Achim Huegen 049 * @since 1.1 050 */ 051 public class LogManagementMBean extends AbstractDynamicMBean implements LogManagement 052 { 053 private static final String OBJECT_NAME_TYPE = "logger"; 054 055 private static final char WILDCARD = '*'; 056 057 private static Logger logger = Logger.getLogger(LogManagementMBean.class); 058 059 private ObjectNameBuilder _objectNameBuilder; 060 061 private LoggerRepository _loggerRepository; 062 063 private List _loggerContributions; 064 065 public LogManagementMBean(ObjectNameBuilder objectNameBuilder, List loggerContributions) 066 { 067 _objectNameBuilder = objectNameBuilder; 068 _loggerRepository = LogManager.getLoggerRepository(); 069 _loggerContributions = loggerContributions; 070 } 071 072 protected MBeanAttributeInfo[] createMBeanAttributeInfo() 073 { 074 return new MBeanAttributeInfo[] 075 { new MBeanAttributeInfo("Threshold", String.class.getName(), 076 "The \"threshold\" state of the logger hierarchy.", true, true, false) }; 077 } 078 079 protected MBeanOperationInfo[] createMBeanOperationInfo() 080 { 081 MBeanParameterInfo parameterInfo[] = new MBeanParameterInfo[1]; 082 parameterInfo[0] = new MBeanParameterInfo("loggerPattern", "java.lang.String", 083 "Name of the Logger. Use * as wildcard"); 084 return new MBeanOperationInfo[] 085 { new MBeanOperationInfo("addLoggerMBean", "Adds a MBean for a single Logger or " 086 + "a group of Loggers", parameterInfo, "void", 1) }; 087 } 088 089 public void postRegister(Boolean registrationDone) 090 { 091 addConfiguredLoggerMBeans(); 092 } 093 094 public String getThreshold() 095 { 096 return _loggerRepository.getThreshold().toString(); 097 } 098 099 public void setThreshold(String threshold) 100 { 101 OptionConverter.toLevel(threshold, _loggerRepository.getThreshold()); 102 103 _loggerRepository.setThreshold(threshold); 104 } 105 106 /** 107 * @see org.apache.hivemind.management.log4j.LogManagement#addLoggerMBean(java.lang.String) 108 */ 109 public void addLoggerMBean(String loggerPattern) 110 { 111 boolean hasWildcard = loggerPattern.indexOf(WILDCARD) >= 0; 112 if (hasWildcard) 113 { 114 addLoggerMBeansForPattern(loggerPattern); 115 } 116 else 117 { 118 Logger log = LogManager.getLogger(loggerPattern); 119 addLoggerMBean(log); 120 } 121 } 122 123 /** 124 * Adds a MBean for a logger. 125 * 126 * @param log 127 * the logger 128 * @return ObjectName of created MBean 129 */ 130 protected ObjectName addLoggerMBean(Logger log) 131 { 132 String name = log.getName(); 133 ObjectName objectname = null; 134 try 135 { 136 LoggerMBean loggerMBean = new LoggerMBean(log); 137 objectname = getObjectNameBuilder().createObjectName(name, OBJECT_NAME_TYPE); 138 getMBeanServer().registerMBean(loggerMBean, objectname); 139 } 140 catch (InstanceAlreadyExistsException exception) 141 { 142 // just warn 143 logger.warn("MBean for Logger " + log.getName() + " already exists"); 144 } 145 catch (JMException exception) 146 { 147 throw new ApplicationRuntimeException(exception); 148 } 149 return objectname; 150 } 151 152 /** 153 * Adds MBeans for all Loggers that are defined in the service configuration 154 */ 155 protected void addConfiguredLoggerMBeans() 156 { 157 for (Iterator iterContributions = _loggerContributions.iterator(); iterContributions 158 .hasNext();) 159 { 160 LoggerContribution contribution = (LoggerContribution) iterContributions.next(); 161 String loggerPattern = contribution.getLoggerPattern(); 162 163 addLoggerMBeansForPattern(loggerPattern); 164 } 165 } 166 167 /** 168 * Adds MBeans for all existing Loggers, that match the loggerPattern 169 * 170 * @param loggerPattern 171 */ 172 protected void addLoggerMBeansForPattern(String loggerPattern) 173 { 174 // Add MBeans for all loggers that match the pattern 175 Enumeration loggers = LogManager.getCurrentLoggers(); 176 while (loggers.hasMoreElements()) 177 { 178 Logger log = (Logger) loggers.nextElement(); 179 if (isMatch(log.getName(), loggerPattern)) 180 addLoggerMBean(log); 181 } 182 } 183 184 /** 185 * @return Returns the _objectNameBuilder. 186 */ 187 public ObjectNameBuilder getObjectNameBuilder() 188 { 189 return _objectNameBuilder; 190 } 191 192 /** 193 * Returns true if loggerName matches a loggerPattern The pattern kann contain '*' as wildcard 194 * character. This gets translated to '.*' and is used for a regex match using jakarta oro 195 */ 196 protected boolean isMatch(String loggerName, String loggerPattern) 197 { 198 // Adapt loggerPattern for oro 199 String realLoggerPattern = StringUtils 200 .replace(loggerPattern, "" + WILDCARD, "." + WILDCARD); 201 202 Perl5Compiler compiler = new Perl5Compiler(); 203 Perl5Matcher matcher = new Perl5Matcher(); 204 Pattern compiled; 205 try 206 { 207 compiled = compiler.compile(realLoggerPattern); 208 } 209 catch (MalformedPatternException e) 210 { 211 throw new ApplicationRuntimeException("Malformed Logger Pattern:" + realLoggerPattern); 212 } 213 return matcher.matches(loggerName, compiled); 214 215 } 216 217 }