View | Details | Raw Unified | Return to bug 44308
Collapse All | Expand All

(-)src/main/java/org/apache/log4j/jmx/RollbackableLoggerManager.java (+70 lines)
Line 0 Link Here
1
/**
2
 *
3
 */
4
package org.apache.log4j.jmx;
5
6
import java.util.HashMap;
7
import java.util.Iterator;
8
import java.util.Map;
9
import java.util.Map.Entry;
10
11
import org.apache.log4j.Level;
12
import org.apache.log4j.Logger;
13
14
/**
15
 * LoggerManager implementation with additional rollback support to be able to undo the changes
16
 * done by this class.
17
 * @see LoggerManager
18
 * @author Stefan Fleiter
19
 */
20
public class RollbackableLoggerManager extends LoggerManager {
21
22
    /**
23
     * Thread safety guaranteed by locking on this (instance of LoggerManager) on every access.
24
     */
25
    private final Map savedLoggerConfiguration = new HashMap();
26
27
    /**
28
     * Sets the level of the specified logger.
29
     * Can be overriden to do something additional when modifying loggers.
30
     * @param logger Log4j Logger Instance
31
     * @param level New level as string
32
     * @return true, if level has changed, false if level is same as before
33
     */
34
    protected boolean doSetLogLogLevel(Logger logger, String level) {
35
        Level originalLevel = logger.getLevel();
36
        boolean modified = super.doSetLogLogLevel(logger, level);
37
        synchronized (savedLoggerConfiguration) {
38
            if (!savedLoggerConfiguration.containsKey(logger)) {
39
                savedLoggerConfiguration.put(logger, originalLevel);
40
            }
41
        }
42
        return modified;
43
    }
44
45
    /**
46
     * Rolls back all modifications which where done to the log configuration by this instance.
47
     */
48
    public synchronized void rollbackLogConfiguration() {
49
        synchronized (savedLoggerConfiguration) {
50
            for (Iterator it = savedLoggerConfiguration.entrySet().iterator(); it.hasNext(); ) {
51
                Map.Entry entry = (Entry) it.next();
52
                Logger logger = (Logger) entry.getKey();
53
                Level originalLevel = (Level) entry.getValue();
54
                logger.setLevel(originalLevel);
55
            }
56
            savedLoggerConfiguration.clear();
57
        }
58
    }
59
60
    /**
61
     * Shutdown hook which clears all references, but does not call <code>resetLogConfiguration</code>
62
     * @see #resetLogConfiguration()
63
     */
64
    public void destroy() {
65
        synchronized (savedLoggerConfiguration) {
66
            savedLoggerConfiguration.clear();
67
        }
68
    }
69
70
}
(-)src/main/java/org/apache/log4j/jmx/LoggerManager.java (+183 lines)
Line 0 Link Here
1
package org.apache.log4j.jmx;
2
3
import java.util.ArrayList;
4
import java.util.Enumeration;
5
import java.util.HashMap;
6
import java.util.Iterator;
7
import java.util.List;
8
import java.util.Map;
9
10
import org.apache.log4j.Level;
11
import org.apache.log4j.LogManager;
12
import org.apache.log4j.Logger;
13
import org.apache.log4j.spi.LoggerRepository;
14
15
/**
16
 * Helper for reading and modifying the logger configuration of a running log4j instance.
17
 * This class is thread safe.
18
 * @author Stefan Fleiter
19
 */
20
public class LoggerManager {
21
22
    /**
23
     * Returns a Level instance matching the given string representation.
24
     * @param levelName Name of the level of INHERITED to inherit level from the next ancestor.
25
     * @return Level matching levelName, null for INHERITED
26
     * @throws IllegalArgumentException levelName does not represent a known level
27
     */
28
    Level getLevelByName(String levelName) throws IllegalArgumentException {
29
        Level level = Level.toLevel(levelName, null);
30
        if (null == level && null != levelName) {
31
            String lowerLevelName = levelName.toLowerCase();
32
            if (!"inherit".equals(lowerLevelName) &&
33
                    !"inherited".equals(lowerLevelName) &&
34
                    !"null".equals(lowerLevelName)) {
35
                throw new IllegalArgumentException('"' + levelName + "\" is not a valid level");
36
            }
37
        }
38
        return level;
39
    }
40
41
    /**
42
     * Returns the string representation of the given Level.
43
     * @param level Level instance
44
     * @return Name of level or null if level is null
45
     */
46
    String getLogLevelString(Level level) {
47
        return null == level ? null : level.toString();
48
    }
49
50
51
    /**
52
     * Returns the explicit set level of a specified logger.
53
     * @param loggerName Name of the logger
54
     * @return Level of the logger
55
     */
56
    public String getLogLevel(String loggerName) {
57
        return getLogLevelString(LogManager.getLogger(loggerName).getLevel());
58
    }
59
60
    /**
61
     * Returns the effective level (the level set on this logger or if not set explicitly the
62
     * level of the next ancestor) of the specified logger.
63
     * @param loggerName Name of logger either existing or to be created
64
     * @return Effective level of the logger
65
     */
66
    public String getEffectiveLogLevel(String loggerName) {
67
        return getLogLevelString(LogManager.getLogger(loggerName).getEffectiveLevel());
68
    }
69
70
    /**
71
     * Compares two levels and returns whether they are equal.
72
     * @param first first level
73
     * @param second second level
74
     * @return true if levels are equal
75
     */
76
    boolean levelEquals(Level first, Level second) {
77
        if (null == first) {
78
            return null == second;
79
        } else {
80
            return first.equals(second);
81
        }
82
    }
83
84
    /**
85
     * Sets the level of the specified logger.
86
     * @param loggerName Name of logger either existing or to be created
87
     * @param level New level
88
     * @throws IllegalArgumentException levelName does not represent a known level
89
     */
90
    public void setLogLevel(String loggerName, String level) throws IllegalArgumentException {
91
        Logger logger = LogManager.getLogger(loggerName);
92
        doSetLogLogLevel(logger, level);
93
    }
94
95
    /**
96
     * Returns the level of the root logger.
97
     * @return Level of the logger
98
     */
99
    public String getRootLogLevel() {
100
        return getLogLevelString(LogManager.getRootLogger().getLevel());
101
    }
102
103
    /**
104
     * Sets the level of the specified logger.
105
     * @param level New level
106
     * @throws IllegalArgumentException levelName does not represent a known level
107
     */
108
    public void setRootLogLevel(String level) throws IllegalArgumentException {
109
        Logger logger = LogManager.getRootLogger();
110
        doSetLogLogLevel(logger, level);
111
    }
112
113
    /**
114
     * Sets the level of the specified logger.
115
     * Can be overriden to do something additional when modifying loggers.
116
     * @param logger Log4j Logger Instance
117
     * @param level New level as string
118
     * @return true, if level has changed, false if level is same as before
119
     */
120
    protected boolean doSetLogLogLevel(Logger logger, String level) {
121
        Level originalLevel = logger.getLevel();
122
        Level newLevel = getLevelByName(level);
123
        boolean modified = false;
124
        if (!levelEquals(newLevel, originalLevel)) {
125
            modified  = true;
126
            logger.setLevel(newLevel);
127
        }
128
        return modified;
129
    }
130
131
    /**
132
     * Shutdown hook.
133
     */
134
    public void destroy() {
135
        // nothing to do
136
    }
137
138
    /**
139
     * Returns a map of all explicitly configured loggers with the level as value.
140
     * @return map of logger names and level names
141
     */
142
    public Map getLogConfiguration() {
143
        Map result = new HashMap();
144
        List loggers = getConfiguredLoggersInternal();
145
        for (Iterator it = loggers.iterator(); it.hasNext(); ) {
146
            Logger logger = (Logger) it.next();
147
            result.put(logger.getName(), logger.getEffectiveLevel().toString());
148
        }
149
        return result;
150
    }
151
152
    /**
153
     * @return all explicitly configured loggers
154
     */
155
    List getConfiguredLoggersInternal() {
156
        List result = new ArrayList();
157
        LoggerRepository r = LogManager.getLoggerRepository();
158
        Enumeration loggers = r.getCurrentLoggers();
159
        while (loggers.hasMoreElements()) {
160
            Logger logger = (Logger) loggers.nextElement();
161
            if (null != logger.getLevel()) {
162
                result.add(logger);
163
            }
164
        }
165
        result.add(LogManager.getRootLogger());
166
        return result;
167
    }
168
169
    /**
170
     * Returns the names of all loggers with an explicit set level
171
     * (Logger{@link #getLogLevel(String)} is not null).
172
     * @return array of names of all explicitly configured loggers
173
     */
174
    public String[] getConfiguredLoggers() {
175
        List configuredLoggers = getConfiguredLoggersInternal();
176
        String[] result = new String[configuredLoggers.size()];
177
        for (int i = 0; i < configuredLoggers.size(); ++i) {
178
            result[i] = ((Logger) configuredLoggers.get(i)).getName();
179
        }
180
        return result;
181
    }
182
183
}
(-)src/main/java/org/apache/log4j/jmx/LoggerManagerModelMBean.java (+305 lines)
Line 0 Link Here
1
package org.apache.log4j.jmx;
2
3
import java.util.ArrayList;
4
import java.util.List;
5
import java.util.Map;
6
7
import javax.management.Descriptor;
8
import javax.management.MBeanException;
9
import javax.management.MBeanOperationInfo;
10
import javax.management.MBeanParameterInfo;
11
import javax.management.RuntimeOperationsException;
12
import javax.management.modelmbean.DescriptorSupport;
13
import javax.management.modelmbean.ModelMBeanAttributeInfo;
14
import javax.management.modelmbean.ModelMBeanConstructorInfo;
15
import javax.management.modelmbean.ModelMBeanInfo;
16
import javax.management.modelmbean.ModelMBeanInfoSupport;
17
import javax.management.modelmbean.ModelMBeanNotificationInfo;
18
import javax.management.modelmbean.ModelMBeanOperationInfo;
19
import javax.management.modelmbean.RequiredModelMBean;
20
21
/**
22
 * Model MBean which makes the methods of <code>LoggerManager</code> available per JMX.
23
 * @author Stefan Fleiter
24
 * @see LoggerManager
25
 */
26
public class LoggerManagerModelMBean extends RequiredModelMBean {
27
28
    private final LoggerManager loggerManager;
29
30
    /**
31
     * Constructor.
32
     * @throws MBeanException user Exception of MBean
33
     * @throws RuntimeOperationsException Runtime Exceptions in the MBeanServer
34
     */
35
    public LoggerManagerModelMBean() throws MBeanException, RuntimeOperationsException {
36
        this(new LoggerManager());
37
    }
38
39
    /**
40
     * Constructor to use an own instance of LoggerManager to represent per JMX.
41
     * @param loggerManager Instance of LoggerManager to represent as MBean
42
     * @throws MBeanException user Exception of MBean
43
     * @throws RuntimeOperationsException Runtime Exceptions in the MBeanServer
44
     */
45
    public LoggerManagerModelMBean(LoggerManager loggerManager) throws MBeanException, RuntimeOperationsException {
46
        this.loggerManager = loggerManager;
47
        setModelMBeanInfo(getModelMBeanInfo());
48
        try {
49
            setManagedResource(loggerManager, "ObjectReference");
50
        } catch (Exception e) {
51
            throw new RuntimeException(e);
52
        }
53
    }
54
55
    /**
56
     * Constructs the ModelMBeanInfo for this Model MBean.
57
     * @return ModelMBeanInfo instance
58
     * @throws MBeanException user Exception of MBean
59
     * @throws RuntimeOperationsException Runtime Exceptions in the MBeanServer
60
     */
61
    ModelMBeanInfo getModelMBeanInfo() throws RuntimeOperationsException, MBeanException {
62
        Descriptor managerDescriptor = new DescriptorSupport(new String[] {
63
                "name=" + "log4j:manager",
64
                "descriptorType=mbean",
65
                "displayName=Log4jManager",
66
                "type=" + LoggerManager.class.getName(),
67
        });
68
69
        ModelMBeanOperationInfo getLogConfiguration = createOperationInfo(
70
                "getLogConfiguration",
71
                "Return the levels of all explicitly configured loggers",
72
                new MBeanParameterInfo[0],
73
                Map.class,
74
                ModelMBeanOperationInfo.INFO
75
                );
76
        ModelMBeanOperationInfo getConfiguredLoggers = createOperationInfo(
77
                "getConfiguredLoggers",
78
                "Return the names of the explicitly configured loggers",
79
                new MBeanParameterInfo[0],
80
                String[].class,
81
                ModelMBeanOperationInfo.INFO
82
                );
83
84
85
        ModelMBeanOperationInfo getRootLogLevel = createOperationInfo(
86
                "getRootLogLevel",
87
                "Return the level of the root logger",
88
                new MBeanParameterInfo[0],
89
                String.class,
90
                MBeanOperationInfo.INFO
91
                );
92
        ModelMBeanOperationInfo setRootLogLevel = createOperationInfo(
93
                "setRootLogLevel",
94
                "Set the level of the root logger",
95
                new MBeanParameterInfo[] {
96
                        new MBeanParameterInfo(
97
                                "level",
98
                                String.class.getName(),
99
                                "New level of root logger (INHERITED to inherit level from next ancestor)"
100
                                ),
101
102
                },
103
                void.class,
104
                ModelMBeanOperationInfo.ACTION
105
                );
106
107
        ModelMBeanOperationInfo getLogLevel = createOperationInfo(
108
                "getLogLevel",
109
                "Return the level explicitly set at the specified logger, null if this logger INHERITS its level",
110
                new MBeanParameterInfo[] {
111
                        new MBeanParameterInfo(
112
                                "logger",
113
                                String.class.getName(),
114
                                "Name of logger to query level"
115
                                ),
116
                },
117
                String.class,
118
                MBeanOperationInfo.INFO
119
                );
120
        ModelMBeanOperationInfo getEffectiveLogLevel = createOperationInfo(
121
                "getEffectiveLogLevel",
122
                "Return the effective level of the specified logger " +
123
                        "(the explicitly specified level or the level of the next ancestor)",
124
                new MBeanParameterInfo[] {
125
                        new MBeanParameterInfo(
126
                                "logger",
127
                                String.class.getName(),
128
                                "Name of logger to query level"
129
                                ),
130
                },
131
                String.class,
132
                MBeanOperationInfo.INFO
133
                );
134
        ModelMBeanOperationInfo setLogLevel = createOperationInfo(
135
                "setLogLevel",
136
                "Set the level of the specified logger",
137
                new MBeanParameterInfo[] {
138
                        new MBeanParameterInfo(
139
                                "logger",
140
                                String.class.getName(),
141
                                "name of logger to modify level"
142
143
                                ),
144
                            new MBeanParameterInfo(
145
                                    "level",
146
                                    String.class.getName(),
147
                                    "new level of specified logger (INHERITED to inherit level from next ancestor)"
148
                                    ),
149
                },
150
                void.class,
151
                MBeanOperationInfo.ACTION
152
                );
153
154
        ModelMBeanOperationInfo rollbackLogConfiguration = createOperationInfo(
155
                "rollbackLogConfiguration",
156
                "Resets all loggers to its' states before calling actions in this MBean",
157
                new MBeanParameterInfo[0],
158
                void.class,
159
                MBeanOperationInfo.ACTION
160
                );
161
162
163
        ModelMBeanAttributeInfo rootLoggerAttribute = createAttributeInfo(
164
                "rootLogger",
165
                "Level of root logger",
166
                String.class,
167
                true,
168
                true,
169
                false,
170
                "getRootLogLevel",
171
                "setRootLogLevel"
172
                );
173
174
        ModelMBeanAttributeInfo configuredLoggersAttribute = createAttributeInfo(
175
                "configuredLoggers",
176
                "Names of all loggers with explicitly set log levels",
177
                String[].class,
178
                true,
179
                false,
180
                false,
181
                "getConfiguredLoggers",
182
                null
183
                );
184
185
        ModelMBeanAttributeInfo logConfigurationAttribute = createAttributeInfo(
186
                "logConfiguration",
187
                "Name of all explicitly configured loggers with their log level",
188
                Map.class,
189
                true,
190
                false,
191
                false,
192
                "getLogConfiguration",
193
                null
194
                );
195
196
197
        ModelMBeanOperationInfo[] infoArray = new ModelMBeanOperationInfo[] {
198
                getLogConfiguration, getConfiguredLoggers,
199
                getRootLogLevel, setRootLogLevel,
200
                getLogLevel, getEffectiveLogLevel, setLogLevel,
201
                };
202
203
        // dynamically register rollbackLogConfiguration, but only if our LoggerManager has that method
204
        List modelMBeanOperations = new ArrayList();
205
        try {
206
            loggerManager.getClass().getMethod("rollbackLogConfiguration", null);
207
            modelMBeanOperations.add(rollbackLogConfiguration);
208
        } catch (NoSuchMethodException expected) {
209
            // nothing to do
210
        }
211
        for (int i = 0; i < infoArray.length; ++i) {
212
            modelMBeanOperations.add(infoArray[i]);
213
        }
214
215
        ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport(
216
                loggerManager.getClass().getName(),
217
                "Model MBean for Manager Logger Configuration of Log4j",
218
                new ModelMBeanAttributeInfo[] {
219
                    rootLoggerAttribute,
220
                    configuredLoggersAttribute,
221
                    logConfigurationAttribute,
222
                    },
223
                new ModelMBeanConstructorInfo[] {},
224
                (ModelMBeanOperationInfo[]) modelMBeanOperations.toArray(
225
                        new ModelMBeanOperationInfo[modelMBeanOperations.size()]),
226
                new ModelMBeanNotificationInfo[] {},
227
                managerDescriptor
228
                );
229
230
231
        return mbeanInfo;
232
    }
233
234
235
    /**
236
     * Helper Method for registering operations of LoggerManager.
237
     * @param name Name of operation
238
     * @param description describes what the operation does
239
     * @param parameters parameters of the operation
240
     * @param returnType class which is returned by the to be registered method
241
     * @param operationInfo INFO if non-modifying and ACTION if modifying status
242
     * @return ModelMBeanOperationInfo for the described method
243
     */
244
    ModelMBeanOperationInfo createOperationInfo(String name,
245
            String description, MBeanParameterInfo[] parameters,
246
            Class returnType, int operationInfo) {
247
        return new ModelMBeanOperationInfo(
248
                name,
249
                description,
250
                parameters,
251
                returnType.getName(),
252
                operationInfo,
253
                new DescriptorSupport(new String[] {
254
                        "name=" + name,
255
                        "displayName=" + description,
256
                        "descriptorType=operation",
257
                        "class=" + loggerManager.getClass().getName(),
258
                        "role=operation",
259
                    })
260
                );
261
    }
262
263
    /**
264
     * Helper Method for registering attributes of LoggerManager.
265
     * @param name Name of attribute
266
     * @param description describes what the attribute is for
267
     * @param type type of attribute (return value of get and parameter of set Operation)
268
     * @param readable true, if attribute can be read
269
     * @param writable true, if attribute can be set
270
     * @param is true if the attribute has an "is" getter, false otherwise
271
     * @param getMethod name of getter Method
272
     * @param setMethod name of setter Method
273
     * @return ModelMBeanAttributeInfo for the described method
274
     */
275
    ModelMBeanAttributeInfo createAttributeInfo(String name,
276
            String description, Class type,
277
            boolean readable, boolean writable, boolean is,
278
            String getMethod, String setMethod) {
279
        return new ModelMBeanAttributeInfo(
280
                name,
281
                type.getName(),
282
                description,
283
                readable, writable, is,
284
                new DescriptorSupport(new String[] {
285
                        "name=" + name,
286
                        "descriptorType=attribute",
287
                        "displayName=" + description,
288
                        "getMethod=" + getMethod,
289
                        "setMethod=" + setMethod,
290
                    })
291
                );
292
    }
293
294
    /**
295
     * Calls <code>LoggerManager#destroy()</code>.
296
     * @see LoggerManager#destroy()
297
     * {@inheritDoc}}
298
     */
299
    public void postDeregister() {
300
        loggerManager.destroy();
301
        super.postDeregister();
302
    }
303
304
305
}

Return to bug 44308