1

I faced a problem while implementing the logger.

First, I used to __LINE__ and __FILE__ with standard C Macro function like below

// global.h
..
namespace MyLogger {

class Logger
{
    ..
    void _write(int _level, const char* _file, int _line, const char* _fmt, ...);
};
static Logger    logger;

}; // namespace MyLogger

..

// avoid conflict..
#undef error
#undef trace

#define error(_MESSAGE_, ...) _write(LOG_LEVEL_ERROR, (const char*)__FILE__, (int)__LINE__, (const char*)_MESSAGE_, ##__VA_ARGS__)
#define info(_MESSAGE_, ...)  _write(LOG_LEVEL_INFO,  (const char*)__FILE__, (int)__LINE__, (const char*)_MESSAGE_, ##__VA_ARGS__)
#define trace(_MESSAGE_, ...) _write(LOG_LEVEL_TRACE, (const char*)__FILE__, (int)__LINE__, (const char*)_MESSAGE_, ##__VA_ARGS__)
..

// main.cpp

using namespace MyLogger;

// using like this
logger.error("- log error");
logger.info("- log info %s", "test 1");
..

In fact, it seems to work well. However, the problem occurred while using openv.

error and trace seem to conflicted with error and trace in opencv.

error: expected primary-expression before ‘int’ [build] CV_EXPORTS CV_NORETURN void error(int _code, const String& _err, const char* _func, const char* _file, int _line);

So I'm thinking about other methods using inline functions, not macros.

// global.h
..
    //void _write(int _level, const char* _file, int _line, const char* _fmt, ...);
    static inline void error(/* Is it possible to toss __LINE__ or __FILE__ ? */);
    static inline void info(/* .. */);
    static inline void trace(/* .. */);
..

// main.cpp
logger::error("- log error");
logger::info("%d %c %f, 1, 'A', '0.1');

Can I know the line or file of the location where the log was output through a method other than a macro?

Clifford
  • 88,407
  • 13
  • 85
  • 165
mystes
  • 59
  • 7
  • 3
    To bad you can't use C++20 and [`std::source_location`](https://en.cppreference.com/w/cpp/utility/source_location) – Ted Lyngmo Aug 29 '22 at 05:34

3 Answers3

3

No, inline functions/methods won't work the same as macro in this context. Macros are simply text replacements, that's why the __LINE__ and __FILE__ will give accurate results. Thus macros are your only choice; See if you can name them better to avoid conflicts.

However the inline functions are systematically compiled subunits. So the line number and the file names will always be same that of those functions where it resides.

Refer: Inline functions vs Preprocessor macros

C++20

As suggested in this useful comment, you may also consider using std::source_location which allows you to avoid the macro trickery via the help of standard library & language features.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • In fact, it was confirmed that __LINE__ or __FILE__ was not working when passed with a fixed factor in the inline function. So is there any other way than using macros? – mystes Aug 29 '22 at 05:31
2

There are 3 stages in which C++ becomes a running program.

  1. Preprocessor
  2. Compiler
  3. Linker

__LINE__ and __FILE__ are processed by the preprocessor (stage 1). However, it's the compiler that decides about inlining (stage 2).

Other languages like C# have this in the compiler stage: [CallerMemberName], [CallerFilePath] and [CallerLineNumber] [MSDN] but I am don't think this exists in C++ at the moment.

Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
  • Again, there seems to be no choice but to use macros. I think I need to change the name of the macro to avoid conflict. Thank you very much for your reply. – mystes Aug 29 '22 at 05:35
1

How about this:

#define log_error(_MESSAGE_, ...) \
    logger._write( \
        LOG_LEVEL_ERROR, \
        (const char*)__FILE__, \
        (int)__LINE__, \
        (const char*)_MESSAGE_, \
        ##__VA_ARGS__)

There is no much difference (in the sense of typed characters) between logger.error and log_error. The advantages are, that you use a macro (__FILE__, __LINE__ are utilized as desired) and have your logger class used only at one place (via the macro, in case you want to use a different logging mechanism), refactoring should be without any headaches.

Erdal Küçük
  • 4,810
  • 1
  • 6
  • 11
  • Thank you for the new idea. Similar to your code, we created a new macro by avoiding the "error" keyword. – mystes Aug 29 '22 at 12:06