1

Sorry, but I don't even know how exactly to ask this.

I want to generate a trace log with some of the methods or functions being run, but I don't want to write the command name in every method (I'm really lazy!).

Example:

My current code:

void doSomething() {
    TRACE("doSomething");
    // now do something!
    system("pause");
}

What I want to do:

void doSomething() {
    TRACE;
    // do something!
    system("pause");
}

Output expected (of both programs):

doSomething
Press any key to continue...

If you need me to be more clear, please let me know. I'll try to be as clear as possible.

user207421
  • 298,294
  • 41
  • 291
  • 462

1 Answers1

1

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;
}
Bill Lynch
  • 76,897
  • 15
  • 123
  • 168
  • `printf`? Much safer and more extensible to accept arguments to stream to an `iostream`. – Tony Delroy Jun 03 '14 at 01:04
  • @TonyD: That's fair. But then I'd probably toss this whole style, and just go with a Log object of some sort. If you'd like to write something like that up, I imagine that Vinícius would find it interesting. – Bill Lynch Jun 03 '14 at 01:06
  • A log object alone can't help capture the function name (nor file, line...), so this "style" is necessary. I've marked this as a duplicate so can't add another answer now! Idea's very simple anyway: `#define TRACE(MSG) do { log_stream << __func__ << ' ' << MSG << '\n'; } while (false)` or similar. `do`/`while (false)` is just there in case you want to later add to the compound statement (e.g. prefix `if (logging_enabled)`); it prevents breaking `if`/`else` clauses in the context of macro use - a common trick for macros. – Tony Delroy Jun 03 '14 at 01:11
  • @TonyD: Right, but then your formatting has become more complex, or you use an odd syntax of `TRACE("canary " << 2);` or `TRACE(boost::format("canary %1%") % 2);` – Bill Lynch Jun 03 '14 at 01:15
  • " or you use an odd syntax " - it's only odd until you get used to it ;-). – Tony Delroy Jun 03 '14 at 01:16
  • @TonyD: I've added to the post the syntax I'd probably use if I wanted an iostreams interface. – Bill Lynch Jun 03 '14 at 01:30
  • it's less flexible. What will you do if you want to add a check for a "logging enabled" flag? Check it in the constructor and on every call to `< – Tony Delroy Jun 03 '14 at 01:48
  • Wow, this scalated quickly! The implementation I've been using is with `iostreams`. Not as fancy as the one your provided but worked very well so far. – Vinícius Gobbo A. de Oliveira Jun 03 '14 at 02:08
  • @ViníciusGobboA.deOliveira true - worked on enough corporate libraries making these decisions to know all the pros and cons aren't immediately obvious... sometimes the design decisions limit what you can do later without rewriting "client" code, so choose well if it's a big system you're implementing and/or code outside your own control will adopt your interface. Cheers – Tony Delroy Jun 03 '14 at 07:40