10

I am creating c++ library modules in my application. To do logging, I use spdlog. But in a production environment, I don't want my lib modules to do any logging. One way to achieve turning on/off would be to litter my code with #ifdef conditionals like...

#ifdef logging
  // call the logger here.
#endif

I am looking for a way to avoid writing these conditionals. May be a wrapper function that does the #ifdef checking and write it. But the problem with this approach is that I have to write wrappers for every logging method (such as info, trace, warn, error, ...)

Is there a better way?

Pavel_K
  • 10,748
  • 13
  • 73
  • 186
Mopparthy Ravindranath
  • 3,014
  • 6
  • 41
  • 78

3 Answers3

10

You can disable logging with set_level():

auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");

#if defined(PRODUCTION)
    my_logger->set_level(spdlog::level::off);
#else
    my_logger->set_level(spdlog::level::trace);
#endif

spdlog::register_logger(my_logger);
iamantony
  • 1,345
  • 17
  • 32
7

You can disable all logging before you compile the code by adding the following macro (before including spdlog.h):

#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_OFF
#include<spdlog.h>

It is explained as a comment in the file https://github.com/gabime/spdlog/blob/v1.x/include/spdlog/spdlog.h :

//
// enable/disable log calls at compile time according to global level.
//
// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h):
// SPDLOG_LEVEL_TRACE,
// SPDLOG_LEVEL_DEBUG,
// SPDLOG_LEVEL_INFO,
// SPDLOG_LEVEL_WARN,
// SPDLOG_LEVEL_ERROR,
// SPDLOG_LEVEL_CRITICAL,
// SPDLOG_LEVEL_OFF
//

Using this macro will also speed up your productive code because the logging calls are completely erased from your code. Therefore this approach may be better than using my_logger->set_level(spdlog::level::off);

However, in order for the complete code removal to work you need to use either of the macros when logging:

SPDLOG_LOGGER_###(logger, ...)

SPDLOG_###(...)

where ### is one of TRACE, DEBUG, INFO, WARN, ERROR, CRITICAL.

The latter macro uses the default logger spdlog::default_logger_raw(), the former can be used with your custom loggers. The variadic arguments ... stand for the regular arguments to your logging invocation: the fmt string, followed by some values to splice into the message.

CygnusX1
  • 20,968
  • 5
  • 65
  • 109
user74696c
  • 324
  • 4
  • 12
  • 2
    I don't know if I have an old version, but to write TRACE and DEBUG (not for others levels), I need to add ```spdlog::set_level(spdlog::level::###);``` in my code. – Kafka Aug 01 '20 at 11:06
  • @Kafka: That is correct. The macro SPDLOG_ACTIVE_LEVEL sets the "highest available log level" at compile time. The level actually logged at runtime is still affected by what your logger instance has chosen at runtime (e.g. via "spdlog::set_level"). In other words, your final log level will always be the maximum of SPDLOG_ACTIVE_LEVEL and what you have set with "spdlog::set_level". Since the default level for the latter is INFO, you did not see DEBUG and TRACE messages. – user74696c Aug 03 '20 at 10:14
1

I don't know spdlog.

However, you may define a macro in one of your common used include file, to replace the logcall by nothing, or a call to an empty inline function which the compiler optimizer will eliminate.

in "app.h"

#ifndef LOG

#ifdef logging
#define LOG spdlog
#endif

#ifndef logging
#define LOG noop
#endif

#endif

Did you get the idea?

This let most of your code untouched

stefan bachert
  • 9,413
  • 4
  • 33
  • 40
  • Yes, thx. As I checked, it works for plain functions. But if spdlog is a class which has member fns like trace(), info() etc, it doesn't compile. – Mopparthy Ravindranath Aug 11 '17 at 02:59
  • I think the approach should also work with classes. Please document how your current code looks like. Maybe me or other supply you with other approaches – stefan bachert Aug 11 '17 at 10:27