// BlockyFroggy
// Copyright © 2017 John Ryland.
// All rights reserved.
#pragma once
#ifndef LOG_H
#define LOG_H
/*!
@page Topics
@subpage Logging
@page Logging Logging
Documentation about logging
Example Usage:
@code
DECLARE_LOG_CONTEXT(MyScope)
void MyScope::Function(const char* file)
{
Log(LL_Error, "Error loading file %s", file);
}
@endcode
What this does is to declare in the current scope what tag to
associate with any logging. In this case it will be a tag of "MyScope".
Then is does some logging by calling Log, where this is an error so
the LL_Error parameter is passed.
*/
enum LogLevel
{
LL_Trace,
LL_Debug,
LL_Info,
LL_Warn,
LL_Error
};
// Could optimize the string concatenations to at compile time, but logger implementations would lose ability to
// decide how to format, organize and filter the messages as easily
//#define Log(a_level, a_tag, /* a_fmt */ ...) \
// SystemLogger(a_level, 0, 0, "[" a_tag "] " __FILE__ " (" STRINGIZE(__LINE__) "): " __VA_ARGS__)
// fprintf(stderr, "[" a_tag "] " __FILE__ " (" STRINGIZE(__LINE__) "): " a_fmt "\n", ## __VA_ARGS__)
// NSLogv([NSString stringWithUTF8String:a_fmt], args);
#define Log(a_level, /* a_fmt */ ...) \
contextLogger(a_level, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#define LogTag(a_level, a_tag, /* a_fmt */ ...) \
filterLogger(a_level, a_tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
void filterLogger(enum LogLevel a_level, const char* a_tag,
const char* a_file, const char* a_function, int a_line, const char* a_fmt, ...);
template<class T, typename ...Ts>
void contextLogger(enum LogLevel a_level, T a_file, const char* a_function, int a_line, Ts... args)
{
filterLogger(a_level, "Global", a_file, a_function, a_line, args...);
}
// Add a call to this macro either inside a class definition to add a context to member functions calling Log
// or add it at the top of a cpp file to set the context for the file (incompatible with compulation unit builds).
// It works in a class because it will be the function with the closest scope, and works outside to override the
// "Global" one above because of the T template parameter which as used below is more explicit/specialized
// (because of the '*' in the type).
#define DECLARE_LOG_CONTEXT(name) \
template<class T, typename ...Ts> \
static void contextLogger(enum LogLevel a_level, T* a_file, const char* a_function, int a_line, Ts... args) \
{ \
filterLogger(a_level, #name, a_file, a_function, a_line, args...); \
}
#endif // LOG_H