00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "CeylanLogAggregator.h"
00028
00029 #include "CeylanLog.h"
00030 #include "CeylanLogLight.h"
00031 #include "CeylanObjectIdentifier.h"
00032 #include "CeylanObjectChannel.h"
00033 #include "CeylanLoggable.h"
00034 #include "CeylanStringUtils.h"
00035
00036 #include "CeylanOperators.h"
00037 #include "CeylanLogPlug.h"
00038 #include "CeylanLogChannel.h"
00039 #include "CeylanLogMessage.h"
00040
00041
00042 #ifdef CEYLAN_USES_CONFIG_H
00043 #include "CeylanConfig.h"
00044 #endif // CEYLAN_USES_CONFIG_H
00045
00046
00047
00048
00049 using std::string ;
00050 using std::list ;
00051
00052 using namespace Ceylan::Log ;
00053
00054
00055
00056 LogAggregator::LogAggregatorException::LogAggregatorException(
00057 const string & message ) :
00058 LogException( message )
00059 {
00060
00061 }
00062
00063
00064
00065 LogAggregator::LogAggregatorException::~LogAggregatorException() throw()
00066 {
00067
00068 }
00069
00070
00071
00072
00073 const LevelOfDetail LogAggregator::DefaultGlobalLevelOfDetail
00074 = Ceylan::Log::DefaultLevelOfDetailForListener ;
00075
00076
00077
00078 LogAggregator::LogAggregator( bool beSmart,
00079 bool useGlobalLevelOfDetail ) :
00080 _beSmart( beSmart ),
00081 _useGlobalLevelOfDetail( useGlobalLevelOfDetail ),
00082 _globalLevelOfDetail( DefaultGlobalLevelOfDetail )
00083 {
00084
00085 CEYLAN_LOG( "LogAggregator constructor." ) ;
00086
00087 }
00088
00089
00090 LogAggregator::~LogAggregator() throw()
00091 {
00092
00093 CEYLAN_LOG( "LogAggregator destructor called." ) ;
00094
00095
00096
00097 CEYLAN_LOG( "### Removing " + Ceylan::toString( _channelList.size() )
00098 + " channels." ) ;
00099
00100
00101 for ( list<LogChannel *>::iterator it = _channelList.begin();
00102 it != _channelList.end(); it++ )
00103 {
00104 if ( (*it) != 0 )
00105 {
00106
00107 CEYLAN_LOG( "Removing channel " + (*it)->toString( low ) ) ;
00108
00109 delete (*it) ;
00110
00111 CEYLAN_LOG( "...done" ) ;
00112
00113 }
00114 }
00115
00116 }
00117
00118
00119
00120 LogChannel & LogAggregator::createBasicChannel( const string & channelName )
00121 {
00122
00123 #if CEYLAN_DEBUG
00124
00125 if ( hasChannel( channelName ) )
00126 throw LogException( "LogAggregator::createBasicChannel: "
00127 "attempt to create an already-existing channel." ) ;
00128
00129 CEYLAN_LOG( "LogAggregator: creating basic channel " + channelName ) ;
00130
00131 #endif // CEYLAN_DEBUG
00132
00133 LogChannel * newChannel = new LogChannel( channelName ) ;
00134 _channelList.push_back( newChannel ) ;
00135
00136 return * newChannel ;
00137
00138 }
00139
00140
00141
00142 ObjectChannel & LogAggregator::createObjectChannel( LogMessage & message )
00143 {
00144
00145 string realChannelName = Loggable::GetEmbeddedChannelName(
00146 message.getChannelName() ) ;
00147
00148 #if CEYLAN_DEBUG
00149
00150 if ( hasChannel( realChannelName ) )
00151 throw LogException( "LogAggregator::createObjectChannel: "
00152 "attempt to create an already-existing channel, "
00153 + realChannelName + "." ) ;
00154
00155 CEYLAN_LOG( "LogAggregator: creating object channel for "
00156 + realChannelName ) ;
00157
00158 #endif // CEYLAN_DEBUG
00159
00160 ObjectChannel * newChannel = new ObjectChannel( realChannelName ) ;
00161 _channelList.push_back( newChannel ) ;
00162
00163 CEYLAN_LOG( "New object channel registered." ) ;
00164
00165 return * newChannel ;
00166
00167 }
00168
00169
00170
00171 bool LogAggregator::hasChannel( const std::string & channelName ) const
00172 {
00173
00174 return ( findChannel( channelName ) != 0 ) ;
00175
00176 }
00177
00178
00179
00180
00181 LogChannel * LogAggregator::findChannel( const string & channelName ) const
00182 {
00183
00184 CEYLAN_LOG( "LogAggregator::findChannel: looking for channel "
00185 + channelName ) ;
00186
00187
00188
00189
00190
00191
00192
00193
00194 if ( Loggable::IsALoggableChannelName( channelName ) )
00195 return findObjectChannel(
00196 Loggable::GetEmbeddedChannelName( channelName ) ) ;
00197 else
00198 return findBasicChannel( channelName ) ;
00199
00200 }
00201
00202
00203
00204 void LogAggregator::transferChannel( LogChannel & source, LogChannel & target )
00205 {
00206
00207 CEYLAN_LOG( "LogAggregator::transferChannel, from "
00208 + source.getName()
00209 + " to " + target.getName() ) ;
00210
00211 CEYLAN_LOG( "Source channel is: " + source.toString() ) ;
00212 CEYLAN_LOG( "Target channel is: " + target.toString() ) ;
00213
00214
00215
00216
00217
00218
00219
00220 for ( list<LogMessage *>::iterator it = source._messages.begin();
00221 it != source._messages.end(); it++ )
00222 {
00223
00224 #if CEYLAN_DEBUG
00225
00226 if ( (*it) == 0 )
00227 throw LogException( "LogAggregator::transferChannel: "
00228 "null pointer in channel list." ) ;
00229
00230 #endif // CEYLAN_DEBUG
00231
00232
00233 LogMessage * movedMessage = *it ;
00234 CEYLAN_LOG( "LogAggregator::transferChannel: moving "
00235 + movedMessage->toString( Ceylan::low ) ) ;
00236
00237 movedMessage->setChannelName( target.getName() ) ;
00238 target.addMessage( * movedMessage ) ;
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 *it = 0 ;
00250
00251 }
00252
00253
00254
00255
00256
00257
00258 source._messages.clear() ;
00259
00260
00261 removeChannel( source ) ;
00262
00263 }
00264
00265
00266
00267 void LogAggregator::removeChannel( LogChannel & target )
00268 {
00269
00270 CEYLAN_LOG( "Removing channel " + target.getName() ) ;
00271
00272 _channelList.remove( & target ) ;
00273 delete & target ;
00274
00275 }
00276
00277
00278
00279 void LogAggregator::store( LogMessage & message )
00280 {
00281
00282 CEYLAN_LOG( "LogAggregator::store: incoming message is '"
00283 + message.toString() + "'." ) ;
00284
00285
00286
00287
00288
00289
00290
00291 if ( Loggable::IsALoggableChannelName( message.getChannelName() ) )
00292 storeObjectMessage( message ) ;
00293 else
00294 storeBasicMessage( message ) ;
00295
00296 CEYLAN_LOG( "LogAggregator::store: done" ) ;
00297
00298 }
00299
00300
00301
00302 LogChannel * LogAggregator::findBasicChannel(
00303 const string & basicChannelName ) const
00304 {
00305
00306 CEYLAN_LOG( "LogAggregator::findBasicChannel: "
00307 "searching basic channels for " + basicChannelName ) ;
00308
00309 for ( list<LogChannel *>::const_iterator it = _channelList.begin();
00310 it != _channelList.end(); it++ )
00311 {
00312
00313 #if CEYLAN_DEBUG
00314
00315 if ( (*it) == 0 )
00316 throw LogException( "LogAggregator::findBasicChannel: "
00317 "null pointer in channel list." ) ;
00318
00319 #endif // CEYLAN_DEBUG
00320
00321 ObjectChannel * objChannel =
00322 dynamic_cast<ObjectChannel *>( (*it) ) ;
00323
00324 if ( objChannel == 0 )
00325 {
00326
00327 CEYLAN_LOG( (*it)->getName()
00328 + " is a basic log channel." ) ;
00329
00330 if ( (*it)->getName() == basicChannelName )
00331 return (*it) ;
00332 }
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343 return 0 ;
00344
00345 }
00346
00347
00348
00349 ObjectChannel * LogAggregator::findObjectChannel(
00350 const string & nonPrefixedChannelName ) const
00351 {
00352
00353 CEYLAN_LOG( "LogAggregator::findObjectChannel: "
00354 "searching object channels for " + nonPrefixedChannelName ) ;
00355
00356 for ( list<LogChannel *>::const_iterator it = _channelList.begin();
00357 it != _channelList.end(); it++ )
00358 {
00359
00360 #if CEYLAN_DEBUG
00361
00362 if ( (*it) == 0 )
00363 throw LogException( "LogAggregator::findObjectChannel: "
00364 "null pointer in channel list." ) ;
00365
00366 #endif // CEYLAN_DEBUG
00367
00368 ObjectChannel * objChannel =
00369 dynamic_cast<ObjectChannel *>( (*it) ) ;
00370
00371 if ( objChannel != 0 )
00372 {
00373
00374 CEYLAN_LOG( objChannel->getName() + " is an Object log channel." ) ;
00375
00376 if ( objChannel->getName() == nonPrefixedChannelName )
00377 return objChannel ;
00378 }
00379
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 return 0 ;
00392
00393 }
00394
00395
00396
00397 void LogAggregator::createBasicChannelFrom( LogMessage & message )
00398 {
00399
00400
00401
00402
00403
00404
00405
00406 LogChannel & newChannel = createBasicChannel( message.getChannelName() ) ;
00407 newChannel.addMessage( message ) ;
00408
00409 }
00410
00411
00412
00413 void LogAggregator::createLoggableChannelFrom( LogMessage & message )
00414 {
00415
00416
00417 if ( ! _beSmart )
00418 {
00419 CEYLAN_LOG( "LogAggregator::createLoggableChannelFrom: "
00420 "being not smart, store message unconditionally "
00421 "as if it were basic." ) ;
00422 createBasicChannelFrom( message ) ;
00423 return ;
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433 CEYLAN_LOG( "LogAggregator::createLoggableChannelFrom: "
00434 "smart aggregator will try to find any previously "
00435 "created channel corresponding to this message aimed at "
00436 + message.getChannelName() ) ;
00437
00438
00439
00440
00441
00442
00443 string realChannelName = Loggable::GetEmbeddedChannelName(
00444 message.getChannelName() ) ;
00445
00446 CEYLAN_LOG( "LogAggregator::createLoggableChannelFrom: "
00447 "channel name is " + realChannelName ) ;
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 ObjectIdentifier * identifierFromMessage ;
00463
00464 try
00465 {
00466
00467 identifierFromMessage =
00468 & ObjectIdentifier::generateFromChannelName( realChannelName ) ;
00469
00470 }
00471 catch( const Identifier::IdentifierException & idEx )
00472 {
00473
00474 throw LogException(
00475 "LogAggregator::createLoggableChannelFrom: "
00476 "the channel name of incoming message, "
00477 + realChannelName + " is not an object channel name: "
00478 + idEx.toString() + ": this shoud never happen." ) ;
00479
00480 }
00481
00482 CEYLAN_LOG( "Trying to match '" + realChannelName
00483 + "' with already existing channels." ) ;
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 for ( list<LogChannel *>::const_iterator it = _channelList.begin();
00496 it != _channelList.end(); it++ )
00497 {
00498
00499 #if CEYLAN_DEBUG
00500
00501 if ( (*it) == 0 )
00502 throw LogException(
00503 "LogAggregator::createLoggableChannelFrom: "
00504 "null pointer in channel list." ) ;
00505
00506 #endif // CEYLAN_DEBUG
00507
00508 CEYLAN_LOG( "Trying " + (*it)->getName() ) ;
00509
00510 ObjectChannel * objChannel = dynamic_cast<ObjectChannel *>( (*it) ) ;
00511
00512 if ( objChannel )
00513 {
00514
00515 CEYLAN_LOG( (*it)->getName() + " is an object channel." ) ;
00516
00517
00518
00519
00520
00521
00522
00523 ObjectIdentifier * id = & objChannel->getObjectIdentifier() ;
00524
00525 CEYLAN_LOG( "This object channel identifier is "
00526 + id->toString() ) ;
00527
00528 if ( identifierFromMessage->differentButMatches( * id ) )
00529 {
00530
00531 CEYLAN_LOG( (*it)->getName()
00532 + " matches the new channel, moving its "
00533 "messages to the new one." ) ;
00534
00535
00536
00537
00538
00539
00540
00541 ObjectChannel & newChannel = createObjectChannel( message ) ;
00542 transferChannel( * objChannel, newChannel ) ;
00543
00544
00545
00546
00547
00548
00549 newChannel.addMessage( message ) ;
00550
00551 delete identifierFromMessage ;
00552
00553
00554 return ;
00555 }
00556
00557
00558
00559
00560 CEYLAN_LOG( (*it)->getName() + " does not match." ) ;
00561
00562 }
00563
00564
00565
00566 CEYLAN_LOG( (*it)->getName() + " is not an object channel." ) ;
00567
00568 }
00569
00570
00571
00572 delete identifierFromMessage ;
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 CEYLAN_LOG( realChannelName
00583 + " did not match any other object channel, create it." ) ;
00584
00585 ObjectChannel & newObjectChannel = createObjectChannel( message ) ;
00586
00587 CEYLAN_LOG( "Adding message to newly created object channel." ) ;
00588
00589 newObjectChannel.addMessage( message ) ;
00590
00591 CEYLAN_LOG( "LogAggregator::createLoggableChannelFrom: done." ) ;
00592
00593 }
00594
00595
00596
00597 void LogAggregator::storeBasicMessage( LogMessage & basicLogMessage )
00598 {
00599
00600 CEYLAN_LOG( "LogAggregator::storeBasicMessage: message aimed at "
00601 + basicLogMessage.getChannelName() ) ;
00602
00603
00604
00605 LogChannel * channel = findBasicChannel(
00606 basicLogMessage.getChannelName() ) ;
00607
00608 if ( channel == 0 )
00609 {
00610
00611 CEYLAN_LOG( "LogAggregator::storeBasicMessage: channel "
00612 + basicLogMessage.getChannelName()
00613 + " not found, hence is to be created." ) ;
00614 createBasicChannelFrom( basicLogMessage ) ;
00615
00616 return ;
00617 }
00618
00619 CEYLAN_LOG( "LogAggregator::storeBasicMessage: "
00620 "adding new message to already existing channel "
00621 + channel->getName() ) ;
00622 channel->addMessage( basicLogMessage ) ;
00623
00624 }
00625
00626
00627
00628 void LogAggregator::storeObjectMessage( LogMessage & objectLogMessage )
00629 {
00630
00631
00632
00633
00634 demangle( objectLogMessage ) ;
00635
00636 const string targetChannelName = Loggable::GetEmbeddedChannelName(
00637 objectLogMessage.getChannelName() ) ;
00638
00639 CEYLAN_LOG(
00640 "LogAggregator::storeObjectMessage: message aimed at "
00641 + targetChannelName ) ;
00642
00643 ObjectChannel * channel = findObjectChannel( targetChannelName ) ;
00644
00645 if ( channel == 0 )
00646 {
00647
00648 CEYLAN_LOG( "LogAggregator::storeObjectMessage: object channel '"
00649 + targetChannelName + "' not found." ) ;
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 createLoggableChannelFrom( objectLogMessage ) ;
00662
00663 CEYLAN_LOG( "Message successfully stored in new object channel." ) ;
00664
00665 return ;
00666 }
00667
00668
00669
00670
00671
00672
00673
00674
00675 CEYLAN_LOG( "Object Channel " + targetChannelName + " found." ) ;
00676
00677
00678
00679
00680
00681
00682 objectLogMessage.setChannelName(
00683 Loggable::GetEmbeddedChannelName(
00684 objectLogMessage.getChannelName() ) ) ;
00685
00686 channel->addMessage( objectLogMessage ) ;
00687
00688 }
00689
00690
00691
00692 void LogAggregator::demangle( LogMessage & objectLogMessage )
00693 {
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 string channelName = objectLogMessage.getChannelName() ;
00706
00707
00708
00709 string demangled ;
00710 Ceylan::Uint16 count = 0 ;
00711
00712
00713
00714 Ceylan::Uint16 sepCount = 0 ;
00715
00716 while ( sepCount < 4 )
00717 {
00718
00719 while ( channelName[ count ] != ObjectIdentifier::Separator )
00720 {
00721 demangled += channelName[ count ] ;
00722 count++ ;
00723 }
00724
00725
00726
00727 count++ ;
00728 demangled += ObjectIdentifier::Separator ;
00729
00730 sepCount++ ;
00731 }
00732
00733
00734
00735 string className ;
00736
00737 while ( channelName[ count ] != ObjectIdentifier::Separator )
00738 {
00739 className += channelName[ count ] ;
00740 count++ ;
00741 }
00742
00743
00744
00745
00746 demangled += Ceylan::demangleSymbol( className ) ;
00747
00748 while ( count < channelName.size() )
00749 {
00750 demangled += channelName[ count ] ;
00751 count ++ ;
00752 }
00753
00754 objectLogMessage.setChannelName( demangled ) ;
00755
00756 }
00757
00758
00759
00760 Ceylan::VerbosityLevels LogAggregator::getOverallVerbosityLevel() const
00761 {
00762
00763 LevelOfDetail level ;
00764
00765
00766 if ( _useGlobalLevelOfDetail )
00767 {
00768 level = _globalLevelOfDetail ;
00769 }
00770 else
00771 {
00772 level = DefaultLevelOfDetailForListener ;
00773 }
00774
00775
00776
00777
00778 Ceylan::VerbosityLevels res =
00779 ConvertListenerLevelOfDetailToVerbosityLevel( level ) ;
00780
00781 CEYLAN_LOG( "LogAggregator::getOverallVerbosityLevel: "
00782 "level of detail is: " + Ceylan::toString( res ) ) ;
00783
00784 return res ;
00785
00786 }
00787
00788
00789
00790 Ceylan::VerbosityLevels LogAggregator::getMessageVerbosityLevel(
00791 const LogMessage & message ) const
00792 {
00793
00794 LevelOfDetail level ;
00795
00796
00797
00798 if ( _useGlobalLevelOfDetail )
00799 {
00800 level = _globalLevelOfDetail ;
00801 }
00802 else
00803 {
00804 level = message.getLevelOfDetail() ;
00805 }
00806
00807
00808
00809
00810 Ceylan::VerbosityLevels res =
00811 LogAggregator::ConvertMessageLevelOfDetailToVerbosityLevel(
00812 level ) ;
00813
00814 CEYLAN_LOG( "LogAggregator::getMessageVerbosityLevel: "
00815 "level of detail is: " + Ceylan::toString( res ) ) ;
00816
00817 return res ;
00818
00819 }
00820
00821
00822
00823 Ceylan::VerbosityLevels
00824 LogAggregator::ConvertListenerLevelOfDetailToVerbosityLevel(
00825 LevelOfDetail level )
00826 {
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844 if ( level == MaximumLevelOfDetailForListener )
00845 return Ceylan::low ;
00846 else if ( level < DefaultLevelOfDetailForListener )
00847 return Ceylan::medium ;
00848 else
00849 return Ceylan::high ;
00850
00851 }
00852
00853
00854
00855 Ceylan::VerbosityLevels
00856 LogAggregator::ConvertMessageLevelOfDetailToVerbosityLevel(
00857 LevelOfDetail level )
00858 {
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871 if ( level == MaximumLevelOfDetailForMessage )
00872 return Ceylan::high ;
00873 else if ( level <= DefaultLevelOfDetailForMessage )
00874 return Ceylan::medium ;
00875 else
00876 return Ceylan::low ;
00877
00878 }
00879
00880
00881
00882 const string LogAggregator::toString( Ceylan::VerbosityLevels level ) const
00883 {
00884
00885 return string( "LogAggregator is up and running, is " )
00886 + ( _beSmart ? "" : "not " )
00887 + string( "smart, and currently has " )
00888 + Ceylan::toString(
00889 static_cast<Ceylan::Uint32>( _channelList.size() ) )
00890 + " log channel(s) created" ;
00891
00892 }
00893