0

I'm using the CocoaLumberjack logging framework 2.0.0 for logging with different levels. In my Prefix.pch (I know that this file is deprecated, but it should work nevertheless) I include Cocoalumberjack and set the global log level as suggested here:

#ifdef DEBUG
  static const DDLogLevel ddLogLevel = DDLogLevelDebug;
#else
  static const DDLogLevel ddLogLevel = DDLogLevelWarn;
#endif

I have a DDLogVerbose statement on a few methods, that should not be logged by default. Problem: However, they are getting logged.

Inspecting the ddLogLevel in an init-function shows 00001111, which equals DDLogLevelDebug. Nevertheless, a verbose logging statement directly after this is executed. (1)

Preprocessing the line DDLogVerbose(@"I AM VERBOSE") shows this code:

do {
        if(DDLogLevelVerbose & DDLogFlagVerbose)
            [DDLog log : __objc_yes
                 level : DDLogLevelVerbose
                  flag : DDLogFlagVerbose
               context : 0
                  file : "....m"
              function : __PRETTY_FUNCTION__
                  line : 59
                   tag : ((void *)0)
                format : (@"I AM VERBOSE")];
    } while(0);

which means, that the LogLevel after preprocessing is Verbose. (2) I found out that this level is the default in CocoaLumberjack in case, no log level is defined:

#ifndef LOG_LEVEL_DEF
    #ifdef ddLogLevel
        #define LOG_LEVEL_DEF ddLogLevel
    #else
        #define LOG_LEVEL_DEF DDLogLevelVerbose
    #endif
#endif

But: Debugging this shows that the first path is executed, i.e. LOG_LEVEL_DEF (which is checked against the level of the statement to determine if it should be logged or not) is assigned the correct level (Debug).

Question: I didn't find out, why (1) shows the LogLevel Debug and, after preprocessing, it switched to Verbose (2). Could this be a matter of the order in which headers are included? Or am I missing some important point?

Florian Gössele
  • 4,376
  • 7
  • 25
  • 49

3 Answers3

1

I didn't solve this issue, so I wrote my own header file for logging:

//  Create Logging Messages by calling the functions:
//  * DDLogFatal(...)
//  * DDLogError(...)
//  * DDLogWarn(...)
//  * DDLogInfo(...)
//  * DDLogDebug(...)
//  * DDLogTrace(...)
//  * DDLogTrace()
//  Only the functions that match Log Level (defined beneath) and above this level will lead to an output.
//
//  NOTE: For this file to work, the option "Treat warnings as errors" must be turned off!

/*********************************
 * CURRENT LOG LEVEL ***
 *********************************/
#define LOG_LEVEL LOG_LEVEL_DEBUG

/* Default Log Level */
#ifndef LOG_LEVEL
    #ifdef DEBUG
        #define LOG_LEVEL LOG_LEVEL_DEBUG
    #else
        #define LOG_LEVEL LOG_LEVEL_WARN
    #endif
#endif

/* List of Log Levels */
#define LOG_LEVEL_OFF    0 // 0000 0000
#define LOG_LEVEL_FATAL  1 // 0000 0001
#define LOG_LEVEL_ERROR  3 // 0000 0011
#define LOG_LEVEL_WARN   7 // 0000 0111
#define LOG_LEVEL_INFO  15 // 0000 1111
#define LOG_LEVEL_DEBUG 31 // 0001 1111
#define LOG_LEVEL_TRACE 63 // 0011 1111

#define LOG_FLAG_FATAL   1 // 0000 0001
#define LOG_FLAG_ERROR   2 // 0000 0010
#define LOG_FLAG_WARN    4 // 0000 0100
#define LOG_FLAG_INFO    8 // 0000 1000
#define LOG_FLAG_DEBUG  16 // 0001 0000
#define LOG_FLAG_TRACE  32 // 0010 0000

#if (LOG_LEVEL & LOG_FLAG_FATAL) > 0
    #define DDLogFatal(...) ALog(@"FATAL", __VA_ARGS__)
#else
    #define DDLogFatal(...)
#endif

#if (LOG_LEVEL & LOG_FLAG_ERROR) > 0
    #define DDLogError(...) ALog(@"ERROR", __VA_ARGS__)
#else
    #define DDLogError(...)
#endif

#if (LOG_LEVEL & LOG_FLAG_WARN) > 0
    #define DDLogWarn(...) ALog(@"WARNING", __VA_ARGS__)
#else
    #define DDLogWarn(...)
#endif

#if (LOG_LEVEL & LOG_FLAG_INFO) > 0
    #define DDLogInfo(...) ALog(@"INFO", __VA_ARGS__)
#else
    #define DDLogInfo(...)
#endif

#if (LOG_LEVEL & LOG_FLAG_DEBUG) > 0
    #define DDLogDebug(...) ALog(@"DEBUG", __VA_ARGS__)
#else
    #define DDLogDebug(...)
#endif

#if (LOG_LEVEL & LOG_FLAG_TRACE) > 0
    #define DDLogTrace(...) ALog(@"TRACE", __VA_ARGS__)
    #define DDLogEntry() ALog(@"TRACE", @"->")
#else
    #define DDLogTrace(...)
    #define DDLogEntry()
#endif

#define ALog(logLevel, fmt, ...) NSLog((@"%s [Line %d] %@: " fmt), __PRETTY_FUNCTION__, __LINE__, logLevel, ##__VA_ARGS__)

Include this file wherever Logging is needed. Hope this helps someone!

Florian Gössele
  • 4,376
  • 7
  • 25
  • 49
1

So I'm not sure if this is the same issue you were running into, but I had a similar symptom, i.e. my log levels being ignored. What was happening for me is that the cocoa lumberjack folks made it easier in v2 for new users to get started by not having to specify a log level at all to get the framework to work.

As per the lumberjack docs, to actually use ddLogLevel I needed to #define it before importing the CocoaLumberjack.h file:

Using ddLogLevel to start using the library is now optional. If you define it add #define LOG_LEVEL_DEF ddLogLevel before #import and make change its type to DDLogLevel

In my case, I'm doing that in the .pch file, so it looks like:

// ProjectX.pch
#define LOG_LEVEL_DEF ddLogLevel // this is the crucial bit!
#import "CocoaLumberjack/CocoaLumberjack.h"

// Then the normal definitions... 
#ifdef DEBUG
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
static DDLogLevel ddLogLevel = DDLogLevelWarning;
#pragma clang diagnostic pop
#else
static const DDLogLevel ddLogLevel = DDLogLevelWarning;
#endif
#define LOG_LEVEL_DEF ddLogLevel
Zoë Smith
  • 1,084
  • 1
  • 11
  • 19
0

CocoaLumberjack has 4 log levels

  1. Error
  2. Warning
  3. Info
  4. Verbose

The "ddLogLevel" determines which logs are to be executed and which to be ignored. If you do not want DDLogVerbose to be executed change to lower levels like Info.

Change your DEBUG macro as follows

#ifdef DEBUG
static const int ddLogLevel = LOG_LEVEL_INFO;
#else
static const int ddLogLevel = LOG_LEVEL_ERROR;
#endif

Hope this solves your issue.

iPhoneDeveloper
  • 958
  • 1
  • 14
  • 23