00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <list>
00016 #include <ctime>
00017 #include <string>
00018 #include <iomanip>
00019 #include <vector>
00020
00021 #include "mbilog.h"
00022
00023 #ifdef _WIN32
00024 #define USE_WIN32COLOREDCONSOLE
00025 #include <windows.h>
00026 #endif
00027
00028 static std::list<mbilog::AbstractBackend*> backends;
00029 static bool g_init=false;
00030
00031 namespace mbilog {
00032 static const std::string NA_STRING = "n/a";
00033 }
00034
00035 void mbilog::RegisterBackend(mbilog::AbstractBackend* backend)
00036 {
00037 backends.push_back(backend);
00038 }
00039
00040 void mbilog::UnregisterBackend(mbilog::AbstractBackend* backend)
00041 {
00042 backends.remove(backend);
00043 }
00044
00045 void mbilog::DistributeToBackends(mbilog::LogMessage &l)
00046 {
00047
00048
00049 {
00050 std::string::size_type i = l.message.find_last_not_of(" \t\f\v\n\r");
00051 l.message = (i != std::string::npos) ? l.message.substr(0, i+1) : "";
00052 }
00053
00054 if(backends.empty())
00055 {
00056 mbilog::BackendCout::FormatSmart(l);
00057 return;
00058 }
00059
00060 std::list<mbilog::AbstractBackend*>::iterator i;
00061
00062 for(i = backends.begin(); i != backends.end(); i++)
00063 (*i)->ProcessMessage(l);
00064 }
00065
00066 mbilog::BackendCout::BackendCout()
00067 {
00068 useFullOutput=false;
00069 }
00070
00071 mbilog::BackendCout::~BackendCout()
00072 {
00073 }
00074
00075 void mbilog::BackendCout::SetFull(bool full)
00076 {
00077 useFullOutput = full;
00078 }
00079
00080 void mbilog::BackendCout::ProcessMessage(const mbilog::LogMessage& l)
00081 {
00082 if(useFullOutput)
00083 FormatFull(l);
00084 else
00085 FormatSmart(l);
00086 }
00087
00088 void mbilog::BackendCout::AppendTimeStamp(std::ostream& out)
00089 {
00090 time_t rawtime = time(NULL);
00091 std::string timestring( ctime(&rawtime) );
00092 timestring.replace( timestring.length() -1, 1," ");
00093 out << timestring;
00094 }
00095
00096 void mbilog::BackendCout::FormatSmart(std::ostream &out, const LogMessage &l,int )
00097 {
00098 char c_open='[';
00099 char c_close=']';
00100
00101 switch(l.level)
00102 {
00103 case mbilog::Info:
00104 break;
00105
00106 case mbilog::Warn:
00107 c_open='!';
00108 c_close='!';
00109 break;
00110
00111 case mbilog::Error:
00112 c_open='#';
00113 c_close='#';
00114 break;
00115
00116 case mbilog::Fatal:
00117 c_open='*';
00118 c_close='*';
00119 break;
00120
00121 case mbilog::Debug:
00122 c_open='{';
00123 c_close='}';
00124 break;
00125 }
00126
00127 out << c_open;
00128
00129 if (!g_init)
00130 {
00131 g_init = true;
00132 AppendTimeStamp(out);
00133 out << std::endl;
00134 }
00135
00136 out << std::fixed << std::setprecision(3) << ((double)std::clock())/CLOCKS_PER_SEC;
00137
00138 out << c_close << " ";
00139
00140 if(!l.category.empty())
00141 {
00142 out << "[" << l.category << "] ";
00143 }
00144
00145 switch(l.level)
00146 {
00147 case mbilog::Info:
00148 break;
00149
00150 case mbilog::Warn:
00151 out << "WARNING: ";
00152 break;
00153
00154 case mbilog::Error:
00155 out << "ERROR: ";
00156 break;
00157
00158 case mbilog::Fatal:
00159 out << "FATAL: ";
00160 break;
00161
00162 case mbilog::Debug:
00163 out << "DEBUG: ";
00164 break;
00165 }
00166
00167 out << l.message << std::endl;
00168 }
00169
00170 void mbilog::BackendCout::FormatFull(std::ostream &out,const LogMessage &l,int threadID)
00171 {
00172 switch(l.level)
00173 {
00174 case mbilog::Info:
00175 out << "INFO";
00176 break;
00177
00178 case mbilog::Warn:
00179 out << "WARN";
00180 break;
00181
00182 case mbilog::Error:
00183 out << "ERROR";
00184 break;
00185
00186 case mbilog::Fatal:
00187 out << "FATAL";
00188 break;
00189
00190 case mbilog::Debug:
00191 out << "DEBUG";
00192 break;
00193 }
00194
00195 time_t rawtime;
00196 time ( &rawtime );
00197 out << "|" << ctime(&rawtime);
00198
00199 out << "|" << std::string(l.filePath) << "(" << l.lineNumber << ")";
00200
00201 out << "|" << std::string(l.functionName);
00202
00203
00204 {
00205 out << "|" << std::hex << threadID;
00206 }
00207
00208
00209 {
00210 out << "|" << std::string(l.moduleName);
00211 }
00212
00213
00214 {
00215 out << "|" << l.category;
00216 }
00217
00218 out << l.message << std::endl;
00219 }
00220
00221 #ifdef USE_WIN32COLOREDCONSOLE
00222
00223 static HANDLE g_hConsole;
00224
00225 class AutoCategorize
00226 {
00227 protected:
00228
00229 std::vector<std::string> path;
00230
00231 std::string current,category;
00232
00233 int pos;
00234
00235 void flush()
00236 {
00237 if(current.size()>0)
00238 {
00239 if(current.compare("..")==0)
00240 {
00241 if(path.size()>0)
00242 path.pop_back();
00243 }
00244 else
00245 {
00246 path.push_back(current);
00247 }
00248 current="";
00249 }
00250 }
00251
00252 std::string simplify(std::string x)
00253 {
00254 static char *replace[] =
00255 {
00256 ".cpp", "",
00257 ".cxx", "",
00258 ".txx", "",
00259 ".h", "",
00260 ".hpp", "",
00261 ".hxx", "",
00262 ".c", "",
00263
00264 "org.blueberry.", "",
00265 "org.mitk.gui.qt.", "",
00266 "org.mitk.", "",
00267
00268 "qmitk", "",
00269 "mitk", "",
00270 "berry", "",
00271 "itk", "",
00272 "vtk", "",
00273 "qt", "",
00274
00275 "object", "obj",
00276 "factory", "fac",
00277 "classes", "cls",
00278 "plugin", "plg",
00279 "widget", "wdgt",
00280 "interface", "itf",
00281 "service", "svc",
00282 "register", "reg",
00283 "perspective", "prs",
00284
00285 "assessor", "ase",
00286
00287 "atrophy", "atr",
00288
00289 "bias", "bias",
00290
00291 "field", "fld",
00292
00293 "multi", "mlt",
00294
00295 "contour", "cntr",
00296 "tools", "tls",
00297 "tool", "tl",
00298
00299 "application", "app",
00300 "calculate", "calc",
00301 "subtract", "sub",
00302 "region", "reg",
00303 "tumor", "tum",
00304 "growing", "grow",
00305 "segmentation", "seg",
00306 "statistics", "stat",
00307
00308 "imaging", "img",
00309 "image", "img",
00310
00311 "diffusion", "dif",
00312 "registration", "reg",
00313 "navigation", "nav",
00314
00315 "generation", "gen",
00316 "generator", "gen",
00317
00318 "vector", "vec",
00319 "gradient", "grad",
00320 "flow", "flow",
00321
00322 "paint", "pnt",
00323 "brush", "brsh",
00324 "volumetry", "vol",
00325 "volume", "vol",
00326 "mapper", "map",
00327 "filter", "flt",
00328 "surface", "sfc",
00329 "point", "pnt",
00330 "organ", "org",
00331 "multiple", "mlt",
00332
00333 "corrector", "cor",
00334 "correction", "cor",
00335
00336 "batch", "bat",
00337
00338 "window", "wnd",
00339
00340 "advisor", "adv",
00341
00342 "editor", "edt",
00343
00344 "material", "mat",
00345
00346 "visualization", "vis",
00347
00348 "measurement", "mes",
00349
00350 "scene", "scn",
00351
00352 "serialization", "ser",
00353 "deserializer", "dser",
00354 "serializer", "ser",
00355
00356 "sandbox", "sb",
00357 "texture", "tex",
00358 "opengl", "ogl",
00359 "vessel", "vsl",
00360 "value", "val",
00361 "analysis", "ana",
00362
00363 "patient", "pat",
00364 "body", "body",
00365 "diagnosis", "diag",
00366 "mesh", "mesh",
00367 "radial", "rad",
00368 "simple", "smp",
00369 "algorithms", "alg",
00370 "controllers", "con",
00371 "control", "con",
00372 "interactive", "ia",
00373 "interactions", "ia",
00374
00375 "processing", "pro",
00376 "process", "pro",
00377
00378 "rendering", "rnd",
00379 "renderer", "rnd",
00380 "render", "rnd",
00381
00382 "datamanagement", "data",
00383 "management", "mng",
00384 "manager", "mng",
00385 "data", "data",
00386
00387 "anatomy", "ana",
00388 "neuro", "neo",
00389 "automatic", "auto",
00390
00391 "optimizer", "opt",
00392 "optimize", "opt",
00393
00394 "binary", "bin",
00395 "liver", "liv",
00396 "lymph", "lym",
00397 "node", "node",
00398 "tree", "tree",
00399 "homogeneous", "hmgn",
00400 "threshold", "tsh",
00401
00402
00403 "based", "bsd",
00404 "shape", "shp",
00405
00406 "model", "mdl",
00407 "extension", "ext",
00408 "activator", "act",
00409
00410 "dicom", "dicom",
00411
00412 "browser", "brwr",
00413
00414 "viewer", "view",
00415 "view", "view",
00416
00417 "finder", "fnd",
00418
00419 "indexer", "idx",
00420 "index", "idx",
00421
00422 "rapid", "rpd",
00423
00424 "gui", "gui",
00425
00426 "slices", "slc",
00427 "slice", "slc",
00428
00429 "about", "abt",
00430
00431 "interpolator", "inp",
00432
00433 "switcher", "swh",
00434
00435 "planning", "plan",
00436 "planner", "plan",
00437 "plane", "pln",
00438 "plan", "plan",
00439
00440 "workbench", "wrkbnc",
00441 "common", "com",
00442 "resection", "rsc",
00443 "translation", "trnsl",
00444 "rotation", "rot",
00445 "deformation", "dfrm",
00446 "shader", "shd",
00447 "repository", "rep",
00448 "initializer", "init",
00449 "dialog", "dlg",
00450 "download", "down",
00451 "upload", "up",
00452 "core", "core",
00453 "manual", "man",
00454 "leaf", "leaf",
00455 "internal", "int",
00456 "external", "ext",
00457 "platform", "pltfm",
00458 "method", "mthd",
00459 "pyramidal", "prmdl",
00460 "tracking", "trck",
00461 "track", "trck",
00462
00463 "bspline", "bspl",
00464 "spline", "spl",
00465
00466 "create", "crt",
00467 "erase", "ers",
00468
00469 "auto", "auto",
00470 "crop", "crop",
00471 "file", "file",
00472 "io", "io",
00473
00474 "2d", "2d",
00475 "3d", "3d",
00476 ".", "."
00477
00478 };
00479
00480 bool redo;
00481
00482 std::string lft(""),rgt("");
00483
00484 do
00485 {
00486 redo=false;
00487
00488 for(int r=0; r < sizeof(replace)/sizeof(char*); r+=2)
00489 {
00490 int s = static_cast<int>( strlen(replace[r]) );
00491 int xs = static_cast<int>( x.size() );
00492
00493 if(xs==s)
00494 {
00495 if( replace[r+1][0] || !lft.empty() || !rgt.empty() )
00496 if(x.compare(replace[r])==0)
00497 x=replace[r+1];
00498 }
00499 else if(xs>s)
00500 {
00501 if(strncmp(replace[r],&x.c_str()[xs-s],s)==0)
00502 {
00503 std::string rp = replace[r+1];
00504 if(!rp.empty()) rp[0]=toupper(rp[0]);
00505 x = x.substr(0,xs-s);
00506 rgt = rp + rgt;
00507 redo=true;
00508 }
00509 else if(strncmp(replace[r],x.c_str(),s)==0)
00510 {
00511 std::string rp = replace[r+1];
00512 if(!rp.empty()) rp[0]=toupper(rp[0]);
00513 x=x.substr(s,xs-s);
00514 lft = lft + rp;
00515 redo=true;
00516 }
00517 }
00518 }
00519 }
00520 while(redo);
00521
00522 x[0]=toupper(x[0]);
00523
00524 x=lft+x+rgt;
00525
00526 x[0]=tolower(x[0]);
00527
00528 return x;
00529 }
00530
00531 std::string concat(std::string a,std::string b,bool opt)
00532 {
00533 int as = static_cast<int>( a.size() );
00534 int bs = static_cast<int>( b.size() );
00535 if(opt && as <= bs)
00536 {
00537 if (as==bs && a.compare(b)==0)
00538 return a;
00539
00540 if(strncmp(a.c_str(),b.c_str(),as)==0)
00541 {
00542 b=b.substr(as,bs-as);
00543 b[0]=tolower(b[0]);
00544 }
00545 }
00546
00547 return a+"."+b;
00548 }
00549
00550 bool search2p2(char *a,char *b,bool optimize=true)
00551 {
00552 int size = static_cast<int>( path.size() ) - 3;
00553 for(int r=0;r<size;r++)
00554 if(path[r].compare(a)==0 && path[r+1].compare(b)==0)
00555 {
00556 pos = r+2;
00557 category = concat(simplify(path[pos]),simplify(path[path.size()-1]),optimize);
00558 return true;
00559 }
00560 return false;
00561 }
00562
00563 bool search2p1(char *a,char *b)
00564 {
00565 int size = static_cast<int>( path.size() ) - 2;
00566 for(int r=0;r<size;r++)
00567 if(path[r].compare(a)==0 && path[r+1].compare(b)==0)
00568 {
00569 pos = r+2;
00570 category = simplify(path[path.size()-1]);
00571 return true;
00572 }
00573 return false;
00574 }
00575
00576 bool search1p2(char *a,bool optimize=true)
00577 {
00578 int size = static_cast<int>( path.size() ) - 2;
00579 for(int r=0;r<size;r++)
00580 if(path[r].compare(a)==0)
00581 {
00582 pos = r+1;
00583 category = concat(simplify(path[pos]),simplify(path[path.size()-1]),optimize);
00584 return true;
00585 }
00586 return false;
00587 }
00588
00589 public:
00590
00591 AutoCategorize( const mbilog::LogMessage &l )
00592 {
00593 int size = static_cast<int>( strlen(l.filePath) );
00594
00595 current = "";
00596
00597 for(int r = 0;r<size;r++)
00598 {
00599 char c=l.filePath[r];
00600 if(c=='\\' || c=='/')
00601 flush();
00602 else
00603 current+=tolower(c);
00604 }
00605
00606 flush();
00607 }
00608
00609 std::string GetPrefix()
00610 {
00611 category="";
00612 if(search2p2("mbi-sb","core",false)) return "sb.";
00613 if(search2p1("mbi-sb","q4mitk")) return "sb.ui.";
00614 if(search2p2("mbi","applications")) return "sb.app.";
00615 if(search2p2("mbi-sb","q4applications")) return "sb.app.";
00616 if(search2p2("mbi-sb","utilities")) return "sb.util.";
00617 if(search2p2("mbi-sb","bundles")) return "sb.bun.";
00618 if(search2p2("mbi-sb","bundlesqt")) return "sb.bun.";
00619 if(search2p2("mbi","modules")) return "sb.mod.";
00620
00621 if(search2p2("mbi-qm","core",false)) return "qm.";
00622 if(search2p2("mbi-qm","utilities")) return "qm.util.";
00623
00624 if(search2p2("modules","mitkext",false)) return "ext.";
00625 if(search2p1("modules","qmitkext")) return "ext.ui.";
00626 if(search2p2("modules","bundles")) return "ext.bun.";
00627
00628 if(search2p2("blueberry","bundles")) return "blueberry.";
00629
00630 if(search2p2("core","code",false)) return "core.";
00631 if(search2p1("coreui","qmitk")) return "core.ui.";
00632 if(search2p2("coreui","bundles")) return "core.bun.";
00633
00634
00635 if(search1p2("modules")) return "core.mod.";
00636 if(search1p2("utilities")) return "core.util.";
00637 if(search1p2("applications")) return "core.app.";
00638
00639 return "";
00640 }
00641
00642 std::string GetCategory()
00643 {
00644 return category;
00645 }
00646
00647 };
00648
00649
00650 void mbilog::BackendCout::FormatSmartWindows(const mbilog::LogMessage &l,int )
00651 {
00652 int colorNormal = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE;
00653
00654 int lastColor = colorNormal;
00655 #define ChangeColor( _col ) { int col=(_col); if(lastColor != (col)) { SetConsoleTextAttribute(g_hConsole, (col) ); lastColor=(col); } }
00656
00657 int colorTime = FOREGROUND_GREEN;
00658 int colorText = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE;
00659 int colorCat = FOREGROUND_BLUE | FOREGROUND_RED;
00660 bool showColon = true;
00661 bool forceCat = false;
00662
00663 if(!g_init)
00664 {
00665 g_hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
00666 g_init=true;
00667
00668 std::string title = "mbilog";
00669
00670 SetConsoleTitle( title.c_str() );
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684 ChangeColor( colorTime );
00685 AppendTimeStamp(std::cout);
00686 std::cout << std::endl;
00687 }
00688
00689 switch(l.level)
00690 {
00691 case mbilog::Info:
00692 break;
00693
00694 case mbilog::Warn:
00695 colorTime = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY;
00696 colorText = FOREGROUND_RED|FOREGROUND_GREEN;
00697 colorCat = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
00698 showColon = false;
00699 forceCat = true;
00700 break;
00701
00702 case mbilog::Error:
00703 colorTime = FOREGROUND_RED|FOREGROUND_INTENSITY;
00704 colorText = FOREGROUND_RED;
00705 colorCat = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
00706 showColon = false;
00707 forceCat = true;
00708 break;
00709
00710 case mbilog::Fatal:
00711 colorTime = FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_INTENSITY;
00712 colorText = FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_INTENSITY;
00713 colorCat = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
00714 showColon = false;
00715 forceCat = true;
00716 break;
00717
00718 case mbilog::Debug:
00719 colorTime = FOREGROUND_BLUE|FOREGROUND_INTENSITY;
00720 colorText |= FOREGROUND_INTENSITY;
00721 showColon = false;
00722 break;
00723 }
00724
00725 ChangeColor( colorTime );
00726 std::cout << std::fixed << std::setprecision(2) << ((double)std::clock())/CLOCKS_PER_SEC << " ";
00727
00728
00729 {
00730 AutoCategorize ac(l);
00731 std::string pre=ac.GetPrefix();
00732 std::string cat=ac.GetCategory();
00733
00734 cat = pre + cat;
00735
00736 if(cat.empty())
00737 cat = l.category;
00738
00739 if(!cat.empty())
00740 {
00741 ChangeColor( colorCat );
00742
00743
00744 {
00745 std::cout << cat << std::flush;
00746
00747 }
00748
00749
00750
00751 if(showColon)
00752 {
00753 ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY );
00754 std::cout << ": " << std::flush;
00755 }
00756 else
00757 std::cout << " ";
00758 }
00759 }
00760
00761 switch(l.level)
00762 {
00763 case mbilog::Info:
00764 break;
00765
00766 case mbilog::Warn:
00767 ChangeColor( colorTime );
00768 std::cout << "WARNING" << std::flush;
00769 ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY );
00770 std::cout << ": " << std::flush;
00771 break;
00772
00773 case mbilog::Error:
00774 ChangeColor( colorTime );
00775 std::cout << "ERROR" << std::flush;
00776 ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY );
00777 std::cout << ": " << std::flush;
00778 break;
00779
00780 case mbilog::Fatal:
00781 ChangeColor( colorTime );
00782 std::cout << "FATAL" << std::flush;
00783 ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY );
00784 std::cout << ": " << std::flush;
00785 break;
00786
00787 case mbilog::Debug:
00788 ChangeColor( colorTime );
00789 std::cout << "DBG" << std::flush;
00790 ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY );
00791 std::cout << ": " << std::flush;
00792 break;
00793 }
00794
00795 ChangeColor( colorText );
00796 std::cout << l.message << std::endl;
00797
00798 ChangeColor( colorNormal );
00799 }
00800
00801 #endif
00802
00803 void mbilog::BackendCout::FormatSmart(const LogMessage &l,int threadID)
00804 {
00805 #ifdef USE_WIN32COLOREDCONSOLE
00806 FormatSmartWindows(l,threadID);
00807 #else
00808 mbilog::BackendCout::FormatSmart(std::cout,l,threadID);
00809 #endif
00810 }
00811
00812 void mbilog::BackendCout::FormatFull(const LogMessage &l,int threadID)
00813 {
00814 mbilog::BackendCout::FormatFull(std::cout,l,threadID);
00815 }