diff --git a/Utilities/mbilog/mbilog.cpp b/Utilities/mbilog/mbilog.cpp index 3cb2502ea4..18420d081d 100644 --- a/Utilities/mbilog/mbilog.cpp +++ b/Utilities/mbilog/mbilog.cpp @@ -1,818 +1,840 @@ /*========================================================================= Program: mbilog - logging for mitk / BlueBerry Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include #include #include #include #include #include "mbilog.h" #ifdef _WIN32 #define USE_WIN32COLOREDCONSOLE #include #endif static std::list backends; static bool g_init=false; namespace mbilog { static const std::string NA_STRING = "n/a"; } void mbilog::RegisterBackend(mbilog::AbstractBackend* backend) { backends.push_back(backend); } void mbilog::UnregisterBackend(mbilog::AbstractBackend* backend) { backends.remove(backend); } void mbilog::DistributeToBackends(mbilog::LogMessage &l) { // Crop Message { std::string::size_type i = l.message.find_last_not_of(" \t\f\v\n\r"); l.message = (i != std::string::npos) ? l.message.substr(0, i+1) : ""; } if(backends.empty()) { mbilog::BackendCout::FormatSmart(l); return; } std::list::iterator i; for(i = backends.begin(); i != backends.end(); i++) (*i)->ProcessMessage(l); } mbilog::BackendCout::BackendCout() { useFullOutput=false; } mbilog::BackendCout::~BackendCout() { } void mbilog::BackendCout::SetFull(bool full) { useFullOutput = full; } void mbilog::BackendCout::ProcessMessage(const mbilog::LogMessage& l) { if(useFullOutput) FormatFull(l); else FormatSmart(l); } void mbilog::BackendCout::AppendTimeStamp(std::ostream& out) { time_t rawtime = time(NULL); std::string timestring( ctime(&rawtime) ); timestring.replace( timestring.length() -1, 1," "); // replace \n by " " (separates date/time from following output of relative time since start) + + std::locale C("C"); + std::locale originalLocale = out.getloc(); + out.imbue(C); + out << timestring; + + out.imbue( originalLocale ); + } void mbilog::BackendCout::FormatSmart(std::ostream &out, const LogMessage &l,int /*threadID*/) { char c_open='['; char c_close=']'; switch(l.level) { case mbilog::Info: break; case mbilog::Warn: c_open='!'; c_close='!'; break; case mbilog::Error: c_open='#'; c_close='#'; break; case mbilog::Fatal: c_open='*'; c_close='*'; break; case mbilog::Debug: c_open='{'; c_close='}'; break; } out << c_open; if (!g_init) { g_init = true; AppendTimeStamp(out); out << std::endl; } + std::locale C("C"); + std::locale originalLocale = out.getloc(); + out.imbue(C); + out << std::fixed << std::setprecision(3) << ((double)std::clock())/CLOCKS_PER_SEC; + out.imbue( originalLocale ); + out << c_close << " "; if(!l.category.empty()) { out << "[" << l.category << "] "; } switch(l.level) { case mbilog::Info: break; case mbilog::Warn: out << "WARNING: "; break; case mbilog::Error: out << "ERROR: "; break; case mbilog::Fatal: out << "FATAL: "; break; case mbilog::Debug: out << "DEBUG: "; break; } out << l.message << std::endl; } void mbilog::BackendCout::FormatFull(std::ostream &out,const LogMessage &l,int threadID) { switch(l.level) { case mbilog::Info: out << "INFO"; break; case mbilog::Warn: out << "WARN"; break; case mbilog::Error: out << "ERROR"; break; case mbilog::Fatal: out << "FATAL"; break; case mbilog::Debug: out << "DEBUG"; break; } out << "|"; AppendTimeStamp(out); out << "|"; out << "|" << std::string(l.filePath) << "(" << l.lineNumber << ")"; out << "|" << std::string(l.functionName); //if(threadID) { out << "|" << std::hex << threadID; } //if(NA_STRING != l.moduleName) { out << "|" << std::string(l.moduleName); } //if(!l.category.empty()) { out << "|" << l.category; } out << l.message << std::endl; } #ifdef USE_WIN32COLOREDCONSOLE static HANDLE g_hConsole; class AutoCategorize { protected: std::vector path; std::string current,category; int pos; void flush() { if(current.size()>0) { if(current.compare("..")==0) { if(path.size()>0) path.pop_back(); } else { path.push_back(current); } current=""; } } std::string simplify(std::string x) { static char *replace[] = { ".cpp", "", ".cxx", "", ".txx", "", ".h", "", ".hpp", "", ".hxx", "", ".c", "", "org.blueberry.", "", "org.mitk.gui.qt.", "", "org.mitk.", "", "qmitk", "", "mitk", "", "berry", "", "itk", "", "vtk", "", "qt", "", "object", "obj", "factory", "fac", "classes", "cls", "plugin", "plg", "widget", "wdgt", "interface", "itf", "service", "svc", "register", "reg", "perspective", "prs", "assessor", "ase", "atrophy", "atr", "bias", "bias", "field", "fld", "multi", "mlt", "contour", "cntr", "tools", "tls", "tool", "tl", "application", "app", "calculate", "calc", "subtract", "sub", "region", "reg", "tumor", "tum", "growing", "grow", "segmentation", "seg", "statistics", "stat", "imaging", "img", "image", "img", "diffusion", "dif", "registration", "reg", "navigation", "nav", "generation", "gen", "generator", "gen", "vector", "vec", "gradient", "grad", "flow", "flow", "paint", "pnt", "brush", "brsh", "volumetry", "vol", "volume", "vol", "mapper", "map", "filter", "flt", "surface", "sfc", "point", "pnt", "organ", "org", "multiple", "mlt", "corrector", "cor", "correction", "cor", "batch", "bat", "window", "wnd", "advisor", "adv", "editor", "edt", "material", "mat", "visualization", "vis", "measurement", "mes", "scene", "scn", "serialization", "ser", "deserializer", "dser", "serializer", "ser", "sandbox", "sb", "texture", "tex", "opengl", "ogl", "vessel", "vsl", "value", "val", "analysis", "ana", "patient", "pat", "body", "body", "diagnosis", "diag", "mesh", "mesh", "radial", "rad", "simple", "smp", "algorithms", "alg", "controllers", "con", "control", "con", "interactive", "ia", "interactions", "ia", "processing", "pro", "process", "pro", "rendering", "rnd", "renderer", "rnd", "render", "rnd", "datamanagement", "data", "management", "mng", "manager", "mng", "data", "data", "anatomy", "ana", "neuro", "neo", "automatic", "auto", "optimizer", "opt", "optimize", "opt", "binary", "bin", "liver", "liv", "lymph", "lym", "node", "node", "tree", "tree", "homogeneous", "hmgn", "threshold", "tsh", // "shapebased", "shp", "based", "bsd", "shape", "shp", "model", "mdl", "extension", "ext", "activator", "act", "dicom", "dicom", "browser", "brwr", "viewer", "view", "view", "view", "finder", "fnd", "indexer", "idx", "index", "idx", "rapid", "rpd", "gui", "gui", "slices", "slc", "slice", "slc", "about", "abt", "interpolator", "inp", "switcher", "swh", "planning", "plan", "planner", "plan", "plane", "pln", "plan", "plan", "workbench", "wrkbnc", "common", "com", "resection", "rsc", "translation", "trnsl", "rotation", "rot", "deformation", "dfrm", "shader", "shd", "repository", "rep", "initializer", "init", "dialog", "dlg", "download", "down", "upload", "up", "core", "core", "manual", "man", "leaf", "leaf", "internal", "int", "external", "ext", "platform", "pltfm", "method", "mthd", "pyramidal", "prmdl", "tracking", "trck", "track", "trck", "bspline", "bspl", "spline", "spl", "create", "crt", "erase", "ers", "auto", "auto", "crop", "crop", "file", "file", "io", "io", "2d", "2d", "3d", "3d", ".", "." }; bool redo; std::string lft(""),rgt(""); do { redo=false; for(int r=0; r < sizeof(replace)/sizeof(char*); r+=2) { int s = static_cast( strlen(replace[r]) ); int xs = static_cast( x.size() ); if(xs==s) { if( replace[r+1][0] || !lft.empty() || !rgt.empty() ) if(x.compare(replace[r])==0) x=replace[r+1]; } else if(xs>s) { if(strncmp(replace[r],&x.c_str()[xs-s],s)==0) { std::string rp = replace[r+1]; if(!rp.empty()) rp[0]=toupper(rp[0]); x = x.substr(0,xs-s); rgt = rp + rgt; redo=true; } else if(strncmp(replace[r],x.c_str(),s)==0) { std::string rp = replace[r+1]; if(!rp.empty()) rp[0]=toupper(rp[0]); x=x.substr(s,xs-s); lft = lft + rp; redo=true; } } } } while(redo); x[0]=toupper(x[0]); x=lft+x+rgt; x[0]=tolower(x[0]); return x; } std::string concat(std::string a,std::string b,bool opt) { int as = static_cast( a.size() ); int bs = static_cast( b.size() ); if(opt && as <= bs) { if (as==bs && a.compare(b)==0) return a; if(strncmp(a.c_str(),b.c_str(),as)==0) { b=b.substr(as,bs-as); b[0]=tolower(b[0]); } } return a+"."+b; } bool search2p2(char *a,char *b,bool optimize=true) { int size = static_cast( path.size() ) - 3; for(int r=0;r( path.size() ) - 2; for(int r=0;r( path.size() ) - 2; for(int r=0;r( strlen(l.filePath) ); current = ""; for(int r = 0;r>> " << std::flush; ChangeColor( colorNormal ); std::cout << std::endl; */ // Give out start time ChangeColor( colorTime ); AppendTimeStamp(std::cout); std::cout << std::endl; } switch(l.level) { case mbilog::Info: break; case mbilog::Warn: colorTime = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY; //colorText = FOREGROUND_RED|FOREGROUND_GREEN; colorCat = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; showColon = false; forceCat = true; break; case mbilog::Error: colorTime = FOREGROUND_RED|FOREGROUND_INTENSITY; //colorText = FOREGROUND_RED; colorCat = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; showColon = false; forceCat = true; break; case mbilog::Fatal: colorTime = FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_INTENSITY; //colorText = FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_INTENSITY; colorCat = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; showColon = false; forceCat = true; break; case mbilog::Debug: colorTime = FOREGROUND_BLUE|FOREGROUND_INTENSITY; //colorText |= FOREGROUND_INTENSITY; showColon = false; break; } ChangeColor( colorTime ); + + std::locale C("C"); + std::locale originalLocale = std::cout.getloc(); + std::cout.imbue(C); + std::cout << std::fixed << std::setprecision(2) << ((double)std::clock())/CLOCKS_PER_SEC << " "; + + std::cout.imbue( originalLocale ); + // category { AutoCategorize ac(l); std::string pre=ac.GetPrefix(); std::string cat=ac.GetCategory(); cat = pre + cat; if(cat.empty()) cat = l.category; if(!cat.empty()) { ChangeColor( colorCat ); // static std::string lastCat; // if(forceCat||lastCat.compare(cat)) { std::cout << cat << std::flush; // lastCat = cat; } // else // std::cout << "..." << std::flush; if(showColon) { ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY ); std::cout << ": " << std::flush; } else std::cout << " "; } } switch(l.level) { case mbilog::Info: break; case mbilog::Warn: ChangeColor( colorTime ); std::cout << "WARNING" << std::flush; ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY ); std::cout << ": " << std::flush; break; case mbilog::Error: ChangeColor( colorTime ); std::cout << "ERROR" << std::flush; ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY ); std::cout << ": " << std::flush; break; case mbilog::Fatal: ChangeColor( colorTime ); std::cout << "FATAL" << std::flush; ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY ); std::cout << ": " << std::flush; break; case mbilog::Debug: ChangeColor( colorTime ); std::cout << "DBG" << std::flush; ChangeColor( FOREGROUND_BLUE | FOREGROUND_INTENSITY ); std::cout << ": " << std::flush; break; } ChangeColor( colorText ); std::cout << l.message << std::endl; ChangeColor( colorNormal ); } #endif void mbilog::BackendCout::FormatSmart(const LogMessage &l,int threadID) { #ifdef USE_WIN32COLOREDCONSOLE FormatSmartWindows(l,threadID); #else mbilog::BackendCout::FormatSmart(std::cout,l,threadID); #endif } void mbilog::BackendCout::FormatFull(const LogMessage &l,int threadID) { mbilog::BackendCout::FormatFull(std::cout,l,threadID); } diff --git a/Utilities/mbilog/mbilog.h b/Utilities/mbilog/mbilog.h index bc2af3fc9f..7d8965ca5a 100644 --- a/Utilities/mbilog/mbilog.h +++ b/Utilities/mbilog/mbilog.h @@ -1,247 +1,271 @@ /*========================================================================= Program: mbilog - logging for mitk / BlueBerry Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _MBILOG_H #define _MBILOG_H #include #include #include #include "mbilogConfig.h" #ifndef MBILOG_MODULENAME #if defined(_CMAKE_MODULENAME) #define MBILOG_MODULENAME _CMAKE_MODULENAME #else #define MBILOG_MODULENAME "n/a" #endif #endif #if defined(_WIN32) #ifdef mbilog_EXPORTS #define MBILOG_DLL_API __declspec(dllexport) #else #define MBILOG_DLL_API __declspec(dllimport) #endif #else #define MBILOG_DLL_API #endif namespace mbilog { enum { Info, Warn, Error, Fatal, Debug }; class MBILOG_DLL_API LogMessage { public: const int level; const char* filePath; const int lineNumber; const char* functionName; const char* moduleName; std::string category; std::string message; LogMessage( const int _level, const char* _filePath, const int _lineNumber, const char* _functionName ) : level(_level) , filePath(_filePath) , lineNumber(_lineNumber) , functionName(_functionName) { } }; struct MBILOG_DLL_API AbstractBackend { virtual ~AbstractBackend(){} virtual void ProcessMessage(const mbilog::LogMessage& )=0; }; class MBILOG_DLL_API BackendCout : public AbstractBackend { public: BackendCout(); ~BackendCout(); virtual void ProcessMessage(const mbilog::LogMessage &l ); void SetFull(bool full); static void FormatSmart(const LogMessage &l,int threadID=0); static void FormatFull(const LogMessage &l,int threadID=0); static void FormatSmart(std::ostream &out, const LogMessage &l,int threadID=0); static void FormatFull(std::ostream &out, const LogMessage &l,int threadID=0); private: static void AppendTimeStamp(std::ostream& out); static void FormatSmartWindows(const mbilog::LogMessage &l,int /*threadID*/); bool useFullOutput; }; void MBILOG_DLL_API RegisterBackend(AbstractBackend* backend); void MBILOG_DLL_API UnregisterBackend(AbstractBackend* backend); void MBILOG_DLL_API DistributeToBackends(LogMessage &l); class MBILOG_DLL_API PseudoStream { protected: bool disabled; LogMessage msg; std::stringstream ss; public: inline PseudoStream( int level, const char* filePath, int lineNumber, const char* functionName) : disabled(false) , msg(LogMessage(level,filePath,lineNumber,functionName)) , ss(std::stringstream::out) { } inline ~PseudoStream() { if(!disabled) { msg.message = ss.str(); msg.moduleName = MBILOG_MODULENAME; DistributeToBackends(msg); } } template inline PseudoStream& operator<<(const T& data) { if(!disabled) + { + std::locale C("C"); + std::locale originalLocale = ss.getloc(); + ss.imbue(C); + ss << data; + + ss.imbue( originalLocale ); + } return *this; } template inline PseudoStream& operator<<(T& data) { if(!disabled) + { + std::locale C("C"); + std::locale originalLocale = ss.getloc(); + ss.imbue(C); + ss << data; + + ss.imbue( originalLocale ); + } return *this; } inline PseudoStream& operator<<(std::ostream& (*func)(std::ostream&)) { if(!disabled) + { + std::locale C("C"); + std::locale originalLocale = ss.getloc(); + ss.imbue(C); + ss << func; + + ss.imbue( originalLocale ); + } return *this; } inline PseudoStream& operator()(const char *category) { if(!disabled) { if(msg.category.length()) msg.category+="."; msg.category+=category; } return *this; } inline PseudoStream& operator()(bool enabled) { disabled|=!enabled; return *this; } }; class MBILOG_DLL_API NullStream { public: template inline NullStream& operator<<(const T& /*data*/) { return *this; } template inline NullStream& operator<<(T& /*data*/) { return *this; } inline NullStream& operator<<(std::ostream& (*)(std::ostream&)) { return *this; } inline NullStream& operator()(const char *) { return *this; } inline NullStream& operator()(bool) { return *this; } }; // // template // struct DelegateBackend : public AbstractBackend // { // // typedef void(T::*Callback)(const mbilog::LogMessage&); // // DelegateBackend(T* obj, Callback callback) : m_Obj(obj), m_Callback(callback) // { // } // // void ProcessMessage(const mbilog::LogMessage& msg) // { // m_Obj->*m_Callback(msg); // } // // private: // // T* m_Obj; // Callback m_Callback; // }; } #define MBI_INFO mbilog::PseudoStream(mbilog::Info,__FILE__,__LINE__,__FUNCTION__) #define MBI_WARN mbilog::PseudoStream(mbilog::Warn,__FILE__,__LINE__,__FUNCTION__) #define MBI_ERROR mbilog::PseudoStream(mbilog::Error,__FILE__,__LINE__,__FUNCTION__) #define MBI_FATAL mbilog::PseudoStream(mbilog::Fatal,__FILE__,__LINE__,__FUNCTION__) #ifdef MBILOG_ENABLE_DEBUG #define MBI_DEBUG mbilog::PseudoStream(mbilog::Debug,__FILE__,__LINE__,__FUNCTION__) #else #define MBI_DEBUG true ? mbilog::NullStream() : mbilog::NullStream() #endif #endif