Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Fix" conflicts with 3rd party libraries using CocoaLumberjack #172

Merged

Conversation

rivera-ernesto
Copy link
Member

As discussed in #162, there's no solution to sharing ddLogLevel between libraries and the client application:

  • Apps/libraries may define ddLogLevel as a const, extern, int, a function returning an int, etc. Each one incompatible with the other.
  • Even more, if apps/libraries used a compatible and shared ddLogLevel there would be no way to manage separately log levels from each one.

The solution is to define a LOG_LEVEL_DEF by default equal to ddLogLevel so apps can continue to work as usual.

3rd party libraries simple redefine LOG_LEVEL_DEF to something different:

// #undef LOG_LEVEL_DEF // Undefine first only if needed
#define LOG_LEVEL_DEF myLibLogLevel

3rd party frameworks need to be updated.

As discussed in CocoaLumberjack#162, there's no solution to sharing `ddLogLevel` between libraries and the client application:

* Apps/libraries may define `ddLogLevel` as a const, extern, int, a function returning an int, etc. Each one incompatible with the other.

* Even more, if apps/libraries used a compatible and shared `ddLogLevel` there would be no way to manage separately log levels from each one.

The solution is to define a `LOG_LEVEL_DEF` by default equal to `ddLogLevel` so apps can continue to work as usual.

3rd party libraries simple redefine `LOG_LEVEL_DEF` to something different:

```obj-c
// #undef LOG_LEVEL_DEF // Undefine first only if needed
#define LOG_LEVEL_DEF myLibLogLevel
```

3rd party frameworks **need** to be updated.
@bpoplauschi
Copy link
Member

Looks good @rivera-ernesto . Thanks for doing this

bpoplauschi added a commit that referenced this pull request Nov 21, 2013
"Fix" conflicts with 3rd party libraries using CocoaLumberjack
@bpoplauschi bpoplauschi merged commit 807cc06 into CocoaLumberjack:master Nov 21, 2013
@rivera-ernesto
Copy link
Member Author

Now we need to ask library devs to update their CocoaLumberjack usage:

 * Step 1:
 * Import the header in your implementation file:
 * 
 * #import "DDLog.h"
 * 
 * Step 2:
 * Define your logging level in your implementation file:
 * 
 * // Log levels: off, error, warn, info, verbose
 * static const int ddLogLevel = LOG_LEVEL_VERBOSE;
 * 
 * Step 2 [3rd party frameworks]:
 *
 * Define your LOG_LEVEL_DEF to a different variable/function than ddLogLevel:
 *
 * // #undef LOG_LEVEL_DEF // Undefine first only if needed
 * #define LOG_LEVEL_DEF myLibLogLevel
 *
 * Define your logging level in your implementation file:
 *
 * // Log levels: off, error, warn, info, verbose
 * static const int myLibLogLevel = LOG_LEVEL_VERBOSE;
 *
 * Step 3:
 * Replace your NSLog statements with DDLog statements according to the severity of the message.
 * 
 * NSLog(@"Fatal error, no dohickey found!"); -> DDLogError(@"Fatal error, no dohickey found!");

We'll also need some proper documentation for this in the README and/or Wiki.

@rivera-ernesto
Copy link
Member Author

Creating a 1.6.4 release so they can point this release in their specs' requirements.

@rivera-ernesto rivera-ernesto deleted the fix_ddloglevel_conflict branch November 21, 2013 08:53
@augustj
Copy link
Contributor

augustj commented Nov 21, 2013

Looks like a great solution. Thanks for working it out.

@ealeksandrov
Copy link

https://github.com/robbiehanson/CocoaLumberjack/wiki/XcodeTricks - this is still true, considering last changes?

I am recieving error, when building with CocoaLumberjack and MagicalRecord as pods:

Pods/Headers/MagicalRecord/MagicalRecord.h:27:20: Redefinition of 'ddLogLevel' with a different type: 'int' vs 'const int'

How can I supress this, from my side? Or this requires changes from MagicalRecord?

@rivera-ernesto
Copy link
Member Author

https://github.com/robbiehanson/CocoaLumberjack/wiki/XcodeTricks - this is still true, considering last changes?

It is, but only for the host application. Frameworks could do the same with their levels:

#ifdef DEBUG
  static const int myLibLogLevel = LOG_LEVEL_WARN; // Probably not VERBOSE here!
#else
  static const int myLibLogLevel = LOG_LEVEL_ERROR;
#endif

@rivera-ernesto
Copy link
Member Author

I am receiving error, when building with CocoaLumberjack and MagicalRecord as pods:
Pods/Headers/MagicalRecord/MagicalRecord.h:27:20: Redefinition of 'ddLogLevel' with a different type: 'int' vs 'const int'
How can I supress this, from my side? Or this requires changes from MagicalRecord?

For now you could redefine LOG_LEVEL_DEF for your app:

#define LOG_LEVEL_DEF myAppLogLevel

// Just before
#import <DDLog/DDLog.h>

Then you replace ddLogLevel by myAppLogLevel in your code.

@ealeksandrov
Copy link

@rivera-ernesto thanks for this hints!
But now, if we are defining in 3rd party, like:

#define LOG_LEVEL_DEF MRLogLevel
static const int MRLogLevel = LOG_LEVEL_WARN;

including this define along with whole library - will override pch setting for application log level.
What am I doing wrong?

The only solution that I see - to import DDLog.h with LOG_LEVEL_DEF redefine at top of every .m file in my project (but after all other imports).
Step 1 confirms this? No way to use one declaration in pch now?

And about proposed temporary solution:
screen shot 2013-11-22 at 14 04 44

@rivera-ernesto
Copy link
Member Author

Yes, you have to define LOG_LEVEL_DEF before importing <DDLog/DDLog.h>. You can either:

  • Do it inside every *.m file;
  • Add it to your library's prefix file if you build the library yourself.
  • Let CocoaPods add it to your library's prefix file:
  s.prefix_header_contents = <<-EOS
  #ifdef __OBJC__  
        #define LOG_LEVEL_DEF MRLogLevel
        static const int MRLogLevel = LOG_LEVEL_WARN;
        #import <DDLog/DDLog.h>
        //...
  #endif
  • Create a Private.h header that you import in all your *.m files and also define there any values and shared code that your library needs. Personally I do this.

@rivera-ernesto
Copy link
Member Author

I'm trying to make CocoaLumberjack optional for my libraries (sample). Use it if available, else fallback to NSLog.

// a) Use NBULog for logging when available
#ifdef COCOAPODS_POD_AVAILABLE_NBULog

#import "NBULog+NBUKit.h"

#define NBUKIT_LOG_LEVEL    [NBULog kitLogLevel]

// Customize NBULog macros
#undef  NBULogError
#define NBULogError(frmt, ...)  LOG_OBJC_MAYBE(LOG_ASYNC_ERROR,   NBUKIT_LOG_LEVEL, LOG_FLAG_ERROR,   NBUKIT_LOG_CONTEXT, frmt, ##__VA_ARGS__)
#undef  NBULogWarn
#define NBULogWarn(frmt, ...)   LOG_OBJC_MAYBE(LOG_ASYNC_WARN,    NBUKIT_LOG_LEVEL, LOG_FLAG_WARN,    NBUKIT_LOG_CONTEXT, frmt, ##__VA_ARGS__)
#undef  NBULogInfo
#define NBULogInfo(frmt, ...)   LOG_OBJC_MAYBE(LOG_ASYNC_INFO,    NBUKIT_LOG_LEVEL, LOG_FLAG_INFO,    NBUKIT_LOG_CONTEXT, frmt, ##__VA_ARGS__)
#undef  NBULogDebug
#define NBULogDebug(frmt, ...)  LOG_OBJC_MAYBE(LOG_ASYNC_DEBUG,   NBUKIT_LOG_LEVEL, LOG_FLAG_DEBUG,   NBUKIT_LOG_CONTEXT, frmt, ##__VA_ARGS__)
#undef  NBULogVerbose
#define NBULogVerbose(frmt, ...)LOG_OBJC_MAYBE(LOG_ASYNC_VERBOSE, NBUKIT_LOG_LEVEL, LOG_FLAG_VERBOSE, NBUKIT_LOG_CONTEXT, frmt, ##__VA_ARGS__)


// b) Else try CocoaLumberjack
#elif defined(COCOAPODS_POD_AVAILABLE_CocoaLumberjack)

#ifdef DEBUG
    #define NBUKitLogLevel LOG_LEVEL_VERBOSE
#else
    #define NBUKitLogLevel LOG_LEVEL_WARN
#endif

#define LOG_LEVEL_DEF   NBUKitLogLevel
#import <CocoaLumberjack/DDLog.h>

#define NBULogError(frmt, ...)      DDLogError(frmt, ##__VA_ARGS__)
#define NBULogWarn(frmt, ...)       DDLogWarn(frmt, ##__VA_ARGS__)
#define NBULogInfo(frmt, ...)       DDLogInfo(frmt, ##__VA_ARGS__)
#define NBULogDebug(frmt, ...)      DDLogDebug(frmt, ##__VA_ARGS__)
#define NBULogVerbose(frmt, ...)    DDLogVerbose(frmt, ##__VA_ARGS__)
#define NBULogTrace()               NBULogDebug(@"%@", THIS_METHOD)


// c) Else fallback to NSLog
#else

#ifdef DEBUG
    #define LOG_LEVEL 3
#else
    #define LOG_LEVEL 2
#endif

#define THIS_METHOD                 NSStringFromSelector(_cmd)
#define NBULogError(frmt, ...)      do{ if(LOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NBULogWarn(frmt, ...)       do{ if(LOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NBULogInfo(frmt, ...)       do{ if(LOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NBULogDebug(frmt, ...)      do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NBULogVerbose(frmt, ...)    do{ if(LOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NBULogTrace()               NBULogDebug(@"%@", THIS_METHOD)

#endif

This could be extended to other log frameworks allowing app developers to use the one they prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants