This project is read-only.

C++ Logging Project Documentation

Log project ZIP file

This project was created using Visual Studio 2015 and uses Windows libraries, but nothing exotic or specific to any version of Windows starting at XP. The SLN (solution) file used to support earlier versions, but I no longer have those versions at my disposal - just 2015.

In the download ZIP file, inside the LogFileTest folder are two directories (among several):
LogLibs and
LogIncludes

The LogLibs folder, once you compile the project in VS 2015, will contain the static lib files according to the log build type:
  • LogFile_x86d.lib -- the x86 debug build
  • LogFile_x86r.lib -- the x86 release build
  • LogFile_x64d.lib -- the x64 debug build
  • LogFile_x64r.lib -- the x64 release build
The LogIncludes folder contains the include files needed in your project.
The other folders contain the project's source code.

Steps for compiling the logger library:

  1. Download the CppLogLib_<version>.zip file and unzip the project to an appropriate folder.
  2. Open the .sln file for the logger project in VS 2015.
  3. Access the Build menu and select Batch Build. Select the types of libraries appropriate for your project.
  4. Build the project.

It is recommended to build the log project yourself to create the lib files to prevent binary incompatibilities.

When you build the log libraries yourself, the compiled lib files are "post-event" copied to the LogLibs folder.

Using the logger in your project

  1. Add paths to the logger include and library files:
    • Properties -> Configuration Properties -> C/C++ -> General: add path to LogIncludes folder.
    • Properties -> Configuration Properties -> Linker -> input: add path and name of an appropriate LogFile<build type>.lib file.
  2. Add #include "log.h" in each source file in your project where log messages will be created.
  3. Call "Logger::Init(logFileNameVar)" once, but call "Logger::GetLog()" wherever logging is needed. A good place to call Logger::GetLog() might be a class constructor, and save the object pointer to a member variable (type "LogFile_t").
  4. Assign the output from Logger::GetLog() to a LogFile_t variable (possibly a member variable), then use this variable to call the Info(), Debug(), Warning() and Error() methods.

Sample code:
#include "Log.h"
using namespace std;
int main(void)
{
	Logger::Init(L"MyProjectApp.log", true, false);
	LogFile_t log = Logger::GetLog();
	if ( log->IsProblem() )
	{
            cout << "\n" << log->GetErrorMessage() << endl;
	}
	else
	{
                log->Error(__FILE__, __LINE__, "main", "This is a regular log test (main thread)");
                if ( log->IsProblem() )
                {
                    cout << log->GetErrorMessage() << endl;
                }
         }
	return 0;
}

  • The Logger::Init() is called only once in an application. Repeated calls are ignored.
  • Use Logger::GetLog() to get a pointer to the log object. Each class that wants to log will need to call Logger::GetLog().
  • Since the logger is thread-safe, GetLog() can be called from threads other than the one that initialized the log.

Logger API (log initialization)

void Logger::Init(const char* logPathName, bool overwrite = true, bool useUTCtime = true);
void Logger::Init(const wchar_t* logPathName, bool overwrite = true, bool useUTCtime = true);
void Logger::Init(const std::string& logPathName, bool overwrite = true, bool useUTCtime = true);
void Logger::Init(const std::wstring& logPathName, bool overwrite = true, bool useUTCtime = true);
  • logPathName can either contain just the log name (which will be created or opened in the current working directory), or a full path and log file name. If the path does not exist, the output will be redirected to stderr.
  • overwrite is a flag that instructs the log file to be opened in overwrite mode (true) or append mode (false).
  • useUTCtime is a flag that determines the date/time format added to each log entry: UTC time (true) or local time (false). for UTC time, a "U" is added after the date/time in the log entry to communicate the time is UTC. A "L" is added if the time is local (the system time).
Call one of these static methods to initialize the logging system.

LogFile_t Logger::GetLog(void);
Returns the pointer to the log object that gives access to creating log messages. If the Logger has not been initialized, GetLog() will return an empty shared pointer.

bool Logger::IsAlreadyInit(void);
Returns true if Logger::Init() was already called successfully, false if not.

bool Logger::IsProblem(void);
Returns true if an error condition has occurred. Call Logger::GetErrorMessage() go retrieve the error message.

std::string& Logger::GetErrorMessage(void);
Returns a STL string with an error message (or an empty string if no error was detected).

std::string& Logger::GetLogNameA(void);
Returns the ASCII log file name if one of the Init(char*...) or Init(string&...) methods were called; otherwise an empty string is returned.

std::wstring& Logger::GetLogNameW(void);
Returns the wide char log file name if one of the Init(wchar_t*...) or Init(wstring&...) methods were called; otherwise an empty string is returned.

LogFile_t API (log file access)

For example: LogFile_t myLog = Logger::GetLog();
myLog->Info("my log entry number %d", numberVar);

void Info(const char* message, ...);
void Info(const wchar_t* message, ...);
  • message is a printf-style string containing optional printf formatters (like, %d, %s, %x, etc.). If formatters are used, a corresponding number of variables (of types that match each formatter) must follow message.

void Debug(const char* file, const int lineNumber, const char* function, const char* message, ...);
void Debug(const char* file, const int lineNumber, const wchart* function, const wchart* message, ...);
void Warning(const char* file, const int lineNumber, const char* function, const char* message, ...);
void Warning(const char* file, const int lineNumber, const wchart* function, const wchart* message, ...);
void Error(const char* file, const int lineNumber, const char* function, const char* message, ...);
void Error(const char* file, const int lineNumber, const wchart* function, const wchart* message, ...);
  • file is the source file name. The easiest thing to do is use the macro __FILE__.
  • lineNumber is the source file line number where one of these methods is called. Try using macro __LINE__.
  • function is what you supply to log the method or function from which the log entry is created.
  • message is a printf-style string containing optional printf formatters (like, %d, %s, %x, etc.). If formatters are used, a corresponding number of variables (of types that match each formatter) must follow message. For format specifiers see http://msdn.microsoft.com/en-us/library/56e442dc(VS.90).aspx.

bool IsProblem();
Returns true if an error has been detected and false if not.

const std::string& GetErrorMessage();
Returns a STL string with the error message, or an empty string if no error has been detected.

About the code

The Logger class is a singleton: the constructors are protected, and the accessor methods are static. Initialization constructs the data-access-layer class along with helper classes, LogFileObjInit and MessageFormat.

The LogFileDAL class provides proxy access to the log file class: the Info(), Debug(), Warning() and Error() methods grant user access to this writing class.

The LogFileObjInit class creates and initializes the LogFile class, and makes it available to LogFileDAL.

The MessageFormat class handles data formatting from LogFileDAL logging methods.

The LogFile class takes a message string (formatted in the LogFileDAL layer) and writes it to the opened log file.

Miscellaneous Information

  • The log entries are written to an ASCII file, which means a wchar_t string containing any values greater than 255 will not translate correctly. In such cases, the too-large-a-value is converted to character 254 (the old English "thorn" letter). You can change this conversion character in the code (perhaps to a question mark?) when calling function char_to_wchar_string(). Perhaps at a later time I could add UNICODE file support if there is enough interest.
  • If the log file cannot be opened for whatever reason, log entries will be sent to stderr. If you intentionally want the output sent to stderr, call Logger::Init("") with an empty file string name.
  • In "Release" build mode, Debug() log entries are ignored -- not sent to the log file.
  • The logger will not work properly (with the same log path/name) across application or service spaces. However, if you feel ambitious the back-end (LogFile) can be replaced with your own code to handle this situation.
  • The logger does not presently support multiple simultaneous log files within an application execution space -- just one open log file.
  • The logger intentionally does not throw exceptions, since likely the last thing you want is the log to throw unhandled exceptions. Nor, I suppose, would you want to surround every log call with try-catch blocks. To check for errors use the "IsProblem()" method.

Last edited Aug 16, 2016 at 2:05 AM by krisgus, version 50

Comments

No comments yet.