Уровень глобального журнала для CocoaLumberjack

Я использую CocoaLumberjack в проекте iPhone, чтобы зарегистрировать некоторую информацию.

Я следовал руководству по началу работы, и все работает отлично, но есть одна вещь, которая меня беспокоит: кажется, не существует элегантного способа определения уровня журнала для всего приложения. Чтобы это работало, мне нужно определить константу в каждом исходном файле, например так:

static const int ddLogLevel = LOG_LEVEL_VERBOSE;

Итак, есть ли способ определить глобальный уровень журнала для приложения?

Я нашел эту статью на эту тему, но мне все еще нужно добавить #import в каждый файл...

11 ответов

Решение

Я не нашел лучшего способа сделать это, чем объяснил в статье, которую я упомянул в вопросе.

Constant.h

extern int const ddLogLevel;

Constant.m

#import "Constants.h"
#import "DDLog.h"

int const ddLogLevel = LOG_LEVEL_VERBOSE;

Конфигурация логгера

#import "DDLog.h"
#import "DDASLLogger.h"
#import "DDTTYLogger.h"
#import "DDFileLogger.h"

...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

 [DDLog addLogger:[DDASLLogger sharedInstance]];
 [DDLog addLogger:[DDTTYLogger sharedInstance]];

 DDFileLogger *fileLogger = [[DDFileLogger alloc] init]; 
 [DDLog addLogger:fileLogger];
 [fileLogger release];

...

Импортируйте свой класс

#import "DDLog.h"
#import "Constants.h"

...

- (void)someMethod {
 DDLogVerbose(@"Log this message");
}

Вы могли бы использовать #include в вашем файле *.pch, чтобы он автоматически включался во все файлы вашего проекта.

Больше никаких префиксных заголовков, пожалуйста.

Вы не нуждаетесь в теперь не рекомендуется .pch файл, просто включите заголовочный файл, где это необходимо.

Logger.h - CocoaLumberjack 1.9.x

#ifndef Project_Logger_h
#define Project_Logger_h

#if defined(__OBJC__)

#import <CocoaLumberjack/DDLog.h>
extern int ddLogLevel;

#endif

#endif

Logger.m

#import "Logger.h"

int ddLogLevel = LOG_LEVEL_VERBOSE;

Изменения для CocoaLumberjack 2.x

#import <CocoaLumberjack/CocoaLumberjack.h>

int ddLogLevel = DDLogLevelVerbose;

Если синтаксис изменится, когда 2.0 выйдет из бета-версии, прокомментируйте или измените

Пример использования в AppDelegate

#import "AppDelegate.h"

#import "Logger.h"

#import <CocoaLumberjack/DDFileLogger.h>
#import <CocoaLumberjack/DDASLLogger.h>
#import <CocoaLumberjack/DDTTYLogger.h>



@interface AppDelegate ()
@property (strong, nonatomic) DDFileLogger *fileLogger;
@end



@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [DDLog addLogger:[DDASLLogger sharedInstance]];
    [DDLog addLogger:[DDTTYLogger sharedInstance]];

    DDFileLogger *fileLogger = [[DDFileLogger alloc] init];
    fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling
    fileLogger.logFileManager.maximumNumberOfLogFiles = 7;

    [DDLog addLogger:fileLogger];
    self.fileLogger = fileLogger;

    DDLogDebug(@"%s", __PRETTY_FUNCTION__);

    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    DDLogDebug(@"%s", __PRETTY_FUNCTION__);
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    DDLogDebug(@"%s", __PRETTY_FUNCTION__);
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    DDLogDebug(@"%s", __PRETTY_FUNCTION__);
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    DDLogDebug(@"%s", __PRETTY_FUNCTION__);
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    DDLogDebug(@"%s", __PRETTY_FUNCTION__);
}

Чтобы динамически внедрить уровень журнала (например, из файла конфигурации):

1) Создайте новый класс с именем DDLogLevel со следующим кодом:

#import "DDLogLevel.h"
#import "DDLog.h"

@implementation DDLogLevel

static int _ddLogLevel = LOG_LEVEL_VERBOSE;

+ (int)ddLogLevel
{
    return _ddLogLevel;
}

+ (void)ddSetLogLevel:(int)logLevel
{
    _ddLogLevel = logLevel;
}

@end

2) В DDLogLevel.h найдите строку, содержащую следующую инструкцию:

#ifndef LOG_LEVEL_DEF
    #define LOG_LEVEL_DEF ddLogLevel
#endif

И заменить его на:

#ifndef LOG_LEVEL_DEF
    #define LOG_LEVEL_DEF [DDLogLevel ddLogLevel]
#endif

3) Наконец, вызов из вашего процесса инициализации (возможно, из appDelegate) для ddSetLogLevel с желаемым уровнем.

Для тех, кто использует CocoaLumberjackSwift, вы можете просто установить следующую глобальную переменную в любом месте вашего кода:

dynamicLogLevel = .verbose

Обсуждение здесь

Вы можете использовать это в своем файле *.pch, чтобы автоматически получать различные уровни глобального журнала в зависимости от текущей конфигурации сборки.[Для xcode 4+]

#ifdef DEBUG
  static const int ddLogLevel = LOG_LEVEL_VERBOSE;
#else
  static const int ddLogLevel = LOG_LEVEL_WARN;
#endif

или если вам нужен другой уровень журнала для каждого регистратора, вы можете легко добиться этого, используя метод DDLog +addLogger:withLogLevel:.

[DDLog addLogger:[DDASLLogger sharedInstance] withLogLevel:LOG_LEVEL_INFO];
[DDLog addLogger:[DDTTYLogger sharedInstance] withLogLevel:LOG_LEVEL_DEBUG];

Определение уровня ведения журнала в каждом упомянутом вами исходном файле имеет преимущество. Вы можете использовать подробный уровень ведения журнала только для той части, над которой вы сейчас работаете. Для остальной части вы можете использовать другой уровень, как информация, предупреждение, ошибка.

Поделитесь моей конфигурацией для CocoaLumberjack 2.0.0 с global log level и необязательно local log level с сохраненной функцией DynamicLogLevels.

Мое решение включает в себя простой заголовочный файл DSLogging.h (и это аналог), который импортирует CocoaLumberjack.h и определить удобные макросы для настройки файлов, которые используют макросы журнала CocoaLumberjack. Вот как вы должны его использовать:

  1. Импортировать DSLogging.h заголовок (двумя способами):
  2. использование DSLogLevelSetup... макросы для установки уровня журнала для файла. Примечание: в КАЖДОМ исходном файле, который использует ведение журнала, должны быть макросы.

Смотрите документацию внутри для более подробной информации. Скачать суть.

DSLogging.h заголовок:

//
//  Created by DanSkeel on 23.04.15.

#import "CocoaLumberjack.h"

#define DS_LogScopeGlobal extern
#define DS_LogScopeLocal static
#define DS_LogMutableYes
#define DS_LogMutableNo const

#define DS_LogValueGlobal ;
#define DS_LogValueLocal(lvl) = lvl

#define DS_Setup_Log(scope, mutablility, value) scope mutablility DDLogLevel ddLogLevel value

/** To setup loggin enviroment for particular file use one of these macros
 *
 *  @note Use CocoaLumberjack as usual (https://github.com/CocoaLumberjack/CocoaLumberjack/blob/master/Documentation/GettingStarted.md):
 *
 *  1. just import DSLoggin.h in source file instead of CocoaLumberjack.h
 *
 *  2. Use one of these macros to setup loggin enviroment for the file.
 *  Note: there should one of these macros in EACH file that uses CocoaLumberjack macroses.
 *  @example To enable logging for file with globally defined level you can make convinient snippet:
 *  @code
 *  #import "DSLogging.h"
 *  DSLogLevelSetupGlobal
 *  @endcode
 * 
 *  Use @b SetupGlobal to setup files that will use global level from @p DSLogging.m file
 *
 *  Use @b SetupMutableGlobal to be able to change global level at runtime (assign new level to ddLogLevel variable)
 *
 *  Use @b Setup(DDLogLevel) to set local log level
 *
 *  Use @b SetupMutable(DDLogLevel) to be able to modify local level at runtime ((assign new level to ddLogLevel variable))
 *
 *  This approach preserves a lot of CocoaLumberjack advantages. See SO https://stackru.com/a/29837945/991816
 *
 *  @remarks details: these macros just help you define/reference ddLogLevel value. So if you
 *  see warning about <i> undeclared identifier </i> it should remind you to use one of these macros in this file.
 */
extern char optionClickMeToSeePrettyDoc;
#define DSLogLevelSetupMutableGlobal DS_Setup_Log(DS_LogScopeGlobal, DS_LogMutableYes, DS_LogValueGlobal)
#define DSLogLevelSetupGlobal        DS_Setup_Log(DS_LogScopeGlobal, DS_LogMutableNo,  DS_LogValueGlobal)
#define DSLogLevelSetupMutable(lvl)  DS_Setup_Log(DS_LogScopeLocal,  DS_LogMutableYes, DS_LogValueLocal(lvl))
#define DSLogLevelSetup(lvl)         DS_Setup_Log(DS_LogScopeLocal,  DS_LogMutableNo,  DS_LogValueLocal(lvl))

DSLogging.m источник:

//
//  Created by DanSkeel on 23.04.15.

#import "DSLogging.h"

DDLogLevel ddLogLevel = DDLogLevelVerbose;

Почему я думаю, что это хороший подход:

  1. Это немного лучше, чем просто CocoaLumberjack

    • Глобальный уровень (может быть изменяемым)
    • Позволяет "переопределить" глобальный уровень локальным уровнем (может быть изменяемым)
  2. Это не сокращает функции CocoaLumberjack

    • Использует переменную для установки уровня, поэтому ее можно использовать с расширенными функциями CocoaLumberjack.

Я новичок в CocoaLumberjack и могу быть слишком оптимистичен в отношении моего подхода, был бы рад услышать ваших критиков, если я лгу в какой-то момент.

Существует гораздо более простой способ решить эту проблему, вы можете установить уровень журнала в экземпляре Logger:

#ifdef DEBUG
  [DDLog addLogger:[DDTTYLogger sharedInstance] withLevel:DDLogLevelDebug];
#else
  [DDLog addLogger:[DDTTYLogger sharedInstance] withLevel:DDLogLevelError];
#endif

Таким образом, нет необходимости в дополнительном импорте или.pch-файле.

Вот пример динамического ведения журнала, который использует код DSLogging DanSkeels снизу:

GFDPerson.h

#import <Foundation/Foundation.h>

@interface GFDPerson : NSObject{
@protected
    NSArray         *pLogLevelNames;
    NSArray         *pLogLevelKeys;
    NSDictionary    *pLogLevels;
}

-(void)logPerson;
-(void)setLogLevel:(NSUInteger)logLevel;

@end

GFDPerson.m

#import "GFDPerson.h"
#import "DSLogging.h"

DSLogLevelSetupMutable(DDLogLevelWarning);

@implementation GFDPerson

-(id)init{
    if (self = [super init]) {
        pLogLevelNames = [[NSArray alloc] initWithObjects:
                          @"no logging",
                          @"only errors",
                          @"errors and warnings",
                          @"errors, warnings and infos",
                          @"verbose",
                          nil];

        pLogLevelKeys = [[NSArray alloc] initWithObjects:
                         [[NSNumber numberWithInteger:DDLogLevelOff]stringValue],
                         [[NSNumber     numberWithInteger:DDLogLevelError]stringValue],
                         [[NSNumber     numberWithInteger:DDLogLevelWarning]stringValue],
                         [[NSNumber     numberWithInteger:DDLogLevelInfo]stringValue],
                         [[NSNumber     numberWithInteger:DDLogLevelVerbose]stringValue],
                         nil];

        pLogLevels = [[NSDictionary alloc]initWithObjects:pLogLevelNames
                                                  forKeys:pLogLevelKeys];

        return self;
    }
    return nil;
}

-(void)setLogLevel:(NSUInteger)logLevel{
    ddLogLevel = logLevel;
}

-(void)logPerson{

    NSLog(@"Person is logging with Loglevel: %@",[pLogLevels valueForKey:    [[NSNumber numberWithInteger:ddLogLevel]stringValue]]);
    DDLogVerbose(@"Person log verbose");
    DDLogInfo(@"Person log info");
    DDLogWarn(@"Person log warning");
    DDLogError(@"Person log error");
    DDLogDebug(@"Person log debug");
}

@end

main.m

#import <Foundation/Foundation.h>
#import "DSLogging.h"
#import "GFDPerson.h"

DSLogLevelSetupMutable(DDLogLevelError);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        [DDLog addLogger:[DDASLLogger sharedInstance]];
        [DDLog addLogger:[DDTTYLogger sharedInstance]];

        ddLogLevel = DDLogLevelWarning;
        NSLog(@"Warning:");
        DDLogWarn(@"WARNING LOG!");
        DDLogError(@"ERROR LOG!");
        DDLogVerbose(@"VERBOSE LOG!");

        ddLogLevel = DDLogLevelError;
        NSLog(@"Error:");
        DDLogWarn(@"WARNING LOG!");
        DDLogError(@"ERROR LOG!");
        DDLogVerbose(@"VERBOSE LOG!");

        ddLogLevel = DDLogLevelOff;
        NSLog(@"Off:");
        DDLogWarn(@"WARNING LOG!");
        DDLogError(@"ERROR LOG!");
        DDLogVerbose(@"VERBOSE LOG!");

        ddLogLevel = DDLogLevelVerbose;
        NSLog(@"Verbose:");
        DDLogWarn(@"WARNING LOG!");
        DDLogError(@"ERROR LOG!");
        DDLogVerbose(@"VERBOSE LOG!");

        ddLogLevel = DDLogLevelOff;
        GFDPerson *personA = [[GFDPerson alloc] init];
        [personA logPerson];

        [personA setLogLevel:DDLogLevelVerbose];
        [personA logPerson];

        [personA setLogLevel:DDLogLevelError];
        [personA logPerson];

    }
    return 0;
}

вывод этого кода:

Warning:
WARNING LOG!
ERROR LOG!
Error:
ERROR LOG!
Off:
Verbose:
WARNING LOG!
ERROR LOG!
VERBOSE LOG!
Person is logging with Loglevel: errors and warnings
Person log warning
Person log error
Person is logging with Loglevel: verbose
Person log verbose
Person log info
Person log warning
Person log error
Person log debug
Person is logging with Loglevel: only errors
Person log error

Пожалуйста, прокомментируйте, если я что-то неправильно понял или неправильно использовал...

То, как я это сделал, было вдохновлено этим ответом... однако, так я сделал это по-другому, чтобы иметь как глобальный уровень журнала, так и иметь возможность переопределять глобальный уровень журнала в каждом файле, если я так выбрал:

  • Вместо вызова файла Constants.h Я назвал это GlobalDebugLevel.h, Это связано с тем, что не имеет смысла включать какие-либо другие глобальные константы в этот файл, если только вы действительно не всегда будете использовать глобальный уровень отладки и не будете использовать его для определенных уровней журнала.
  • В файлах, которые я хочу иметь свой собственный уровень журнала.. Я просто закомментирую `#import "GlobalLogLevel.h"и затем добавлю что-то вроде этого:

static const int ddLogLevel = LOG_LEVEL_VERBOSE;

и все счастливы:)

PS это .pch бесплатное решение.. изначально я попробовал это, но потом компилятор будет жаловаться, что ddLogLevel уже определено всякий раз, когда я хочу переопределить его на уровне файла

Есть пример приложения, включенного в CocoaLumberjack, который показывает, как установить глобальный уровень журнала, который вы можете найти здесь https://github.com/robbiehanson/CocoaLumberjack/tree/master/Xcode/GlobalLogLevel

Как ответил FreeAsInBeer, вы можете определить эту константу в файле.pch. Вы можете сделать это в файле.pch.

// include Lumberjack header file 
#import <Lumberjack/Lumberjack.h>

// define ddLogLevel constant
static const int ddLogLevel = LOG_LEVEL_VERBOSE;

Я мой инструмент, я создаю новый заголовочный файл (например, mylog.h) для пользовательских настроек Lumberjack. таким образом, я использую #import заявление в моем файле.pch для включения mylog.h. Этот пользовательский заголовочный файл может понравиться.

// include Lumberjack header file
#import "Lumberjack.h" 

#undef ZEKit_LOG_LEVEL
#if defined (DEBUG) && (DEBUG == 1)
#define ZEKit_LOG_LEVEL LOG_LEVEL_VERBOSE
#else
#define ZEKit_LOG_LEVEL LOG_LEVEL_WARN
#endif

static const int ddLogLevel = ZEKit_LOG_LEVEL;

// ... Other custom settings
Другие вопросы по тегам