1 17 18 package org.apache.geronimo.system.logging.log4j; 19 20 import java.io.File ; 21 import java.io.FileInputStream ; 22 import java.io.FileOutputStream ; 23 import java.io.IOException ; 24 import java.io.InputStreamReader ; 25 import java.io.OutputStream ; 26 import java.io.RandomAccessFile ; 27 import java.io.Reader ; 28 import java.net.MalformedURLException ; 29 import java.nio.CharBuffer ; 30 import java.nio.MappedByteBuffer ; 31 import java.nio.channels.FileChannel ; 32 import java.nio.charset.Charset ; 33 import java.util.ArrayList ; 34 import java.util.Enumeration ; 35 import java.util.Iterator ; 36 import java.util.LinkedList ; 37 import java.util.List ; 38 import java.util.Set ; 39 import java.util.Timer ; 40 import java.util.TimerTask ; 41 import java.util.regex.Matcher ; 42 import java.util.regex.Pattern ; 43 import java.util.regex.PatternSyntaxException ; 44 45 import org.apache.commons.logging.Log; 46 import org.apache.commons.logging.LogConfigurationException; 47 import org.apache.commons.logging.LogFactory; 48 import org.apache.geronimo.gbean.GBeanInfo; 49 import org.apache.geronimo.gbean.GBeanInfoBuilder; 50 import org.apache.geronimo.gbean.GBeanLifecycle; 51 import org.apache.geronimo.kernel.log.GeronimoLogFactory; 52 import org.apache.geronimo.kernel.log.GeronimoLogging; 53 import org.apache.geronimo.system.logging.SystemLog; 54 import org.apache.geronimo.system.serverinfo.DirectoryUtils; 55 import org.apache.geronimo.system.serverinfo.ServerConstants; 56 import org.apache.geronimo.system.serverinfo.ServerInfo; 57 import org.apache.log4j.FileAppender; 58 import org.apache.log4j.Level; 59 import org.apache.log4j.LogManager; 60 import org.apache.log4j.Logger; 61 62 67 public class Log4jService implements GBeanLifecycle, SystemLog { 68 private final static Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{.*?\\}"); 70 private final static Pattern DEFAULT_ANY_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (TRACE|DEBUG|INFO|WARN|ERROR|FATAL) .*"); 72 private final static Pattern DEFAULT_FATAL_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d FATAL .*"); 73 private final static Pattern DEFAULT_ERROR_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (ERROR|FATAL) .*"); 74 private final static Pattern DEFAULT_WARN_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (WARN|ERROR|FATAL) .*"); 75 private final static Pattern DEFAULT_INFO_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (INFO|WARN|ERROR|FATAL) .*"); 76 private final static Pattern DEFAULT_DEBUG_START = Pattern.compile("^\\d\\d\\:\\d\\d\\:\\d\\d\\,\\d\\d\\d (DEBUG|INFO|WARN|ERROR|FATAL) .*"); 77 private final static Pattern UNKNOWN_ANY_START = Pattern.compile("(TRACE|DEBUG|INFO|WARN|ERROR|FATAL)"); 79 private final static Pattern UNKNOWN_FATAL_START = Pattern.compile("FATAL"); 80 private final static Pattern UNKNOWN_ERROR_START = Pattern.compile("(ERROR|FATAL)"); 81 private final static Pattern UNKNOWN_WARN_START = Pattern.compile("(WARN|ERROR|FATAL)"); 82 private final static Pattern UNKNOWN_INFO_START = Pattern.compile("(INFO|WARN|ERROR|FATAL)"); 83 private final static Pattern UNKNOWN_DEBUG_START = Pattern.compile("(DEBUG|INFO|WARN|ERROR|FATAL)"); 84 private final static Pattern FULL_LINE_PATTERN = Pattern.compile("^.*", Pattern.MULTILINE); 86 87 88 91 private String configurationFile; 92 93 96 private int refreshPeriod; 97 98 101 private final ServerInfo serverInfo; 102 103 106 private Timer timer = new Timer (true); 107 108 111 private TimerTask monitor; 112 113 116 private long lastChanged = -1; 117 118 121 private boolean running = false; 122 123 129 public Log4jService(final String configurationFile, final int refreshPeriod, ServerInfo serverInfo) { 130 this.refreshPeriod = refreshPeriod; 131 this.configurationFile = configurationFile; 132 this.serverInfo = serverInfo; 133 } 134 135 138 public synchronized String getRootLoggerLevel() { 139 Level level = LogManager.getRootLogger().getLevel(); 140 141 if (level != null) { 142 return level.toString(); 143 } 144 145 return null; 146 } 147 148 153 public synchronized void setRootLoggerLevel(final String level) { 154 155 String currentLevel = this.getRootLoggerLevel(); 156 157 if (!currentLevel.equals(level)) { 159 LogManager.getRootLogger().setLevel(XLevel.toLevel(level)); 160 } 161 } 162 163 168 public String getLoggerEffectiveLevel(final String logger) { 169 if (logger == null) { 170 throw new IllegalArgumentException ("logger is null"); 171 } 172 173 Level level = LogManager.getLogger(logger).getEffectiveLevel(); 174 175 if (level != null) { 176 return level.toString(); 177 } 178 179 return null; 180 } 181 182 187 public String getLoggerLevel(final String logger) { 188 if (logger == null) { 189 throw new IllegalArgumentException ("logger is null"); 190 } 191 192 Level level = LogManager.getLogger(logger).getLevel(); 193 194 if (level != null) { 195 return level.toString(); 196 } 197 198 return null; 199 } 200 201 207 public void setLoggerLevel(final String logger, final String level) { 208 if (logger == null) { 209 throw new IllegalArgumentException ("logger is null"); 210 } 211 if (level == null) { 212 throw new IllegalArgumentException ("level is null"); 213 } 214 215 Logger.getLogger(logger).setLevel(XLevel.toLevel(level)); 216 } 217 218 223 public synchronized int getRefreshPeriodSeconds() { 224 return refreshPeriod; 225 } 226 227 233 public synchronized void setRefreshPeriodSeconds(final int period) { 234 if (period < 1) { 235 throw new IllegalArgumentException ("Refresh period must be > 0"); 236 } 237 238 if (this.refreshPeriod != period) { 239 this.refreshPeriod = period; 240 schedule(); 241 } 242 } 243 244 249 public synchronized String getConfigFileName() { 250 return configurationFile; 251 } 252 253 258 public synchronized void setConfigFileName(final String configurationFile) { 259 if (configurationFile == null) { 260 throw new IllegalArgumentException ("configurationFile is null"); 261 } 262 263 if (!this.configurationFile.equals(configurationFile)) { 265 this.configurationFile = configurationFile; 266 lastChanged = -1; 267 } 268 } 269 270 275 public synchronized String getConfiguration() { 276 File file = resolveConfigurationFile(); 277 if (file == null || !file.canRead()) { 278 return null; 279 } 280 Reader in = null; 281 try { 282 StringBuffer configuration = new StringBuffer (); 283 in = new InputStreamReader (new FileInputStream (file)); 284 char[] buffer = new char[4096]; 285 for (int size = in.read(buffer); size >= 0; size = in.read(buffer)) { 286 configuration.append(buffer, 0, size); 287 } 288 return configuration.toString(); 289 } catch (IOException e) { 290 e.printStackTrace(); 291 } finally { 292 if (in != null) { 293 try { 294 in.close(); 295 } catch (IOException e1) { 296 e1.printStackTrace(); 297 } 298 } 299 } 300 return null; 301 } 302 303 308 public synchronized void setConfiguration(final String configuration) throws IOException { 309 if (configuration == null || configuration.length() == 0) { 310 throw new IllegalArgumentException ("configuration is null or an empty string"); 311 } 312 313 File file = resolveConfigurationFile(); 314 if (file == null) { 315 throw new IllegalStateException ("Configuration file is null"); 316 } 317 318 if (!file.getParentFile().exists()) { 320 if (!file.getParentFile().mkdirs()) { 321 throw new IllegalStateException ("Could not create parent directory of log configuration file: " + file.getParent()); 322 } 323 } 324 325 if (file.exists() && !file.canWrite()) { 327 throw new IllegalStateException ("Configuration file is not writable: " + file.getAbsolutePath()); 328 } 329 330 OutputStream out = null; 331 try { 332 out = new FileOutputStream (file); 333 out.write(configuration.getBytes()); 334 } finally { 335 if (out != null) { 336 try { 337 out.close(); 338 } catch (IOException e) { 339 e.printStackTrace(); 340 } 341 } 342 } 343 } 344 345 public synchronized String [] getLogFileNames() { 346 List list = new ArrayList (); 347 for (Enumeration e = Logger.getRootLogger().getAllAppenders(); e.hasMoreElements();) { 348 Object appender = e.nextElement(); 349 if (appender instanceof FileAppender) { 350 list.add(((FileAppender) appender).getFile()); 351 } 352 } 353 return (String []) list.toArray(new String [list.size()]); 354 } 355 356 private static SearchResults searchFile(File file, String targetLevel, Pattern textSearch, Integer start, Integer stop, int max, boolean stacks) { 357 List list = new LinkedList (); 358 boolean capped = false; 359 int lineCount = 0; 360 try { 361 RandomAccessFile raf = new RandomAccessFile (file, "r"); 362 FileChannel fc = raf.getChannel(); 363 MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); 364 CharBuffer cb = Charset.forName("US-ASCII").decode(bb); Matcher target = null; 366 Matcher any = null; 367 Matcher lines = FULL_LINE_PATTERN.matcher(cb); 368 Matcher text = textSearch == null ? null : textSearch.matcher(""); 369 boolean hit = false; 370 max = Math.min(max, MAX_SEARCH_RESULTS); 371 while(lines.find()) { 372 ++lineCount; 373 if(target == null) { 374 if(DEFAULT_ANY_START.matcher(cb.subSequence(lines.start(), lines.end())).find()) { 375 target = getDefaultPatternForLevel(targetLevel).matcher(""); 376 any = DEFAULT_ANY_START.matcher(""); 377 } else { 378 target = getUnknownPatternForLevel(targetLevel).matcher(""); 379 any = UNKNOWN_ANY_START.matcher(""); 380 } 381 } 382 if(start != null && start.intValue() > lineCount) { 383 continue; 384 } 385 if(stop != null && stop.intValue() < lineCount) { 386 continue; 387 } 388 CharSequence line = cb.subSequence(lines.start(), lines.end()); 389 target.reset(line); 390 if(target.find()) { 391 if(text != null) { 392 text.reset(line); 393 if(!text.find()) { 394 hit = false; 395 continue; 396 } 397 } 398 list.add(new LogMessage(lineCount,line.toString())); 399 if(list.size() > max) { 400 list.remove(0); 401 capped = true; 402 } 403 hit = true; 404 } else if(stacks && hit) { 405 any.reset(line); 406 if(!any.find()) { 407 list.add(new LogMessage(lineCount,line.toString())); 408 if(list.size() > max) { 409 list.remove(0); 410 capped = true; 411 } 412 } else { 413 hit = false; 414 } 415 } 416 } 417 fc.close(); 418 raf.close(); 419 } catch (Exception e) {} return new SearchResults(lineCount, (LogMessage[]) list.toArray(new LogMessage[list.size()]), capped); 421 } 422 423 private static String substituteSystemProps(String source) { 424 StringBuffer buf = new StringBuffer (); 425 int last = 0; 426 Matcher m = VARIABLE_PATTERN.matcher(source); 427 while(m.find()) { 428 buf.append(source.substring(last, m.start())); 429 String prop = source.substring(m.start()+2, m.end()-1); 430 buf.append(System.getProperty(prop)); 431 last = m.end(); 432 } 433 buf.append(source.substring(last)); 434 return buf.toString(); 435 } 436 437 private static Pattern getDefaultPatternForLevel(String targetLevel) { 438 if(targetLevel.equals("FATAL")) { 439 return DEFAULT_FATAL_START; 440 } else if(targetLevel.equals("ERROR")) { 441 return DEFAULT_ERROR_START; 442 } else if(targetLevel.equals("WARN")) { 443 return DEFAULT_WARN_START; 444 } else if(targetLevel.equals("INFO")) { 445 return DEFAULT_INFO_START; 446 } else if(targetLevel.equals("DEBUG")) { 447 return DEFAULT_DEBUG_START; 448 } else { 449 return DEFAULT_ANY_START; 450 } 451 } 452 453 private static Pattern getUnknownPatternForLevel(String targetLevel) { 454 if(targetLevel.equals("FATAL")) { 455 return UNKNOWN_FATAL_START; 456 } else if(targetLevel.equals("ERROR")) { 457 return UNKNOWN_ERROR_START; 458 } else if(targetLevel.equals("WARN")) { 459 return UNKNOWN_WARN_START; 460 } else if(targetLevel.equals("INFO")) { 461 return UNKNOWN_INFO_START; 462 } else if(targetLevel.equals("DEBUG")) { 463 return UNKNOWN_DEBUG_START; 464 } else { 465 return UNKNOWN_ANY_START; 466 } 467 } 468 469 public SearchResults getMatchingItems(String logFile, Integer firstLine, Integer lastLine, String minLevel, String text, int maxResults, boolean includeStackTraces) { 470 if(logFile == null) { 472 throw new IllegalArgumentException ("Must specify a log file"); 473 } 474 String [] files = getLogFileNames(); 475 boolean found = false; 476 for (int i = 0; i < files.length; i++) { 477 if(files[i].equals(logFile)) { 478 found = true; 479 break; 480 } 481 } 482 if(!found) { 483 throw new IllegalArgumentException ("Not a log file!"); 484 } 485 if(minLevel == null) { 487 minLevel = "TRACE"; 488 } else if(!minLevel.equals("FATAL") && !minLevel.equals("ERROR") && !minLevel.equals("WARN") && 489 !minLevel.equals("INFO") && !minLevel.equals("DEBUG") && !minLevel.equals("TRACE")) { 490 throw new IllegalArgumentException ("Not a valid log level"); 491 } 492 Pattern textPattern = null; 494 try { 495 textPattern = text == null || text.equals("") ? null : Pattern.compile(text); 496 } catch (PatternSyntaxException e) { 497 throw new IllegalArgumentException ("Bad regular expression '"+text+"'"); 498 } 499 File log = new File (substituteSystemProps(logFile)); 501 if(!log.exists()) { 502 throw new IllegalArgumentException ("Log file "+log.getAbsolutePath()+" does not exist"); 503 } 504 return searchFile(log, minLevel, textPattern, firstLine, lastLine, maxResults, includeStackTraces); 506 } 507 508 511 public void reconfigure() { 512 File file = resolveConfigurationFile(); 513 if (file == null || !file.exists()) { 514 return; 515 } 516 517 System.setProperty("org.apache.geronimo.log.ConsoleLogLevel", GeronimoLogging.getConsoleLogLevel().toString()); 519 520 try { 521 URLConfigurator.configure(file.toURL()); 522 } catch (MalformedURLException e) { 523 e.printStackTrace(); 524 } 525 526 GeronimoLogFactory logFactory = (GeronimoLogFactory) LogFactory.getFactory(); 528 Set instances = logFactory.getInstances(); 529 for (Iterator iterator = instances.iterator(); iterator.hasNext();) { 530 Object log = iterator.next(); 531 if (log instanceof CachingLog4jLog) { 532 ((CachingLog4jLog)log).updateLevelInfo(); 533 } 534 } 535 } 536 537 private synchronized void schedule() { 538 if (timer != null) { 539 if (monitor != null) { 541 monitor.cancel(); 542 } 543 544 monitor = new URLMonitorTask(); 546 TimerTask task = monitor; 547 timer.schedule(monitor, 1000 * refreshPeriod, 1000 * refreshPeriod); 548 task.run(); 549 } 550 } 551 552 public void doStart() { 553 LogFactory logFactory = LogFactory.getFactory(); 554 if (logFactory instanceof GeronimoLogFactory) { 555 synchronized (this) { 556 timer = new Timer (true); 557 558 schedule(); 560 561 Logger logger = LogManager.getRootLogger(); 563 564 reconfigure(); 565 566 File file = resolveConfigurationFile(); 567 if (file != null) { 568 lastChanged = file.lastModified(); 569 } 570 logEnvInfo(logger); 571 } 572 573 GeronimoLogFactory geronimoLogFactory = (GeronimoLogFactory) logFactory; 575 synchronized (geronimoLogFactory) { 576 if (!(geronimoLogFactory.getLogFactory() instanceof CachingLog4jLogFactory)) { 577 geronimoLogFactory.setLogFactory(new CachingLog4jLogFactory()); 578 } 579 } 580 } 581 582 synchronized (this) { 583 running = true; 584 } 585 } 586 587 public synchronized void doStop() { 588 running = false; 589 if (monitor != null) { 590 monitor.cancel(); 591 monitor = null; 592 } 593 if (timer != null) { 594 timer.cancel(); 595 timer = null; 596 } 597 } 598 599 public void doFail() { 600 doStop(); 601 } 602 603 private synchronized File resolveConfigurationFile() { 604 try { 605 return serverInfo.resolveServer(configurationFile); 606 } catch (Exception e) { 607 return null; 608 } 609 } 610 611 private void logEnvInfo(Logger log) { 612 try { 613 log.info("----------------------------------------------"); 614 log.info("Started Logging Service"); 615 log.debug("Log4jService created with configFileName=" + this.configurationFile + 616 ", refreshPeriodSeconds=" + this.refreshPeriod); 617 log.info("Runtime Information:"); 618 log.info(" Install Directory = " + DirectoryUtils.getGeronimoInstallDirectory().toString()); 619 log.info(" JVM in use = " + System.getProperty("java.vendor") + " Java " + System.getProperty("java.version")); 620 log.info("Java Information:"); 621 log.info(" System property [java.runtime.name] = " + System.getProperty("java.runtime.name")); 622 log.info(" System property [java.runtime.version] = " + System.getProperty("java.runtime.version")); 623 log.info(" System property [os.name] = " + System.getProperty("os.name")); 624 log.info(" System property [os.version] = " + System.getProperty("os.version")); 625 log.info(" System property [sun.os.patch.level] = " + System.getProperty("sun.os.patch.level")); 626 log.info(" System property [os.arch] = " + System.getProperty("os.arch")); 627 log.info(" System property [java.class.version] = " + System.getProperty("java.class.version")); 628 log.info(" System property [locale] = " + System.getProperty("user.language") + "_" + System.getProperty("user.country")); 629 log.info(" System property [unicode.encoding] = " + System.getProperty("sun.io.unicode.encoding")); 630 log.info(" System property [file.encoding] = " + System.getProperty("file.encoding")); 631 log.info(" System property [java.vm.name] = " + System.getProperty("java.vm.name")); 632 log.info(" System property [java.vm.vendor] = " + System.getProperty("java.vm.vendor")); 633 log.info(" System property [java.vm.version] = " + System.getProperty("java.vm.version")); 634 log.info(" System property [java.vm.info] = " + System.getProperty("java.vm.info")); 635 log.info(" System property [java.home] = " + System.getProperty("java.home")); 636 log.info(" System property [java.classpath] = " + System.getProperty("java.classpath")); 637 log.info(" System property [java.library.path] = " + System.getProperty("java.library.path")); 638 log.info(" System property [java.endorsed.dirs] = " + System.getProperty("java.endorsed.dirs")); 639 log.info(" System property [java.ext.dirs] = " + System.getProperty("java.ext.dirs")); 640 log.info(" System property [sun.boot.class.path] = " + System.getProperty("sun.boot.class.path")); 641 log.info("----------------------------------------------"); 642 } catch (Exception e) { 643 String msg = "Exception caught during logging of Runtime Information. Exception=" + e.toString(); 644 log.error(msg); 645 System.err.println(msg); 646 } 647 } 648 649 650 private class URLMonitorTask extends TimerTask { 651 public void run() { 652 try { 653 long lastModified; 654 synchronized (this) { 655 if (running == false) { 656 return; 657 } 658 659 File file = resolveConfigurationFile(); 660 if (file == null) { 661 return; 662 } 663 664 lastModified = file.lastModified(); 665 } 666 667 if (lastChanged < lastModified) { 668 lastChanged = lastModified; 669 reconfigure(); 670 } 671 } catch (Exception e) { 672 } 673 } 674 } 675 676 private static class CachingLog4jLogFactory extends LogFactory { 677 public Log getInstance(Class clazz) throws LogConfigurationException { 678 return getInstance(clazz.getName()); 679 } 680 681 public Log getInstance(String name) throws LogConfigurationException { 682 return new CachingLog4jLog(name); 683 } 684 685 public Object getAttribute(String name) { 686 return null; 687 } 688 689 public String [] getAttributeNames() { 690 return new String [0]; 691 } 692 693 public void release() { 694 } 695 696 public void removeAttribute(String name) { 697 } 698 699 public void setAttribute(String name, Object value) { 700 } 701 } 702 703 public static final GBeanInfo GBEAN_INFO; 704 705 static { 706 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(Log4jService.class, "SystemLog"); 707 708 infoFactory.addAttribute("configFileName", String .class, true); 709 infoFactory.addAttribute("refreshPeriodSeconds", int.class, true); 710 infoFactory.addAttribute("configuration", String .class, false); 711 infoFactory.addAttribute("rootLoggerLevel", String .class, false); 712 713 infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean"); 714 715 infoFactory.addOperation("reconfigure", "void"); 716 infoFactory.addOperation("setLoggerLevel", new Class []{String .class, String .class}, "void"); 717 infoFactory.addOperation("getLoggerLevel", new Class []{String .class}, "java.lang.String"); 718 infoFactory.addOperation("getLoggerEffectiveLevel", new Class []{String .class}, "java.lang.String"); 719 infoFactory.addInterface(SystemLog.class); 720 721 infoFactory.setConstructor(new String []{"configFileName", "refreshPeriodSeconds", "ServerInfo"}); 722 723 GBEAN_INFO = infoFactory.getBeanInfo(); 724 } 725 726 public static GBeanInfo getGBeanInfo() { 727 return GBEAN_INFO; 728 } 729 } 730 | Popular Tags |