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 */
017
018 package org.apache.geronimo.system.logging.log4j;
019
020 import java.io.BufferedReader;
021 import java.io.File;
022 import java.io.FileInputStream;
023 import java.io.FileOutputStream;
024 import java.io.IOException;
025 import java.io.InputStreamReader;
026 import java.io.OutputStream;
027 import java.io.Reader;
028 import java.net.MalformedURLException;
029 import java.util.ArrayList;
030 import java.util.Enumeration;
031 import java.util.Iterator;
032 import java.util.LinkedList;
033 import java.util.List;
034 import java.util.Set;
035 import java.util.Timer;
036 import java.util.TimerTask;
037 import java.util.regex.Matcher;
038 import java.util.regex.Pattern;
039 import java.util.regex.PatternSyntaxException;
040
041 import org.apache.commons.logging.Log;
042 import org.apache.commons.logging.LogConfigurationException;
043 import org.apache.commons.logging.LogFactory;
044 import org.apache.geronimo.gbean.GBeanInfo;
045 import org.apache.geronimo.gbean.GBeanInfoBuilder;
046 import org.apache.geronimo.gbean.GBeanLifecycle;
047 import org.apache.geronimo.kernel.log.GeronimoLogFactory;
048 import org.apache.geronimo.kernel.log.GeronimoLogging;
049 import org.apache.geronimo.system.logging.SystemLog;
050 import org.apache.geronimo.system.properties.JvmVendor;
051 import org.apache.geronimo.system.serverinfo.DirectoryUtils;
052 import org.apache.geronimo.system.serverinfo.ServerInfo;
053 import org.apache.log4j.FileAppender;
054 import org.apache.log4j.Level;
055 import org.apache.log4j.LogManager;
056 import org.apache.log4j.Logger;
057
058 /**
059 * A Log4j logging service.
060 *
061 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
062 */
063 public class Log4jService implements GBeanLifecycle, SystemLog {
064 // A substitution variable in the file path in the config file
065 private final static Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{.*?\\}");
066 // Next 6 are patterns that identify log messages in our default format
067 private final static Pattern DEFAULT_ANY_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (TRACE|DEBUG|INFO|WARN|ERROR|FATAL) .*");
068 private final static Pattern DEFAULT_FATAL_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d FATAL .*");
069 private final static Pattern DEFAULT_ERROR_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (ERROR|FATAL) .*");
070 private final static Pattern DEFAULT_WARN_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (WARN|ERROR|FATAL) .*");
071 private final static Pattern DEFAULT_INFO_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (INFO|WARN|ERROR|FATAL) .*");
072 private final static Pattern DEFAULT_DEBUG_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (DEBUG|INFO|WARN|ERROR|FATAL) .*");
073 // Next 6 are patterns that identify log messages if the user changed the format -- but we assume the log level is in there somewhere
074 private final static Pattern UNKNOWN_ANY_START = Pattern.compile("(TRACE|DEBUG|INFO|WARN|ERROR|FATAL)");
075 private final static Pattern UNKNOWN_FATAL_START = Pattern.compile("FATAL");
076 private final static Pattern UNKNOWN_ERROR_START = Pattern.compile("(ERROR|FATAL)");
077 private final static Pattern UNKNOWN_WARN_START = Pattern.compile("(WARN|ERROR|FATAL)");
078 private final static Pattern UNKNOWN_INFO_START = Pattern.compile("(INFO|WARN|ERROR|FATAL)");
079 private final static Pattern UNKNOWN_DEBUG_START = Pattern.compile("(DEBUG|INFO|WARN|ERROR|FATAL)");
080
081 private final static Log log = LogFactory.getLog(Log4jService.class);
082
083 private static final String LOG4JSERVICE_CONFIG_PROPERTY = "org.apache.geronimo.log4jservice.configuration";
084
085 /**
086 * The URL to the configuration file.
087 */
088 private String configurationFile;
089
090 /**
091 * The time (in seconds) between checking for new config.
092 */
093 private int refreshPeriod;
094
095 /**
096 * The properties service
097 */
098 private final ServerInfo serverInfo;
099
100 /**
101 * The URL watch timer (in daemon mode).
102 */
103 private Timer timer = new Timer(true);
104
105 /**
106 * A monitor to check when the config URL changes.
107 */
108 private TimerTask monitor;
109
110 /**
111 * Last time the file was changed.
112 */
113 private long lastChanged = -1;
114
115 /**
116 * Is this service running?
117 */
118 private boolean running = false;
119
120 /**
121 * Construct a <code>Log4jService</code>.
122 *
123 * @param configurationFile The log4j configuration file.
124 * @param refreshPeriod The refresh refreshPeriod (in seconds).
125 */
126 public Log4jService(final String configurationFile, final int refreshPeriod, ServerInfo serverInfo) {
127 this.refreshPeriod = refreshPeriod;
128 this.configurationFile = configurationFile;
129 this.serverInfo = serverInfo;
130 Logger.getLogger(this.getClass().getName()).setLevel(Level.INFO);
131 }
132
133 /**
134 * Gets the level of the root logger.
135 */
136 public synchronized String getRootLoggerLevel() {
137 Level level = LogManager.getRootLogger().getLevel();
138
139 if (level != null) {
140 return level.toString();
141 }
142
143 return null;
144 }
145
146 /**
147 * Sets the level of the root logger.
148 *
149 * @param level The level to change the logger to.
150 */
151 public synchronized void setRootLoggerLevel(final String level) {
152
153 String currentLevel = this.getRootLoggerLevel();
154
155 // ensure that the level has really been changed
156 if (!currentLevel.equals(level)) {
157 LogManager.getRootLogger().setLevel(XLevel.toLevel(level));
158 }
159 }
160
161 /**
162 * Gets the level of the logger of the give name.
163 *
164 * @param logger The logger to inspect.
165 */
166 public String getLoggerEffectiveLevel(final String logger) {
167 if (logger == null) {
168 throw new IllegalArgumentException("logger is null");
169 }
170
171 Level level = LogManager.getLogger(logger).getEffectiveLevel();
172
173 if (level != null) {
174 return level.toString();
175 }
176
177 return null;
178 }
179
180 /**
181 * Gets the level of the logger of the give name.
182 *
183 * @param logger The logger to inspect.
184 */
185 public String getLoggerLevel(final String logger) {
186 if (logger == null) {
187 throw new IllegalArgumentException("logger is null");
188 }
189
190 Level level = LogManager.getLogger(logger).getLevel();
191
192 if (level != null) {
193 return level.toString();
194 }
195
196 return null;
197 }
198
199 /**
200 * Sets the level for a logger of the give name.
201 *
202 * @param logger The logger to change level
203 * @param level The level to change the logger to.
204 */
205 public void setLoggerLevel(final String logger, final String level) {
206 if (logger == null) {
207 throw new IllegalArgumentException("logger is null");
208 }
209 if (level == null) {
210 throw new IllegalArgumentException("level is null");
211 }
212
213 log.info("Setting logger level: logger=" + logger + ", level=" + level);
214 Logger.getLogger(logger).setLevel(XLevel.toLevel(level));
215 }
216
217 /**
218 * Get the refresh period.
219 *
220 * @return the refresh period (in seconds)
221 */
222 public synchronized int getRefreshPeriodSeconds() {
223 return refreshPeriod;
224 }
225
226 /**
227 * Set the refresh period.
228 *
229 * @param period the refresh period (in seconds)
230 * @throws IllegalArgumentException if refresh period is < 5
231 */
232 public synchronized void setRefreshPeriodSeconds(final int period) {
233 if (period < 5) {
234 throw new IllegalArgumentException("Refresh period must be at least 5 seconds");
235 }
236
237 if (this.refreshPeriod != period) {
238 this.refreshPeriod = period;
239 schedule();
240 }
241 }
242
243 /**
244 * Get the logging configuration URL.
245 *
246 * @return the logging configuration URL
247 */
248 public synchronized String getConfigFileName() {
249 return configurationFile;
250 }
251
252 /**
253 * Set the logging configuration URL.
254 *
255 * @param configurationFile the logging configuration file
256 */
257 public synchronized void setConfigFileName(final String configurationFile) {
258 if (log.isDebugEnabled()) {
259 log.debug("setConfigFileName() called with configurationFile=" + configurationFile);
260 }
261
262 if (configurationFile == null) {
263 throw new IllegalArgumentException("configurationFile is null");
264 }
265
266 // ensure that the file name has really been updated
267 if (!this.configurationFile.equals(configurationFile)) {
268 this.configurationFile = configurationFile;
269 lastChanged = -1;
270 reconfigure();
271 }
272 }
273
274 /**
275 * Get the content of logging configuration file.
276 *
277 * @return the content of logging configuration file
278 */
279 public synchronized String getConfiguration() {
280 File file = resolveConfigurationFile();
281 if (file == null || !file.canRead()) {
282 return null;
283 }
284 Reader in = null;
285 try {
286 StringBuffer configuration = new StringBuffer();
287 in = new InputStreamReader(new FileInputStream(file));
288 char[] buffer = new char[4096];
289 for (int size = in.read(buffer); size >= 0; size = in.read(buffer)) {
290 configuration.append(buffer, 0, size);
291 }
292 return configuration.toString();
293 } catch (IOException e) {
294 e.printStackTrace();
295 } finally {
296 if (in != null) {
297 try {
298 in.close();
299 } catch (IOException e1) {
300 e1.printStackTrace();
301 }
302 }
303 }
304 return null;
305 }
306
307 /**
308 * Overwrites the content of logging configuration file.
309 *
310 * @param configuration the new content of logging configuration file
311 */
312 public synchronized void setConfiguration(final String configuration) throws IOException {
313 if (configuration == null || configuration.length() == 0) {
314 throw new IllegalArgumentException("configuration is null or an empty string");
315 }
316
317 File file = resolveConfigurationFile();
318 if (file == null) {
319 throw new IllegalStateException("Configuration file is null");
320 }
321
322 // make parent directory if necessary
323 if (!file.getParentFile().exists()) {
324 if (!file.getParentFile().mkdirs()) {
325 throw new IllegalStateException("Could not create parent directory of log configuration file: " + file.getParent());
326 }
327 }
328
329 // verify that the file is writable or does not exist
330 if (file.exists() && !file.canWrite()) {
331 throw new IllegalStateException("Configuration file is not writable: " + file.getAbsolutePath());
332 }
333
334 OutputStream out = null;
335 try {
336 out = new FileOutputStream(file);
337 out.write(configuration.getBytes());
338 log.info("Updated configuration file=" + file.toString());
339 } finally {
340 if (out != null) {
341 try {
342 out.close();
343 } catch (IOException e) {
344 e.printStackTrace();
345 }
346 }
347 }
348 }
349
350 public synchronized String[] getLogFileNames() {
351 List list = new ArrayList();
352 for (Enumeration e = Logger.getRootLogger().getAllAppenders(); e.hasMoreElements();) {
353 Object appender = e.nextElement();
354 if (appender instanceof FileAppender) {
355 list.add(((FileAppender) appender).getFile());
356 }
357 }
358 return (String[]) list.toArray(new String[list.size()]);
359 }
360
361 private static SearchResults searchFile(File file, String targetLevel, Pattern textSearch, Integer start, Integer stop, int max, boolean stacks) {
362 List list = new LinkedList();
363 boolean capped = false;
364 int lineCount = 0;
365 FileInputStream logInputStream = null;
366 try {
367 logInputStream = new FileInputStream(file);
368 BufferedReader reader = new BufferedReader(new InputStreamReader(logInputStream, System.getProperty("file.encoding")));
369 Matcher target = null;
370 Matcher any = null;
371 Matcher text = textSearch == null ? null : textSearch.matcher("");
372 boolean hit = false;
373 max = Math.min(max, MAX_SEARCH_RESULTS);
374 String line;
375 while ((line = reader.readLine()) != null) {
376 ++lineCount;
377 if(target == null) {
378 if(DEFAULT_ANY_START.matcher(line).find()) {
379 target = getDefaultPatternForLevel(targetLevel).matcher("");
380 any = DEFAULT_ANY_START.matcher("");
381 } else {
382 target = getUnknownPatternForLevel(targetLevel).matcher("");
383 any = UNKNOWN_ANY_START.matcher("");
384 }
385 }
386 if(start != null && start.intValue() > lineCount) {
387 continue;
388 }
389 if(stop != null && stop.intValue() < lineCount) {
390 continue;
391 }
392 target.reset(line);
393 if(target.find()) {
394 if(text != null) {
395 text.reset(line);
396 if(!text.find()) {
397 hit = false;
398 continue;
399 }
400 }
401 list.add(new LogMessage(lineCount,line.toString()));
402 if(list.size() > max) {
403 list.remove(0);
404 capped = true;
405 }
406 hit = true;
407 } else if(stacks && hit) {
408 any.reset(line);
409 if(!any.find()) {
410 list.add(new LogMessage(lineCount,line.toString()));
411 if(list.size() > max) {
412 list.remove(0);
413 capped = true;
414 }
415 } else {
416 hit = false;
417 }
418 }
419 }
420 } catch (Exception e) {
421 // TODO: improve exception handling
422 } finally {
423 if (logInputStream != null) {
424 try {
425 logInputStream.close();
426 } catch (IOException e) {
427 // ignore
428 }
429 }
430 }
431 return new SearchResults(lineCount, (LogMessage[]) list.toArray(new LogMessage[list.size()]), capped);
432 }
433
434 private static String substituteSystemProps(String source) {
435 StringBuffer buf = new StringBuffer();
436 int last = 0;
437 Matcher m = VARIABLE_PATTERN.matcher(source);
438 while(m.find()) {
439 buf.append(source.substring(last, m.start()));
440 String prop = source.substring(m.start()+2, m.end()-1);
441 buf.append(System.getProperty(prop));
442 last = m.end();
443 }
444 buf.append(source.substring(last));
445 return buf.toString();
446 }
447
448 private static Pattern getDefaultPatternForLevel(String targetLevel) {
449 if(targetLevel.equals("FATAL")) {
450 return DEFAULT_FATAL_START;
451 } else if(targetLevel.equals("ERROR")) {
452 return DEFAULT_ERROR_START;
453 } else if(targetLevel.equals("WARN")) {
454 return DEFAULT_WARN_START;
455 } else if(targetLevel.equals("INFO")) {
456 return DEFAULT_INFO_START;
457 } else if(targetLevel.equals("DEBUG")) {
458 return DEFAULT_DEBUG_START;
459 } else {
460 return DEFAULT_ANY_START;
461 }
462 }
463
464 private static Pattern getUnknownPatternForLevel(String targetLevel) {
465 if(targetLevel.equals("FATAL")) {
466 return UNKNOWN_FATAL_START;
467 } else if(targetLevel.equals("ERROR")) {
468 return UNKNOWN_ERROR_START;
469 } else if(targetLevel.equals("WARN")) {
470 return UNKNOWN_WARN_START;
471 } else if(targetLevel.equals("INFO")) {
472 return UNKNOWN_INFO_START;
473 } else if(targetLevel.equals("DEBUG")) {
474 return UNKNOWN_DEBUG_START;
475 } else {
476 return UNKNOWN_ANY_START;
477 }
478 }
479
480 public SearchResults getMatchingItems(String logFile, Integer firstLine, Integer lastLine, String minLevel, String text, int maxResults, boolean includeStackTraces) {
481 // Ensure the file argument is really a log file!
482 if(logFile == null) {
483 throw new IllegalArgumentException("Must specify a log file");
484 }
485 String[] files = getLogFileNames();
486 boolean found = false;
487 for (int i = 0; i < files.length; i++) {
488 if(files[i].equals(logFile)) {
489 found = true;
490 break;
491 }
492 }
493 if(!found) {
494 throw new IllegalArgumentException("Not a log file!");
495 }
496 // Check for valid log level
497 if(minLevel == null) {
498 minLevel = "TRACE";
499 } else if(!minLevel.equals("FATAL") && !minLevel.equals("ERROR") && !minLevel.equals("WARN") &&
500 !minLevel.equals("INFO") && !minLevel.equals("DEBUG") && !minLevel.equals("TRACE")) {
501 throw new IllegalArgumentException("Not a valid log level");
502 }
503 // Check that the text pattern is valid
504 Pattern textPattern = null;
505 try {
506 textPattern = text == null || text.equals("") ? null : Pattern.compile(text);
507 } catch (PatternSyntaxException e) {
508 throw new IllegalArgumentException("Bad regular expression '"+text+"'", e);
509 }
510 // Make sure we can find the log file
511 File log = new File(substituteSystemProps(logFile));
512 if(!log.exists()) {
513 throw new IllegalArgumentException("Log file "+log.getAbsolutePath()+" does not exist");
514 }
515 // Run the search
516 return searchFile(log, minLevel, textPattern, firstLine, lastLine, maxResults, includeStackTraces);
517 }
518
519 /**
520 * Force the logging system to reconfigure.
521 */
522 public void reconfigure() {
523 File file = resolveConfigurationFile();
524 if (file == null || !file.exists()) {
525 return;
526 } else {
527 if (log.isDebugEnabled()) {
528 log.debug("reconfigure() using configurationFile=" + configurationFile);
529 }
530 lastChanged = file.lastModified();
531 }
532
533 // Record the default console log level
534 System.setProperty("org.apache.geronimo.log.ConsoleLogLevel", GeronimoLogging.getConsoleLogLevel().toString());
535
536 try {
537 URLConfigurator.configure(file.toURL());
538 } catch (MalformedURLException e) {
539 e.printStackTrace();
540 }
541
542 // refresh the level info for every log
543 GeronimoLogFactory logFactory = (GeronimoLogFactory) LogFactory.getFactory();
544 Set instances = logFactory.getInstances();
545 for (Iterator iterator = instances.iterator(); iterator.hasNext();) {
546 Object log = iterator.next();
547 if (log instanceof CachingLog4jLog) {
548 ((CachingLog4jLog)log).updateLevelInfo();
549 }
550 }
551 }
552
553 private synchronized void schedule() {
554 if (timer != null) {
555 // kill the old monitor
556 if (monitor != null) {
557 monitor.cancel();
558 }
559
560 // start the new one
561 monitor = new URLMonitorTask();
562 TimerTask task = monitor;
563 timer.schedule(monitor, 1000 * refreshPeriod, 1000 * refreshPeriod);
564 task.run();
565 }
566 }
567
568 public void doStart() {
569 LogFactory logFactory = LogFactory.getFactory();
570 if (logFactory instanceof GeronimoLogFactory) {
571 // Make sure the root Logger has loaded
572 Logger logger = LogManager.getRootLogger();
573
574 // Change all of the loggers over to use log4j
575 GeronimoLogFactory geronimoLogFactory = (GeronimoLogFactory) logFactory;
576 synchronized (geronimoLogFactory) {
577 if (!(geronimoLogFactory.getLogFactory() instanceof CachingLog4jLogFactory)) {
578 geronimoLogFactory.setLogFactory(new CachingLog4jLogFactory());
579 }
580 }
581
582 // Allow users to override the configurationFile which is hardcoded
583 // in config.ser and cannot be updated by config.xml, as the
584 // AttrbiuteManager comes up after this GBean
585 String cfgFile = System.getProperty(LOG4JSERVICE_CONFIG_PROPERTY);
586 if ((cfgFile != null) && (!cfgFile.equals(""))) {
587 this.configurationFile = cfgFile;
588 }
589
590 synchronized (this) {
591 reconfigure();
592
593 timer = new Timer(true);
594
595 // Periodically check the configuration file
596 schedule();
597 }
598
599 logEnvInfo();
600 }
601
602 synchronized (this) {
603 running = true;
604 }
605 }
606
607 public synchronized void doStop() {
608 running = false;
609 if (monitor != null) {
610 monitor.cancel();
611 monitor = null;
612 }
613 if (timer != null) {
614 timer.cancel();
615 timer = null;
616 }
617 }
618
619 public void doFail() {
620 doStop();
621 }
622
623 private synchronized File resolveConfigurationFile() {
624 try {
625 return serverInfo.resolveServer(configurationFile);
626 } catch (Exception e) {
627 return null;
628 }
629 }
630
631 private void logEnvInfo() {
632 try {
633 Log log = LogFactory.getLog(Log4jService.class);
634 log.info("----------------------------------------------");
635 log.info("Started Logging Service");
636 if (log.isDebugEnabled()) {
637 log.debug("Log4jService created with configFileName=" + this.configurationFile + ", refreshPeriodSeconds=" + this.refreshPeriod);
638 }
639 log.info("Runtime Information:");
640 log.info(" Install Directory = " + DirectoryUtils.getGeronimoInstallDirectory().toString());
641 log.info(" JVM in use = " + JvmVendor.getJvmInfo());
642 log.info("Java Information:");
643 log.info(" System property [java.runtime.name] = " + System.getProperty("java.runtime.name"));
644 log.info(" System property [java.runtime.version] = " + System.getProperty("java.runtime.version"));
645 log.info(" System property [os.name] = " + System.getProperty("os.name"));
646 log.info(" System property [os.version] = " + System.getProperty("os.version"));
647 log.info(" System property [sun.os.patch.level] = " + System.getProperty("sun.os.patch.level"));
648 log.info(" System property [os.arch] = " + System.getProperty("os.arch"));
649 log.info(" System property [java.class.version] = " + System.getProperty("java.class.version"));
650 log.info(" System property [locale] = " + System.getProperty("user.language") + "_" + System.getProperty("user.country"));
651 log.info(" System property [unicode.encoding] = " + System.getProperty("sun.io.unicode.encoding"));
652 log.info(" System property [file.encoding] = " + System.getProperty("file.encoding"));
653 log.info(" System property [java.vm.name] = " + System.getProperty("java.vm.name"));
654 log.info(" System property [java.vm.vendor] = " + System.getProperty("java.vm.vendor"));
655 log.info(" System property [java.vm.version] = " + System.getProperty("java.vm.version"));
656 log.info(" System property [java.vm.info] = " + System.getProperty("java.vm.info"));
657 log.info(" System property [java.home] = " + System.getProperty("java.home"));
658 log.info(" System property [java.classpath] = " + System.getProperty("java.classpath"));
659 log.info(" System property [java.library.path] = " + System.getProperty("java.library.path"));
660 log.info(" System property [java.endorsed.dirs] = " + System.getProperty("java.endorsed.dirs"));
661 log.info(" System property [java.ext.dirs] = " + System.getProperty("java.ext.dirs"));
662 log.info(" System property [sun.boot.class.path] = " + System.getProperty("sun.boot.class.path"));
663 log.info("----------------------------------------------");
664 } catch (Exception e) {
665 System.err.println("Exception caught during logging of Runtime Information. Exception=" + e.toString());
666 }
667 }
668
669
670 private class URLMonitorTask extends TimerTask {
671 public void run() {
672 try {
673 long lastModified;
674 synchronized (this) {
675 if (running == false) {
676 return;
677 }
678
679 File file = resolveConfigurationFile();
680 if (file == null) {
681 return;
682 }
683
684 lastModified = file.lastModified();
685 }
686
687 if (lastChanged < lastModified) {
688 lastChanged = lastModified;
689 reconfigure();
690 }
691 } catch (Exception e) {
692 }
693 }
694 }
695
696 private static class CachingLog4jLogFactory extends LogFactory {
697 public Log getInstance(Class clazz) throws LogConfigurationException {
698 return getInstance(clazz.getName());
699 }
700
701 public Log getInstance(String name) throws LogConfigurationException {
702 return new CachingLog4jLog(name);
703 }
704
705 public Object getAttribute(String name) {
706 return null;
707 }
708
709 public String[] getAttributeNames() {
710 return new String[0];
711 }
712
713 public void release() {
714 }
715
716 public void removeAttribute(String name) {
717 }
718
719 public void setAttribute(String name, Object value) {
720 }
721 }
722
723 public static final GBeanInfo GBEAN_INFO;
724
725 static {
726 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(Log4jService.class, "SystemLog");
727
728 infoFactory.addAttribute("configFileName", String.class, true);
729 infoFactory.addAttribute("refreshPeriodSeconds", int.class, true);
730 infoFactory.addAttribute("configuration", String.class, false);
731 infoFactory.addAttribute("rootLoggerLevel", String.class, false);
732
733 infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean");
734
735 infoFactory.addOperation("reconfigure");
736 infoFactory.addOperation("setLoggerLevel", new Class[]{String.class, String.class});
737 infoFactory.addOperation("getLoggerLevel", new Class[]{String.class});
738 infoFactory.addOperation("getLoggerEffectiveLevel", new Class[]{String.class});
739 infoFactory.addInterface(SystemLog.class);
740
741 infoFactory.setConstructor(new String[]{"configFileName", "refreshPeriodSeconds", "ServerInfo"});
742
743 GBEAN_INFO = infoFactory.getBeanInfo();
744 }
745
746 public static GBeanInfo getGBeanInfo() {
747 return GBEAN_INFO;
748 }
749 }