1 23 24 package com.sun.enterprise.management.ext.logging; 25 26 import java.util.Map ; 27 import java.util.HashMap ; 28 import java.util.Set ; 29 import java.util.List ; 30 import java.util.ArrayList ; 31 import java.util.Collections ; 32 import java.util.Date ; 33 import java.util.Properties ; 34 import java.util.logging.Level ; 35 import java.util.logging.LogRecord ; 36 import java.util.logging.Formatter ; 37 38 import java.io.File ; 39 import java.io.FileNotFoundException ; 40 import java.io.IOException ; 41 import java.io.Serializable ; 42 import java.io.PrintStream ; 43 import java.io.File ; 44 45 46 import javax.management.MBeanServer ; 47 import javax.management.Attribute ; 48 import javax.management.AttributeList ; 49 import javax.management.MBeanInfo ; 50 import javax.management.MBeanOperationInfo ; 51 import javax.management.MBeanNotificationInfo ; 52 import javax.management.NotificationListener ; 53 import javax.management.NotificationFilter ; 54 import javax.management.Notification ; 55 import javax.management.NotificationEmitter ; 56 import javax.management.ObjectName ; 57 import javax.management.MBeanServerInvocationHandler ; 58 59 import com.sun.appserv.management.base.AMX; 60 import com.sun.appserv.management.base.Util; 61 import com.sun.appserv.management.base.XTypes; 62 import com.sun.enterprise.management.support.AMXImplBase; 63 import com.sun.enterprise.management.support.BootUtil; 64 import com.sun.enterprise.management.support.AMXImplBase; 65 66 import com.sun.appserv.management.ext.logging.Logging; 67 import static com.sun.appserv.management.ext.logging.Logging.*; 68 import com.sun.appserv.management.ext.logging.LogQueryResult; 69 import com.sun.appserv.management.ext.logging.LogQueryResultImpl; 70 import com.sun.appserv.management.util.misc.ListUtil; 71 import com.sun.appserv.management.util.misc.MapUtil; 72 import com.sun.appserv.management.util.misc.GSetUtil; 73 import com.sun.appserv.management.util.misc.FileUtils; 74 import com.sun.appserv.management.util.misc.ThrowableMapper; 75 import com.sun.appserv.management.util.misc.ExceptionUtil; 76 import com.sun.appserv.management.util.misc.TypeCast; 77 78 import com.sun.appserv.management.util.jmx.NotificationBuilder; 79 import com.sun.appserv.management.util.jmx.JMXUtil; 80 import com.sun.appserv.management.util.jmx.NotificationEmitterSupport; 81 82 import com.sun.enterprise.server.logging.LoggingImplHook; 83 84 92 public final class LoggingImpl extends AMXImplBase 93 implements LoggingImplHook 94 { 95 private LogMBeanIntf mLogMBean; 96 private final Map <Level ,String > mLevelToNotificationTypeMap; 97 private final Map <String ,NotificationBuilder> mNotificationTypeToNotificationBuilderMap; 98 99 private static final String SERVER_LOG_NAME = "server.log"; 100 private static final String ACCESS_LOG_NAME = "access.log"; 101 102 final String FILE_SEP; 103 104 private final String mServerName; 105 106 111 public static ObjectName 112 getObjectName( final String serverName ) 113 { 114 final String requiredProps = Util.makeRequiredProps( XTypes.LOGGING, serverName ); 115 final String parentProp = Util.makeProp( XTypes.SERVER_ROOT_MONITOR, serverName ); 116 final String props = Util.concatenateProps( requiredProps, parentProp ); 117 118 return Util.newObjectName( AMX.JMX_DOMAIN, props ); 119 } 120 121 private final static String LOGMBEAN_OBJECT_NAME_PREFIX = 122 "com.sun.appserv:name=logmanager,category=runtime,server="; 123 124 126 public LoggingImpl( final String serverName ) 127 { 128 mServerName = serverName; 129 mLogMBean = null; 130 FILE_SEP = System.getProperty( "file.separator" ); 131 132 mLevelToNotificationTypeMap = initLevelToNotificationTypeMap(); 133 mNotificationTypeToNotificationBuilderMap = new HashMap <String ,NotificationBuilder>(); 134 } 135 136 137 141 protected MBeanInfo 142 modifyMBeanInfo( final MBeanInfo info ) 143 { 144 final MBeanOperationInfo [] ops = info.getOperations(); 145 146 final int idx = JMXUtil.findMBeanOperationInfo( info, "queryServerLog", null); 147 148 final MBeanOperationInfo op = ops[idx]; 149 ops[idx] = new MBeanOperationInfo ( op.getName(), op.getDescription(), 150 op.getSignature(), Map .class.getName(), 151 MBeanOperationInfo.INFO ); 152 153 return JMXUtil.newMBeanInfo( info, ops ); 154 } 155 156 157 158 private static MBeanNotificationInfo [] SELF_NOTIFICATION_INFOS = null; 159 163 private static synchronized MBeanNotificationInfo [] 164 getSelfNotificationInfos() 165 { 166 if ( SELF_NOTIFICATION_INFOS == null ) 167 { 168 final String [] types = GSetUtil.toStringArray( ALL_LOG_RECORD_NOTIFICATION_TYPES ); 169 final MBeanNotificationInfo selfInfo = new MBeanNotificationInfo ( 170 types, Notification .class.getName(), "LogRecord notifications" ); 171 172 SELF_NOTIFICATION_INFOS = new MBeanNotificationInfo [] { selfInfo }; 173 } 174 return( SELF_NOTIFICATION_INFOS ); 175 } 176 177 public MBeanNotificationInfo [] 178 getNotificationInfo() 179 { 180 final MBeanNotificationInfo [] superInfos = super.getNotificationInfo(); 181 182 final MBeanNotificationInfo [] all = 183 JMXUtil.mergeMBeanNotificationInfos( superInfos, getSelfNotificationInfos() ); 184 185 return all; 186 } 187 188 189 private Object 190 newProxy( 191 final ObjectName target, 192 final Class interfaceClass ) 193 { 194 return( MBeanServerInvocationHandler.newProxyInstance( 195 getMBeanServer(), target, interfaceClass, true ) ); 196 } 197 198 public String 199 getGroup() 200 { 201 return( AMX.GROUP_MONITORING ); 202 } 203 204 private LogMBeanIntf 205 getLogMBean() 206 { 207 initLogMBean(); 208 return mLogMBean; 209 } 210 211 private void 212 initLogMBean() 213 { 214 if ( mLogMBean == null ) 215 synchronized( this ) 216 { 217 if ( mLogMBean == null ) 218 { 219 final ObjectName logMBeanObjectName = 220 Util.newObjectName( LOGMBEAN_OBJECT_NAME_PREFIX + mServerName ); 221 222 mLogMBean = (LogMBeanIntf)newProxy( logMBeanObjectName, LogMBeanIntf.class ); 223 } 224 } 225 } 226 227 protected synchronized ObjectName 228 getContainerObjectName( final ObjectName selfObjectName ) 229 { 230 ObjectName containerObjectName = null; 231 232 try 235 { 236 containerObjectName = super.getContainerObjectName( selfObjectName ); 237 } 238 catch( Exception e ) 239 { 240 containerObjectName = null; 242 } 243 return containerObjectName; 244 } 245 246 247 public void 248 setModuleLogLevel( 249 final String module, 250 final String level ) 251 { 252 getLogMBean().setLogLevel( module, level ); 253 } 254 255 public String 256 getModuleLogLevel( final String module) 257 { 258 return getLogMBean().getLogLevel( module ); 259 } 260 261 public int 262 getLogLevelListenerCount( final Level logLevel ) 263 { 264 final String notifType = logLevelToNotificationType( logLevel ); 265 266 final int count = getNotificationEmitter().getNotificationTypeListenerCount( notifType ); 267 return( count ); 268 } 269 270 public String [] 271 getLogFileKeys() 272 { 273 return new String [] { SERVER_KEY, ACCESS_KEY }; 274 } 275 276 277 public synchronized String [] 278 getLogFileNames( final String key ) 279 { 280 String [] result = null; 281 282 if ( SERVER_KEY.equals( key ) ) 283 { 284 result = getLogMBean().getArchivedLogfiles(); 285 } 286 else 287 { 288 throw new IllegalArgumentException ( key ); 289 } 290 291 return result; 292 } 293 294 295 public synchronized String 296 getLogFile( final String key, final String fileName ) 297 { 298 if ( ! SERVER_KEY.equals( key ) ) 299 { 300 throw new IllegalArgumentException ( "" + key ); 301 } 302 303 final String dir = getLogMBean().getLogFilesDirectory(); 304 final String file = dir + FILE_SEP + fileName; 305 306 try 307 { 308 return FileUtils.fileToString( new File ( file ) ); 309 } 310 catch( FileNotFoundException e ) 311 { 312 throw new RuntimeException ( e ); 313 } 314 catch( IOException e ) 315 { 316 throw new RuntimeException ( e ); 317 } 318 } 319 320 321 public synchronized void 322 rotateAllLogFiles() 323 { 324 getLogMBean().rotateNow( ); 325 } 326 327 328 329 public synchronized void 330 rotateLogFile( final String key ) 331 { 332 if ( ACCESS_KEY.equals( key ) ) 333 { 334 throw new IllegalArgumentException ( "not supported: " + key ); 335 } 337 else if ( SERVER_KEY.equals( key ) ) 338 { 339 rotateAllLogFiles(); 340 } 341 else 342 { 343 throw new IllegalArgumentException ( "" + key ); 344 } 345 } 346 347 348 349 350 private Properties 351 attributesToProps( List <Attribute > attrs ) 352 { 353 final Properties props = new Properties (); 354 355 if ( attrs != null ) 356 { 357 for( Attribute attr: attrs) 358 { 359 final Object value = attr.getValue(); 360 if ( value == null ) 361 { 362 throw new IllegalArgumentException ( attr.getName() + "=" + null); 363 } 364 365 props.put( attr.getName(), value.toString() ); 366 } 367 } 368 369 return( props ); 370 } 371 372 private List <Serializable []> 373 convertQueryResult( final AttributeList queryResult ) 374 { 375 final AttributeList fieldAttrs = (AttributeList )((Attribute )queryResult.get( 0 )).getValue(); 377 final String [] fieldHeaders = new String [ fieldAttrs.size() ]; 378 for( int i = 0; i < fieldHeaders.length; ++i ) 379 { 380 final Attribute attr = (Attribute )fieldAttrs.get( i ); 381 fieldHeaders[ i ] = (String )attr.getValue(); 382 } 383 384 final List <List <Serializable >> srcRecords = TypeCast.asList( 385 ((Attribute )queryResult.get( 1 )).getValue() ); 386 387 final List <Serializable []> results = new ArrayList <Serializable []>( srcRecords.size() ); 389 results.add( fieldHeaders ); 390 391 for( int recordIdx = 0; recordIdx < srcRecords.size(); ++recordIdx ) 393 { 394 final List <Serializable > record = srcRecords.get( recordIdx ); 395 396 assert( record.size() == fieldHeaders.length ); 397 final Serializable [] fieldValues = new Serializable [ fieldHeaders.length ]; 398 for( int fieldIdx = 0; fieldIdx < fieldValues.length; ++fieldIdx ) 399 { 400 fieldValues[ fieldIdx ] = record.get( fieldIdx ); 401 } 402 403 results.add( fieldValues ); 404 } 405 406 return results; 407 } 408 409 public List <Serializable []> 410 queryServerLog( 411 String name, 412 long startIndex, 413 boolean searchForward, 414 int maximumNumberOfResults, 415 Long fromTime, 416 Long toTime, 417 String logLevel, 418 Set <String > modules, 419 List <Attribute > nameValuePairs) 420 { 421 final List <Serializable []> result = queryServerLogInternal( 422 name, startIndex, searchForward, maximumNumberOfResults, 423 fromTime, toTime, logLevel, modules, nameValuePairs ); 424 return result; 425 } 426 427 private List <Serializable []> 428 queryServerLogInternal( 429 final String name, 430 final long startIndex, 431 final boolean searchForward, 432 final int maximumNumberOfResults, 433 final Long fromTime, 434 final Long toTime, 435 final String logLevel, 436 final Set <String > modules, 437 final List <Attribute > nameValuePairs) 438 { 439 if ( name == null ) 440 { 441 throw new IllegalArgumentException ( "use MOST_RECENT_NAME, not null" ); 442 } 443 444 final boolean sortAscending = true; 445 final List <String > moduleList = ListUtil.newListFromCollection( modules ); 446 final Properties props = attributesToProps( nameValuePairs ); 447 448 String actualName; 449 if ( MOST_RECENT_NAME.equals( name ) ) 450 { 451 actualName = null; 452 } 453 else 454 { 455 actualName = name; 456 } 457 final AttributeList result = getLogMBean().getLogRecordsUsingQuery( 458 actualName, 459 new Long ( startIndex ), 460 searchForward, 461 sortAscending, 462 maximumNumberOfResults, 463 fromTime == null ? null : new Date ( fromTime ), 464 toTime == null ? null : new Date ( toTime ), 465 logLevel, 466 true, 467 moduleList, 468 props) ; 469 470 return convertQueryResult( result ); 471 } 472 473 public Map <String ,Number >[] 474 getErrorInfo() 475 { 476 final List <Map <String ,Object >> infos = getLogMBean().getErrorInformation(); 477 478 final Map <String ,Number >[] results = TypeCast.asArray( new HashMap [ infos.size() ] ); 479 480 for( int i = 0; i < results.length; ++i ) 481 { 482 final Map <String ,Object > info = infos.get( i ); 483 484 assert( info.keySet().size() == 3 ); 485 486 final Long timestamp = Long.parseLong( info.get( TIMESTAMP_KEY ).toString() ); 487 final Integer severeCount = Integer.parseInt( info.get( SEVERE_COUNT_KEY ).toString() ); 488 final Integer warningCount= Integer.parseInt( info.get( WARNING_COUNT_KEY ).toString() ); 489 490 final Map <String ,Number > item = new HashMap <String ,Number >( info.size() ); 491 item.put( TIMESTAMP_KEY, timestamp); 492 item.put( SEVERE_COUNT_KEY, severeCount); 493 item.put( WARNING_COUNT_KEY, warningCount); 494 495 results[ i ] = item; 496 } 497 498 return results; 499 } 500 501 502 private static final Integer INTEGER_0 = new Integer ( 0 ); 503 504 private static final Map <String ,Integer > EMPTY_ERROR_DISTRIBUTION_MAP = 505 Collections.emptyMap(); 506 507 private static final Set <String > LEGAL_DISTRIBUTION_LEVELS = 508 GSetUtil.newUnmodifiableStringSet( 509 Level.SEVERE.toString(), Level.WARNING.toString() ); 510 511 512 513 public Map <String ,Integer > 514 getErrorDistribution(long timestamp, String level) 515 { 516 if ( ! LEGAL_DISTRIBUTION_LEVELS.contains( level ) ) 517 { 518 throw new IllegalArgumentException ( level ); 519 } 520 521 Map <String ,Integer > result = 522 getLogMBean().getErrorDistribution( timestamp, Level.parse( level ) ); 523 524 if ( result != null ) 526 { 527 final Set <String > moduleIDs = result.keySet(); 528 529 for( final String moduleID : moduleIDs ) 531 { 532 if ( result.get( moduleID ) == null ) 533 { 534 result.put( moduleID, INTEGER_0 ); 535 } 536 } 537 } 538 else 539 { 540 result = EMPTY_ERROR_DISTRIBUTION_MAP; 542 } 543 544 return result; 545 } 546 547 548 public void 549 setKeepErrorStatisticsForIntervals( final int num) 550 { 551 getLogMBean().setKeepErrorStatisticsForIntervals( num ); 552 } 553 554 public int 555 getKeepErrorStatisticsForIntervals() 556 { 557 return getLogMBean().getKeepErrorStatisticsForIntervals(); 558 } 559 560 public void 561 setErrorStatisticsIntervalMinutes(final long minutes) 562 { 563 getLogMBean().setErrorStatisticsIntervalDuration( minutes ); 564 } 565 566 public long 567 getErrorStatisticsIntervalMinutes() 568 { 569 return getLogMBean().getErrorStatisticsIntervalDuration(); 570 } 571 572 public String [] 573 getLoggerNames() 574 { 575 final List <String > names = 576 TypeCast.checkList( getLogMBean().getLoggerNames(), String .class ); 577 578 return names.toArray( EMPTY_STRING_ARRAY ); 579 } 580 581 public String [] 582 getLoggerNamesUnder( final String loggerName ) 583 { 584 final List <String > names = TypeCast.checkList( 585 getLogMBean().getLoggerNamesUnder( loggerName ), String .class ); 586 587 return names.toArray( EMPTY_STRING_ARRAY ); 588 } 589 590 591 592 public String [] 593 getDiagnosticCauses( final String messageID ) 594 { 595 final List <String > causes = TypeCast.checkList( 596 getLogMBean().getDiagnosticCausesForMessageId( messageID ), String .class ); 597 598 String [] result = null; 599 if ( causes != null ) 600 { 601 result = (String [])causes.toArray( new String [causes.size()] ); 602 } 603 604 return result; 605 } 606 607 public String [] 608 getDiagnosticChecks( final String messageID ) 609 { 610 final List <String > checks = TypeCast.checkList( 611 getLogMBean().getDiagnosticChecksForMessageId( messageID ), String .class ); 612 613 String [] result = null; 614 if ( checks != null ) 615 { 616 result = new String [checks.size()]; 617 checks.toArray( result ); 618 } 619 620 return result; 621 } 622 623 public String 624 getDiagnosticURI( final String messageID ) 625 { 626 return getLogMBean().getDiagnosticURIForMessageId( messageID ); 627 } 628 629 630 private static final Object [] 631 LEVELS_AND_NOTIF_TYPES = new Object [] 632 { 633 Level.SEVERE, LOG_RECORD_SEVERE_NOTIFICATION_TYPE, 634 Level.WARNING, LOG_RECORD_WARNING_NOTIFICATION_TYPE, 635 Level.INFO, LOG_RECORD_INFO_NOTIFICATION_TYPE, 636 Level.CONFIG, LOG_RECORD_CONFIG_NOTIFICATION_TYPE, 637 Level.FINE, LOG_RECORD_FINE_NOTIFICATION_TYPE, 638 Level.FINER, LOG_RECORD_FINER_NOTIFICATION_TYPE, 639 Level.FINEST, LOG_RECORD_FINEST_NOTIFICATION_TYPE, 640 }; 641 642 private static Map <Level ,String > 643 initLevelToNotificationTypeMap() 644 { 645 final Map <Level ,String > m = new HashMap <Level ,String >(); 646 647 for( int i = 0; i < LEVELS_AND_NOTIF_TYPES.length; i += 2 ) 648 { 649 final Level level = (Level )LEVELS_AND_NOTIF_TYPES[ i ]; 650 final String notifType = (String )LEVELS_AND_NOTIF_TYPES[ i + 1 ]; 651 m.put( level, notifType ); 652 } 653 654 return( Collections.unmodifiableMap( m ) ); 655 } 656 657 private String 658 logLevelToNotificationType( final Level level ) 659 { 660 String notificationType = mLevelToNotificationTypeMap.get( level ); 661 662 if ( notificationType == null ) 663 { 664 } 665 666 return notificationType; 667 } 668 669 670 protected void 671 preRegisterDone() 672 throws Exception 673 { 674 initNotificationTypeToNotificationBuilderMap( getObjectName() ); 675 } 676 677 private void 678 initNotificationTypeToNotificationBuilderMap( final ObjectName objectName ) 679 { 680 mNotificationTypeToNotificationBuilderMap.clear(); 681 for( final String notifType : ALL_LOG_RECORD_NOTIFICATION_TYPES ) 682 { 683 mNotificationTypeToNotificationBuilderMap.put( 684 notifType, 685 new NotificationBuilder( notifType, objectName ) ); 686 } 687 } 688 689 690 private NotificationBuilder 691 notificationTypeToNotificationBuilder( final String notificationType ) 692 { 693 NotificationBuilder builder = 694 mNotificationTypeToNotificationBuilderMap.get( notificationType ); 695 696 assert( builder != null ); 697 698 return builder; 699 } 700 701 702 private Map <String ,Serializable > 703 logRecordToMap( 704 final LogRecord record, 705 final String recordAsString ) 706 { 707 final Map <String ,Serializable > m = new HashMap <String ,Serializable >(); 708 709 m.put( LOG_RECORD_AS_STRING_KEY, recordAsString ); 710 m.put( LOG_RECORD_LEVEL_KEY, record.getLevel() ); 711 m.put( LOG_RECORD_LOGGER_NAME_KEY, record.getLoggerName() ); 712 m.put( LOG_RECORD_MESSAGE_KEY, record.getMessage() ); 713 m.put( LOG_RECORD_MILLIS_KEY, record.getMillis() ); 714 m.put( LOG_RECORD_SEQUENCE_NUMBER_KEY, record.getSequenceNumber() ); 715 m.put( LOG_RECORD_SOURCE_CLASS_NAME_KEY, record.getSourceClassName() ); 716 m.put( LOG_RECORD_SOURCE_METHOD_NAME_KEY, record.getSourceMethodName() ); 717 m.put( LOG_RECORD_THREAD_ID_KEY, record.getThreadID() ); 718 final Throwable thrown = record.getThrown(); 719 if ( thrown != null ) 720 { 721 final Throwable mapped = new ThrowableMapper( thrown ).map(); 722 m.put( LOG_RECORD_THROWN_KEY, mapped ); 723 724 final Throwable rootCause = ExceptionUtil.getRootCause( thrown ); 725 if ( rootCause != thrown ) 726 { 727 final Throwable mappedRootCause = new ThrowableMapper( rootCause ).map(); 728 m.put( LOG_RECORD_ROOT_CAUSE_KEY, mappedRootCause ); 729 } 730 } 731 return m; 732 } 733 734 735 private long mMyThreadID = -1; 736 739 public void 740 privateLoggingHook( 741 final LogRecord logRecord, 742 final Formatter formatter ) 743 { 744 746 if ( logRecord.getThreadID() == mMyThreadID ) 747 { 748 debug( "privateLoggingHook: recusive call!!!" ); 749 throw new RuntimeException ( "recursive call" ); 750 } 751 synchronized( this ) 752 { 753 mMyThreadID = Thread.currentThread().getId(); 754 755 final Level level = logRecord.getLevel(); 756 757 try 758 { 759 if ( getLogLevelListenerCount( level ) != 0 ) 761 { 762 final String notifType = logLevelToNotificationType( level ); 763 764 final NotificationBuilder builder = 765 notificationTypeToNotificationBuilder( notifType ); 766 767 final String logRecordAsString = formatter.format( logRecord ); 769 770 final Map <String ,Serializable > userData = 771 logRecordToMap( logRecord, logRecordAsString ); 772 773 final Notification notif = 774 builder.buildNewWithMap( logRecordAsString, userData); 775 776 debug( "privateLoggingHook: sending: " + notif ); 777 sendNotification( notif ); 778 } 779 else 780 { 781 } 783 } 784 finally 785 { 786 mMyThreadID = -1; 787 } 788 } 789 } 790 791 public void 792 testEmitLogMessage( final String level, final String message ) 793 { 794 final Level saveLevel = getMBeanLogLevel(); 795 796 setMBeanLogLevel( Level.parse( level ) ); 797 try 798 { 799 debug( "testEmitLogMessage: logging: message = " + message ); 800 getLogger().log( Level.parse( level ), message ); 801 } 802 finally 803 { 804 setMBeanLogLevel( saveLevel ); 805 } 806 } 807 808 850 } 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 | Popular Tags |