#pragma once #include #include #include #include "String.Format.tlh" class SimpleLog { private: FILE * fpLog = nullptr; enum enLogLevel { enDebug = 1, enInfo = 2, enWarn = 3, enError = 4, enFatal = 5 }; static inline char LogLevelToName (int level) { static char Name [6] = { ' ', ' ', ' ', 'W', 'E', 'F' }; if (level < enDebug) return ' '; else if (level > enFatal) return ' '; return Name [level]; } public: SimpleLog () = default; SimpleLog (const char* LogName) { Open (LogName); } bool Open (const char * LogName) { if (fpLog) fclose (fpLog); char AppPath [_MAX_PATH + _MAX_PATH]; int len = GetModuleFileName (NULL, AppPath, _MAX_PATH); len--; while (AppPath [len] != '\\') AppPath [len--] = '\0'; COleDateTime now = COleDateTime::GetCurrentTime (); int Y = now.GetYear (); int M = now.GetMonth (); int D = now.GetDay (); int H = now.GetHour (); int T = now.GetMinute (); int S = now.GetSecond (); char logPath[_MAX_PATH]; ECOM::Utility::StringFormat(logPath, _MAX_PATH) .Format("{$}\\Logs", AppPath); if (_access(logPath,0) != 0) { assert(_mkdir(logPath) == 0); } char logFileName [_MAX_PATH]; ECOM::Utility::StringFormat (logFileName, _MAX_PATH) .Format ("{$}\\Logs\\{$}.{$:d04}{$:d02}{$:d02}.log", AppPath, LogName, Y, M, D); fpLog = fopen (logFileName, "ab+"); assert (fpLog); return (fpLog != NULL); } void Close () { if (fpLog) fclose (fpLog); fpLog = nullptr; } public: template inline int Debug (const char * fmt, Args... args) { return LogOut (enDebug, fmt, args...); } template inline int Info (const char* fmt, Args... args) { return LogOut (enInfo, fmt, args...); } template inline int Warn (const char* fmt, Args... args) { return LogOut (enWarn, fmt, args...); } template inline int Error (const char* fmt, Args... args) { return LogOut (enError, fmt, args...); } template inline int Fatal (const char* fmt, Args... args) { return LogOut (enFatal, fmt, args...); } protected: template inline int LogOut (int Level, const char * fmt, Args... args) { if (! fpLog) return 0; static const int MaxLen = 8192; char * buf = new char [MaxLen]; struct timeb tp; ftime (&tp); tm tmNow; _localtime64_s (&tmNow, &tp.time); auto Y = tmNow.tm_year + 1900; auto M = tmNow.tm_mon + 1; auto D = tmNow.tm_mday; auto H = tmNow.tm_hour; auto T = tmNow.tm_min; auto S = tmNow.tm_sec; int len1 = ECOM::Utility::StringFormat (buf, MaxLen).Format ("{$} {$:d04}{$:d02}{$:d02} {$:d02}:{$:d02}:{$:d02}:{$:d03} [{$:x04}] ", LogLevelToName (Level), Y, M, D, H, T, S, tp.millitm, GetCurrentThreadId ()); int len2 = ECOM::Utility::StringFormat (buf+len1, MaxLen-len1).Format (fmt, args...); buf [len1 + len2 + 0] = '\r'; buf [len1 + len2 + 1] = '\n'; auto rc = (int) Flush (buf, len1+len2+2 ); delete[]buf; return rc; } int Flush (const char * buf, int len) { assert (buf); assert (fpLog); if (! fpLog) return 0; auto rc = (int) fwrite (buf, len, 1, fpLog); fflush (fpLog); return rc; } };