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