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 }