00001
00002
00003
00004
00005
00006
00007
00008
00009
00011 #include "MessageService/MsgStream.h"
00012 #include <cstdlib>
00013 #include <cstdio>
00014 #include <cstring>
00015 #include <ctime>
00016 #include <vector>
00017 extern "C" {
00018 #include <unistd.h>
00019 }
00020 #include "MessageService/MsgFormat.h"
00021 #include "MessageService/MsgOStream.h"
00022 #include "MessageService/MsgOStreamService.h"
00023 #include "MessageService/MsgService.h"
00024 #include "MessageService/MsgTripWire.h"
00025
00026 using namespace std;
00027
00028
00029
00030
00031 const char kColor_Reset[] = { 0x1B, '[', '0', 'm', 0 };
00032 const char kColor_Bold[] = { 0x1B, '[', '1', 'm', 0 };
00033 const char kColor_Dim[] = { 0x1B, '[', '2', 'm', 0 };
00034 const char kColor_Underline[]= { 0x1B, '[', '3', 'm', 0 };
00035 const char kColor_Blink[] = { 0x1B, '[', '5', 'm', 0 };
00036 const char kColor_Reverse[] = { 0x1B, '[', '7', 'm', 0 };
00037
00038 const char kColor_Black[] = { 0x1B, '[', '3', '0', 'm', 0 };
00039 const char kColor_Red[] = { 0x1B, '[', '3', '1', 'm', 0 };
00040 const char kColor_Green[] = { 0x1B, '[', '3', '2', 'm', 0 };
00041 const char kColor_Yellow[] = { 0x1B, '[', '3', '3', 'm', 0 };
00042 const char kColor_Blue[] = { 0x1B, '[', '3', '4', 'm', 0 };
00043 const char kColor_Magenta[] = { 0x1B, '[', '3', '5', 'm', 0 };
00044 const char kColor_Cyan[] = { 0x1B, '[', '3', '6', 'm', 0 };
00045 const char kColor_White[] = { 0x1B, '[', '3', '7', 'm', 0 };
00046
00047 const char kColor_BgWhite[] = { 0x1B, '[', '4', '0', 'm', 0 };
00048 const char kColor_BgRed[] = { 0x1B, '[', '4', '1', 'm', 0 };
00049 const char kColor_BgGreen[] = { 0x1B, '[', '4', '2', 'm', 0 };
00050 const char kColor_BgYellow[] = { 0x1B, '[', '4', '3', 'm', 0 };
00051 const char kColor_BgBlue[] = { 0x1B, '[', '4', '4', 'm', 0 };
00052 const char kColor_BgMagenta[] = { 0x1B, '[', '4', '5', 'm', 0 };
00053 const char kColor_BgCyan[] = { 0x1B, '[', '4', '6', 'm', 0 };
00054 const char kColor_BgBlack[] = { 0x1B, '[', '4', '7', 'm', 0 };
00055
00056
00057
00058
00059 MsgStream::MsgStream()
00060 :fLogLevel(0)
00061 ,fCurrentLogLevel(0)
00062 {
00063
00064
00065
00066 strcpy(fName, "");
00067 Init();
00068 }
00069
00070
00071
00072 MsgStream::MsgStream(const char* name)
00073 :fLogLevel(0)
00074 ,fCurrentLogLevel(0)
00075 {
00076
00077
00078
00079
00080
00081 if (strlen(name)>kMaxNameSize) {
00082 strncpy(fName, name, kMaxNameSize);
00083 fName[kMaxNameSize] = '\0';
00084
00085
00086
00087 }
00088 else {
00089 strcpy(fName, name);
00090 }
00091 Init();
00092 }
00093
00094
00095
00096
00097 void MsgStream::SetLogLevel(Msg::LogLevel_t lvl)
00098 {
00099
00100
00101
00102
00103
00104 fLogLevel = lvl;
00105 MsgService::SetGlobalLevel();
00106 }
00107
00108
00109
00110 void MsgStream::AttachOStream(Msg::LogLevel_t lvl, const char *name)
00111 {
00112
00113
00114
00115
00116
00117
00118
00119
00120 vector<MsgOStream*>::iterator vend(fMsgOStream[lvl].end());
00121 vector<MsgOStream*>::iterator itrOStream = fMsgOStream[lvl].begin();
00122 for (; itrOStream != vend; ++itrOStream) {
00123 if (strcmp(name, (*itrOStream)->GetName())==0) return;
00124 }
00125
00126
00127 MsgOStreamService* oStreamService = MsgOStreamService::Instance();
00128 MsgOStream* msgOStream = oStreamService->GetStream(name);
00129 fMsgOStream[lvl].push_back(msgOStream);
00130 }
00131
00132
00133 void MsgStream::DetachOStream(Msg::LogLevel_t lvl, const char *name)
00134 {
00135
00136
00137
00138
00139
00140
00141
00142
00143 vector<MsgOStream*>::iterator vend(fMsgOStream[lvl].end());
00144 vector<MsgOStream*>::iterator itrOStream = fMsgOStream[lvl].begin();
00145 for (; itrOStream != vend; ++itrOStream) {
00146 if (strcmp(name, (*itrOStream)->GetName())==0) break;
00147 }
00148 if (itrOStream != vend) {
00149 (*itrOStream)->SubtractReference();
00150 fMsgOStream[lvl].erase(itrOStream);
00151 }
00152 }
00153
00154
00155
00156 void MsgStream::AddFormat(Msg::LogLevel_t lvl, int fmt)
00157 {
00158 if((fmt & Msg::kFgColorMask)) fFormat[lvl] &=(~Msg::kFgColorMask);
00159 if((fmt & Msg::kBgColorMask)) fFormat[lvl] &=(~Msg::kBgColorMask);
00160 fFormat[lvl] |= fmt;
00161 }
00162
00163
00164
00165 void MsgStream::Close()
00166 {
00167
00168
00169
00170
00171 for (int i=fLogLevel; i<Msg::kNLogLevel; ++i) {
00172 vector<MsgOStream*>::iterator vend(fMsgOStream[i].end());
00173 for (vector<MsgOStream*>::iterator itrOStreamPtr = fMsgOStream[i].begin();
00174 itrOStreamPtr != vend;
00175 ++itrOStreamPtr) {
00176 (*itrOStreamPtr)->Close();
00177 }
00178 }
00179 }
00180
00181
00182
00183 void MsgStream::Flush()
00184 {
00185
00186
00187
00188 for (int i=fLogLevel; i<Msg::kNLogLevel; ++i) {
00189 vector<MsgOStream*>::iterator vend(fMsgOStream[i].end());
00190 for (vector<MsgOStream*>::iterator itrOStreamPtr = fMsgOStream[i].begin();
00191 itrOStreamPtr != vend;
00192 ++itrOStreamPtr) {
00193 (*itrOStreamPtr)->Flush();
00194 }
00195 }
00196 }
00197
00198
00199
00200 MsgStream& MsgStream::operator()(Msg::LogLevel_t priority,
00201 const char* file,
00202 const char* cvsid,
00203 int line)
00204 {
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 fCurrentLogLevel = priority;
00218
00219
00220 MsgTripWire& tw(MsgTripWire::Instance());
00221 tw.StartCall();
00222
00223
00224 if ( tw.SuppressMessage() ) fCurrentLogLevel = Msg::kMinLogLevel -1;
00225
00226
00227
00228 if (fCurrentLogLevel>=fLogLevel ) {
00229 int fmt = fFormat[fCurrentLogLevel];
00230
00231
00232 if ( tw.IsActive() ) {
00233 fmt = Msg::kFile | Msg::kLine;
00234 (*this) << tw.GetMessagePrefix();
00235 }
00236
00237
00238
00239 int len = strlen(file);
00240 file += len;
00241 for (;len>0 && *(file-1)!='/'; --len) { --file; }
00242
00243
00244 this->LogPrint(fCurrentLogLevel,file);
00245
00246
00247 if (fmt) {
00248
00249 static bool sSomeoneUsedColor = false;
00250 if(sSomeoneUsedColor) {
00251 (*this) << kColor_Reset;
00252 }
00253
00254 if ((fmt & Msg::kFontMask )) {
00255 sSomeoneUsedColor = true;
00256 if((fmt & Msg::kBold )) (*this) << kColor_Bold;
00257 if((fmt & Msg::kDim )) (*this) << kColor_Dim;
00258 if((fmt & Msg::kUnderline )) (*this) << kColor_Underline;
00259 if((fmt & Msg::kBlink )) (*this) << kColor_Blink;
00260 if((fmt & Msg::kReverse )) (*this) << kColor_Reverse;
00261
00262 int color = fmt & Msg::kFgColorMask;
00263 switch(color) {
00264 case Msg::kBlack: (*this) << kColor_Black; break;
00265 case Msg::kRed: (*this) << kColor_Red; break;
00266 case Msg::kGreen: (*this) << kColor_Green; break;
00267 case Msg::kYellow: (*this) << kColor_Yellow; break;
00268 case Msg::kBlue: (*this) << kColor_Blue; break;
00269 case Msg::kMagenta:(*this) << kColor_Magenta; break;
00270 case Msg::kCyan: (*this) << kColor_Cyan; break;
00271 case Msg::kWhite: (*this) << kColor_White; break;
00272 default: break;
00273 }
00274
00275 color = fmt & Msg::kBgColorMask;
00276 switch(color) {
00277 case Msg::kBgBlack: (*this) << kColor_BgBlack; break;
00278 case Msg::kBgRed: (*this) << kColor_BgRed; break;
00279 case Msg::kBgGreen: (*this) << kColor_BgGreen; break;
00280 case Msg::kBgYellow: (*this) << kColor_BgYellow; break;
00281 case Msg::kBgBlue: (*this) << kColor_BgBlue; break;
00282 case Msg::kBgMagenta:(*this) << kColor_BgMagenta; break;
00283 case Msg::kBgCyan: (*this) << kColor_BgCyan; break;
00284 case Msg::kBgWhite: (*this) << kColor_BgWhite; break;
00285 default: break;
00286 }
00287 }
00288
00289 if ((fmt & Msg::kPriority)) {
00290 switch(fCurrentLogLevel) {
00291 case Msg::kVerbose: (*this) << "=V="; break;
00292 case Msg::kDebug: (*this) << "=D="; break;
00293 case Msg::kSynopsis:(*this) << "=S="; break;
00294 case Msg::kInfo: (*this) << "=I="; break;
00295 case Msg::kWarning: (*this) << "=W="; break;
00296 case Msg::kError: (*this) << "=E="; break;
00297 case Msg::kFatal: (*this) << "=F="; break;
00298 default : abort();
00299 }
00300 }
00301 if ((fmt & Msg::kName)) (*this) << " " << fName;
00302 if ((fmt & Msg::kHost)) {
00303 static const int len = 256;
00304 char host[len];
00305 int err = gethostname(host,len);
00306 if (err==0) (*this) << " " << host;
00307 else (*this) << " /host?/";
00308 if ((fmt & Msg::kPID)) {
00309 (*this) << ":" << getpid();
00310 }
00311 }
00312 else {
00313 if ((fmt & Msg::kPID)) {
00314 (*this) << " pid=" << getpid();
00315 }
00316 }
00317 if ((fmt & Msg::kTime)) {
00318 this->SetCurrentDateString();
00319 (*this) << " " << fCurrentDate;
00320 }
00321 if ((fmt && Msg::kRunSnarl )) {
00322 int run, snarl;
00323 MsgService::Instance()->GetCurrentRunSnarl(run,snarl);
00324 (*this) << " [" << run << "|" << snarl << "]";
00325 }
00326 if ((fmt & Msg::kCVSId)) {
00327 if (strlen(cvsid)<8) {
00328
00329
00330 (*this) << " " << file;
00331 }
00332 else {
00333
00334 this->SetCVSVersion(cvsid);
00335 (*this) << " " << fCVSVersion;
00336 }
00337 }
00338 else {
00339
00340 if ((fmt & Msg::kFile)) (*this) << " " << file;
00341 }
00342
00343 if ((fmt & Msg::kLine)) (*this) << ":" << line;
00344 (*this) << "> ";
00345
00346 if ((fmt & Msg::kStackTrace)) {
00347 (*this) << "Stack Trace: " << endl;
00348 MsgService::StackTrace(fName,fCurrentLogLevel,4,1);
00349 (*this) << "... Message: ";
00350 }
00351
00352 if ((fmt & Msg::kFontMask )) {
00353 if((fmt & Msg::kColorAll)) {
00354
00355 } else {
00356 (*this) << kColor_Reset;
00357 }
00358 }
00359
00360 }
00361 }
00362 if (fCurrentLogLevel == Msg::kFatal) {
00363 MsgService::Instance()->SetkFatalAbort();
00364 cerr << endl << endl;
00365 cerr << "***************** MSGException *****************" << endl;
00366 cerr << "**** MSGException will be thrown for kFatal. ***" << endl;
00367 cerr << endl;
00368 cerr << "A MsgService::MSGException will been thrown at" << endl;
00369 cerr << "the next entry to MsgService. This is triggered" << endl;
00370 cerr << "when a kFatal MSG statement is activated." << endl;
00371 cerr << endl;
00372 cerr << "To investigate the cause without aborting the" << endl;
00373 cerr << "job, replace the following statement on line " << line;
00374 cerr << endl << "of file " << file << ":" << endl;
00375 cerr << endl;
00376 cerr << "MSG(" << fName << ", Msg::kFatal) << [...] << endl;"<< endl;
00377 cerr << endl;
00378 cerr << "with:" << endl;
00379 cerr << endl;
00380 cerr << "MsgService::Instance()->SetkFatalAbort(0);" << endl;
00381 cerr << "MSG(" << fName << ", Msg::kError) << [...] << endl;"<< endl;
00382 cerr << "// [Add diagnostic code here.]" << endl;
00383 cerr << "***************** MSGException *****************" << endl;
00384 cerr << endl;
00385
00386 return *this;
00387 }
00388
00389 return *this;
00390 }
00391
00392
00393
00394 ostream& operator<<(ostream& os, const MsgStream& s)
00395 {
00396
00397
00398
00399
00400
00401 os << "*** MsgStream::" << s.fName
00402 << " LogLevel = " << (int)s.fLogLevel << "\n";
00403 for (int i=0; i<Msg::kNLogLevel; ++i) {
00404 os << "(" << i << ") ";
00405 if (s.fFormat[i]&Msg::kPriority) os << "x"; else os << "-";
00406 if (s.fFormat[i]&Msg::kName) os << "x"; else os << "-";
00407 if (s.fFormat[i]&Msg::kTime) os << "x"; else os << "-";
00408 if (s.fFormat[i]&Msg::kFile) os << "x"; else os << "-";
00409 if (s.fFormat[i]&Msg::kCVSId) os << "x"; else os << "-";
00410 if (s.fFormat[i]&Msg::kLine) os << "x"; else os << "-";
00411 if (s.fFormat[i]&Msg::kHost) os << "x"; else os << "-";
00412 if (s.fFormat[i]&Msg::kPID) os << "x"; else os << "-";
00413 vector<MsgOStream*>::const_iterator iter(s.fMsgOStream[i].begin());
00414 vector<MsgOStream*>::const_iterator iterEnd(s.fMsgOStream[i].end());
00415 for (; iter != iterEnd; ++iter) {
00416 os << " " << (*iter)->GetName();
00417 }
00418 os << "\n";
00419 }
00420 os << "***\n";
00421 return os;
00422 }
00423
00424
00425
00426 void MsgStream::Init()
00427 {
00428
00429
00430
00431 fLogLevel = Msg::kInfo;
00432 for (int i=0; i<Msg::kNLogLevel; ++i) {
00433 fFormat[i] = 0;
00434 }
00435 fCurrentLogLevel = fLogLevel;
00436 }
00437
00438
00439
00440 void MsgStream:: LogPrint(Msg::LogLevel_t priority, const char* file)
00441 {
00442
00443
00444
00445
00446
00447 int len = strlen(file);
00448 file += len;
00449 for (;len>0 && *(file-1)!='/'; --len) { --file; }
00450
00451 fFileStat[string(file)].LogPrint(priority);
00452 }
00453
00454
00455
00456 void MsgStream::SetCurrentDateString()
00457 {
00458
00459
00460
00461 time_t tt;
00462 struct tm *tp;
00463 tt = time(NULL);
00464 tp = localtime(&tt);
00465 sprintf(fCurrentDate, "%.4d/%.2d/%.2d %.2d:%.2d:%.2d",
00466 tp->tm_year+1900,
00467 tp->tm_mon+1,
00468 tp->tm_mday,
00469 tp->tm_hour,
00470 tp->tm_min,
00471 tp->tm_sec);
00472 }
00473
00474
00475
00476 void MsgStream::SetCVSVersion(const char* CVSId)
00477 {
00478
00479
00480
00481
00482
00483 int nsegment = 0;
00484 register int j = 0;
00485 for (unsigned int i=1; (i<strlen(CVSId)) && (i<127); ++i) {
00486 if (CVSId[i] != ' ' && CVSId[i-1] == ' ') {
00487 if (++nsegment == 3) break;
00488 }
00489 if (CVSId[i]!=' ' && nsegment>0) {
00490 fCVSVersion[j++] = CVSId[i];
00491 }
00492 }
00493 fCVSVersion[j] = '\0';
00494 }
00495
00496
00497
00498 void MsgStream::StatPrint(ostream& os, const char* label, int n) const
00499 {
00500
00501
00502
00503 if (n>0) {
00504 MsgFormat ifmt("%-5i");
00505 os << label << ifmt(n);
00506 }
00507 else {
00508
00509 os << " ";
00510 }
00511 }
00512
00513
00514
00515 void MsgStream::PrintStatistics(ostream& os)
00516 {
00517
00518
00519
00520
00521 map<string,MsgStatistic>::iterator mend(fFileStat.end());
00522 for (map<string,MsgStatistic>::iterator itrFileStat = fFileStat.begin();
00523 itrFileStat != mend;
00524 ++itrFileStat) {
00525
00526
00527 if (itrFileStat->second.GetPrintCount(Msg::kFatal) +
00528 itrFileStat->second.GetPrintCount(Msg::kError)>0) {
00529 os << "*";
00530 }
00531 else os << " ";
00532
00533
00534 os << fName;
00535 for (int i=strlen(fName); i<7; ++i) os << " ";
00536
00537
00538 os << itrFileStat->first;
00539 for (int i=strlen((*itrFileStat).first.c_str()); i<24; ++i) os << " ";
00540
00541
00542 this->StatPrint(os, " F=",
00543 itrFileStat->second.GetPrintCount(Msg::kFatal));
00544 this->StatPrint(os, " E=",
00545 itrFileStat->second.GetPrintCount(Msg::kError));
00546 this->StatPrint(os, " W=",
00547 itrFileStat->second.GetPrintCount(Msg::kWarning));
00548 this->StatPrint(os, " I=",
00549 itrFileStat->second.GetPrintCount(Msg::kInfo));
00550 this->StatPrint(os, " S=",
00551 itrFileStat->second.GetPrintCount(Msg::kSynopsis));
00552 this->StatPrint(os, " D=",
00553 itrFileStat->second.GetPrintCount(Msg::kDebug));
00554 this->StatPrint(os, " V=",
00555 itrFileStat->second.GetPrintCount(Msg::kVerbose));
00556 os << endl;
00557 }
00558 }