I'd start with something like this:
#define TRACE(message) TRACE_IMPL(__FILE__, __LINE__, __PRETTY_FUNCTION__, message)
void TRACE_IMPL(const char *file, int line, const char *function, const char *message) {
...
}
int main() {
TRACE("help");
}
My next step, would be to change message to be a format string, and enable printf()
style va_args on the Trace. Which would look something like:
#include <cstdio>
#include <stdarg.h>
#define TRACE(format, ...) TRACE_IMPL("File: %s Line: %d Function: %s Message: " format "\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
void TRACE_IMPL(const char *format, ...) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
int main() {
TRACE("help");
TRACE("Canary %d", 2);
}
Which would output:
[8:18pm][wlynch@watermelon /tmp] ./foo
File: foo.c Line: 14 Function: int main() Message: help
File: foo.c Line: 15 Function: int main() Message: Canary 2
You could also use C++ streams if you wanted:
#include <iostream>
#define TRACE LogImpl(__FILE__, __LINE__, __PRETTY_FUNCTION__)
class LogImpl {
public:
LogImpl(const char *file, int line, char *function) {
std::cout << "File: " << file << " Line: " << line << " Function: " << function << " Message: ";
}
~LogImpl() {
std::cout << "\n";
}
LogImpl(LogImpl const &) = delete;
LogImpl & operator=(LogImpl const &) = delete;
template <typename T>
LogImpl & operator<<(T const & obj) {
std::cout << obj;
return *this;
}
};
int main() {
TRACE << "help";
TRACE << "Canary " << 2;
}