Newer
Older
Import / applications / HighwayDash / ports / Framework / Log.h
//  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