00001
00002
00003
00004
00005
00006
00008 #include "MessageService/MsgService.h"
00009
00010 #include <cstdio>
00011 #include <cassert>
00012 #include <iostream>
00013 extern "C" {
00014 #include <unistd.h>
00015 }
00016 #include "MessageService/Msg.h"
00017 #include "MessageService/MsgFormat.h"
00018 #include "MessageService/MsgOStream.h"
00019 #include "MessageService/MsgOStreamService.h"
00020 #include "MessageService/MsgStream.h"
00021 #include "MessageService/MsgCatStream.h"
00022 #include "MessageService/MsgTripWire.h"
00023
00024 using namespace std;
00025
00026 MsgService* MsgService::fInstance = 0;
00027 int MsgService::Init::count = 0;
00028 Msg::LogLevel_t MsgService::fsGlobalLogLevel = Msg::kInfo;
00029
00030
00031
00032 std::ostream& operator<<(std::ostream& os, const MsgService& m)
00033 {
00034
00035
00036
00037
00038
00039
00040
00041
00042 int i;
00043 static const MsgFormat hexfmt("8x");
00044
00045 os << "***** MsgService *******************"
00046 << "************************************\n";
00047 os << " Defaults:\n";
00048 os << " Loglevel: " << (int)m.fDefaultLogLevel << "\n";
00049 for (i = 0; i<Msg::kNLogLevel; ++i) {
00050 os << " OStream : " << m.fDefaultOStream[i]
00051 << " Format : " << hexfmt((int)m.fDefaultFormat[i]) << "\n";
00052 }
00053
00054 os << " Active Streams:\n";
00055 i = 0;
00056 map<std::string,MsgStream*>::const_iterator mend(m.fMsgStreamTable.end());
00057 for (map<std::string,MsgStream*>::const_iterator
00058 itr = m.fMsgStreamTable.begin();
00059 itr != mend;
00060 ++itr) {
00061 os << "<" << itr->first << ">";
00062 if (++i%10 == 0) os << "\n";
00063 }
00064 os << "\n";
00065
00066
00067 os << " Concatenated Streams:\n";
00068 vector<MsgCatStream>::const_iterator vend(m.fMsgCatList.end());
00069 for (vector<MsgCatStream>::const_iterator
00070 itrCatStream(m.fMsgCatList.begin());
00071 itrCatStream != vend;
00072 ++itrCatStream) {
00073 os << " " << (*itrCatStream);
00074 }
00075 os << "************************************"
00076 << "************************************\n";
00077 return os;
00078 }
00079
00080
00081
00082 MsgService::~MsgService()
00083 {
00084
00085
00086
00087
00088
00089
00090
00091 map<std::string,MsgStream*>::iterator mend(fMsgStreamTable.end());
00092 for (map<std::string,MsgStream*>::iterator itr = fMsgStreamTable.begin();
00093 itr != mend;
00094 ++itr) {
00095 itr->second->Close();
00096 delete itr->second;
00097 }
00098
00099
00100 vector<MsgCatStream>::iterator vend(fMsgCatList.end());
00101 for (vector<MsgCatStream>::iterator iter = fMsgCatList.begin();
00102 iter != vend;
00103 ++iter) {
00104 iter->DoConcatenation();
00105 }
00106 }
00107
00108
00109
00110 void MsgService::SetDefaultFormat(int fmt, int level)
00111 {
00112
00113
00114
00115
00116
00117
00118 if ((level>=0) && (level<Msg::kNLogLevel)) {
00119 if((fmt & Msg::kFgColorMask)) fDefaultFormat[level] &=(~Msg::kFgColorMask);
00120 if((fmt & Msg::kBgColorMask)) fDefaultFormat[level] &=(~Msg::kBgColorMask);
00121 fDefaultFormat[level] |= fmt;
00122 }
00123 else {
00124 for (int lvl=0; lvl<Msg::kNLogLevel; ++lvl) {
00125 if((fmt & Msg::kFgColorMask)) fDefaultFormat[lvl] &=(~Msg::kFgColorMask);
00126 if((fmt & Msg::kBgColorMask)) fDefaultFormat[lvl] &=(~Msg::kBgColorMask);
00127 fDefaultFormat[lvl] |= fmt;
00128 }
00129 }
00130
00131 }
00132
00133
00134
00135 MsgService *MsgService::Instance()
00136 {
00137
00138
00139
00140
00141
00142 if (fInstance == 0) {
00143 fInstance = new MsgService();
00144 static int nbirth = 0;
00145 nbirth++;
00146 if (nbirth>1)
00147 cout
00148 << "MsgService::Instance() creating the singleton a 2nd time"
00149 << endl
00150 << "first one must have been destructed prematurely"
00151 << endl;
00152 }
00153
00154
00155 try {if (fInstance->GetkFatalAbort()!=0) throw MSGException();}
00156 catch(MSGException) {
00157 cerr << endl << endl;
00158 cerr << "***************** MSGException *****************" << endl;
00159 cerr << "***** MSGException was thrown for kFatal. ******" << endl;
00160 cerr << endl;
00161 cerr << "A MsgStream MSGException has been thrown. This" << endl;
00162 cerr << "occurs when a kFatal MSG statement is activated." << endl;
00163 cerr << "***************** MSGException *****************" << endl;
00164 cerr << endl;
00165
00166 throw MSGException();
00167 return fInstance;
00168 }
00169
00170
00171 static bool trip_wire_activated = false;
00172 if ( ! trip_wire_activated && MsgTripWire::Instance().IsActive() ) {
00173 trip_wire_activated = true;
00174
00175
00176 Msg::LogLevel_t lvl = MsgTripWire::Instance().GetLogLevel();
00177 fInstance->fDefaultLogLevel = lvl;
00178 map<std::string,MsgStream*>::iterator mend(fInstance->fMsgStreamTable.end());
00179 for (map<std::string,MsgStream*>::iterator itr = fInstance->fMsgStreamTable.begin();
00180 itr != mend;
00181 ++itr) itr->second->SetLogLevel(lvl);
00182 }
00183
00184 return fInstance;
00185 }
00186
00187
00188
00200 #if defined(MACOSX) || defined(IRIX6) || defined(PROBLEM_WITH_COMPILING_THIS)
00201 # include <TSystem.h>
00202 void MsgService::StackTrace(const char* stream, Msg::LogLevel_t lvl, int, int)
00203 {
00204 if(!MsgService::Instance()->IsActive(stream,lvl)) return;
00205 gSystem->StackTrace();
00206 }
00207 #else
00208
00209 # include <stdio.h>
00210 # include <stdlib.h>
00211 # include <execinfo.h>
00212 # include <dlfcn.h>
00213 # include <string.h>
00214 void MsgService::StackTrace(const char* stream, Msg::LogLevel_t lvl, int depth, int ignore)
00215 {
00216 if(!MsgService::Instance()->IsActive(stream,lvl)) return;
00217 MsgStream& s = *((MsgService::Instance())->GetStream(stream));
00218
00219 void *trace[10];
00220 size_t size;
00221
00222 size_t i;
00223 char cmd[512];
00224
00225 size = backtrace (trace, 10);
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 size_t start = 1 + ignore;
00236 size_t end = depth + start;
00237 if(end>size) end=size;
00238
00239 for (i = start; i < end; i++){
00240
00241
00242 unsigned long addr = (unsigned long) trace[i];
00243 Dl_info info;
00244 if(dladdr(trace[i], &info) && info.dli_fname && info.dli_fname[0]) {
00245 const char *libname = info.dli_fname;
00246 const char *symname = (info.dli_sname && info.dli_sname[0])
00247 ? info.dli_sname : "unknown";
00248 unsigned long libaddr = (unsigned long) info.dli_fbase;
00249
00250 unsigned long offset = (addr >= libaddr) ? addr - libaddr :
00251 libaddr - addr;
00252
00253 char linestr[1024];
00254 sprintf(linestr,"addr:0x%lx",addr);
00255
00256 sprintf(cmd,"addr2line -e %s 0x%016lx 2> /dev/null", libname, offset);
00257 if (FILE *pf = ::popen(cmd, "r")) {
00258 if (fgets(linestr, 1024, pf)) {
00259 linestr[strlen(linestr)-1] = 0;
00260 }
00261 ::pclose(pf);
00262 }
00263
00264 char funcname[1024];
00265 strcpy(funcname,symname);
00266 sprintf(cmd,"c++filt %s 2>/dev/null", symname);
00267 if (FILE *pf = ::popen(cmd, "r")) {
00268 if (fgets(funcname, 1024, pf)) {
00269 funcname[strlen(funcname)-1] = 0;
00270 }
00271 ::pclose(pf);
00272 }
00273
00274
00275 int slashes = 0;
00276 for(char* c = linestr+strlen(linestr)-1; c>linestr; c--) {
00277 if( (*c) == '/' ) slashes++;
00278 if(slashes==2) {
00279 char tmp[1024];
00280 strcpy(tmp,c+1);
00281 strcpy(linestr,tmp);
00282 break;
00283 }
00284 }
00285
00286
00287 s << " [" << i-start << "] " << funcname << " @ " << linestr << endl;
00288
00289 }
00290
00291 }
00292 }
00293 #endif
00294
00295
00296
00297 void MsgService::AddCatStream(const char* fileName,
00298 const char* streamName,
00299 Msg::LogLevel_t lvl)
00300 {
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 const char *tmpFileName = GetTmpCatFileName(streamName, lvl);
00312 this->GetStream(streamName)->AttachOStream(lvl, tmpFileName);
00313
00314
00315
00316
00317
00318 MsgCatStream *catStream = 0;
00319 for (vector<MsgCatStream>::iterator iter = fMsgCatList.begin();
00320 iter != fMsgCatList.end();
00321 ++iter) {
00322 if (strcmp((*iter).GetOutputFileName(), fileName)==0) {
00323 catStream = &(*iter);
00324 break;
00325 }
00326 }
00327 if (catStream == 0) {
00328
00329 catStream = new MsgCatStream(fileName);
00330 catStream->AddFileToList(tmpFileName);
00331 fMsgCatList.push_back(*catStream);
00332 delete catStream;
00333 }
00334 else {
00335
00336 catStream->AddFileToList(tmpFileName);
00337 }
00338 }
00339
00340
00341
00342 MsgStream* MsgService::CreateStream(const char *name)
00343 {
00344
00345
00346
00347
00348
00349
00350
00351
00352 std::string msgName(name);
00353 MsgStream *msgStream;
00354
00355
00356 if ((msgStream = fMsgStreamTable[msgName]) != 0) {
00357 return msgStream;
00358 }
00359
00360
00361 msgStream = new MsgStream(name);
00362 assert(msgStream);
00363
00364
00365 msgStream->SetLogLevel(fDefaultLogLevel);
00366 for (Msg::LogLevel_t lvl=0; lvl<Msg::kNLogLevel; ++lvl) {
00367 msgStream->AttachOStream(lvl, fDefaultOStream[lvl]);
00368 msgStream->SetFormat(lvl, fDefaultFormat[lvl]);
00369 }
00370 fMsgStreamTable[msgName] = msgStream;
00371
00372 MsgService::SetGlobalLevel();
00373
00374 return msgStream;
00375 }
00376
00377
00378
00379 MsgService::MsgService() :
00380 fkFatalAbort(0)
00381 {
00382
00383
00384
00385
00386 fDefaultLogLevel = Msg::kInfo;
00387
00388
00389 strcpy(fDefaultOStream[Msg::kVerbose], "cerr");
00390 strcpy(fDefaultOStream[Msg::kDebug], "cerr");
00391 strcpy(fDefaultOStream[Msg::kSynopsis],"cout");
00392 strcpy(fDefaultOStream[Msg::kInfo], "cout");
00393 strcpy(fDefaultOStream[4], "cout");
00394 strcpy(fDefaultOStream[Msg::kWarning], "cerr");
00395 strcpy(fDefaultOStream[Msg::kError], "cerr");
00396 strcpy(fDefaultOStream[Msg::kFatal], "cerr");
00397
00398
00399 fDefaultFormat[Msg::kVerbose] =
00400 Msg::kPriority + Msg::kName +
00401 Msg::kFile + Msg::kLine;
00402 fDefaultFormat[Msg::kDebug] =
00403 Msg::kPriority + Msg::kName +
00404 Msg::kFile + Msg::kLine;
00405 fDefaultFormat[Msg::kSynopsis] = 0;
00406 fDefaultFormat[Msg::kInfo] = 0;
00407 fDefaultFormat[Msg::kWarning] =
00408 Msg::kPriority + Msg::kName +
00409 Msg::kFile + Msg::kCVSId + Msg::kLine;
00410 fDefaultFormat[Msg::kError] =
00411 Msg::kPriority + Msg::kName + Msg::kTime +
00412 Msg::kFile + Msg::kCVSId + Msg::kLine;
00413 fDefaultFormat[Msg::kFatal] =
00414 Msg::kPriority + Msg::kName + Msg::kTime +
00415 Msg::kFile + Msg::kCVSId + Msg::kLine;
00416
00417 fsGlobalLogLevel = fDefaultLogLevel;
00418
00419 fCurrentRun = -1;
00420 fCurrentSnarl = -1;
00421 }
00422
00423
00424
00425 const char *MsgService::GetTmpCatFileName(const char *streamName,
00426 int lvl)
00427 {
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 static char fileName[256];
00438 sprintf(fileName, ".%s.%d.%d", streamName, lvl, getpid());
00439 return fileName;
00440 }
00441
00442
00443
00444 void MsgService::PrintStatistics()
00445 {
00446
00447
00448
00449 this->PrintStatistics(cerr);
00450 }
00451
00452
00453
00454 void MsgService::PrintStatistics(std::ostream &os)
00455 {
00456
00457
00458
00459
00460
00461
00462
00463 list<pair<std::string, MsgStream*> > streamList;
00464 map<std::string, MsgStream*>::iterator mend(fMsgStreamTable.end());
00465 for (map<std::string, MsgStream*>::iterator itr = fMsgStreamTable.begin();
00466 itr != mend;
00467 ++itr) {
00468
00469 streamList.push_back(*itr);
00470 }
00471 streamList.sort();
00472
00473
00474
00475 os << "======================= "
00476 << "Message Service Usage Statistics"
00477 << " =======================\n";
00478 os << " Stream "
00479 << "File "
00480 << "Print Counts\n";
00481 os << " ------ "
00482 << "------------------------ "
00483 << "-----------------------------------------------\n";
00484
00485 list<pair<std::string, MsgStream*> >::iterator lend(streamList.end());
00486 for (list<pair<std::string, MsgStream*> >::iterator itr = streamList.begin();
00487 itr != lend;
00488 ++itr) {
00489 itr->second->PrintStatistics(os);
00490 }
00491
00492 os << "========================"
00493 << "================================"
00494 << "========================\n";
00495 }
00496
00497
00498 void MsgService::SetGlobalLevel()
00499 {
00504 fsGlobalLogLevel = Msg::kFatal;
00505
00506 MsgService* self = MsgService::Instance();
00507 std::map<std::string,MsgStream*>::iterator it = self->fMsgStreamTable.begin();
00508 for(it = self->fMsgStreamTable.begin(); it != self->fMsgStreamTable.end(); it++ ) {
00509 MsgStream* s = it->second;
00510 if(s) {
00511 if(s->GetLogLevel() < fsGlobalLogLevel) fsGlobalLogLevel = s->GetLogLevel();
00512 }
00513 }
00514 }