Глобальный уровень журнала для CocoaLumberjack

Я использую CocoaLumberjack в проекте iPhone для регистрации некоторой информации.

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

static const int ddLogLevel = LOG_LEVEL_VERBOSE;

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

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


person Marcos Crispino    schedule 25.02.2011    source источник


Ответы (12)


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

person FreeAsInBeer    schedule 01.03.2011
comment
Кроме того, для настройки для каждого файла измените ddLogLevel на неконстантный и установите его в методе +initialize класса конкретного файла (это работает, потому что каждый файл .m получает свою собственную статическую переменную ddLogLevel). Примечание. Классы могут вызывать метод +initialize своего суперкласса, поэтому во избежание потенциальных ошибок используйте if (self == [ClassName self]) в методе. - person Danra; 23.06.2014
comment
Проблема в том, что файлы .pch больше не предоставляются в проектах Xcode по умолчанию. Вы, вероятно, должны считать их устаревшими. - person Cameron Lowell Palmer; 13.11.2014

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

Константа.h

extern int const ddLogLevel;

Константа.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");
}
person Marcos Crispino    schedule 07.03.2011
comment
Есть ли способ сделать динамическое ведение журнала с этим? - person Tejaswi Yerukalapudi; 07.05.2013
comment
Пожалуйста, избегайте ответов, в которых единственным источником информации является внешняя ссылка. Хотя бы цитируйте существенные моменты ресурса, во избежание загнивания ссылок. - person Bakuriu; 28.02.2014
comment
Я вижу, что вы делаете, @Marcos Crispino.. но я предполагаю, что это будет работать только в том случае, если единственная константа, определенная в Constants.h, является константой ведения журнала (т.е. в отличие от наличия всех ваших глобальных констант в этом файле) .. в в этом случае имя Constants.h вводит в заблуждение, поскольку оно относится к уровню журнала. Я бы назвал его GlobalLogLevel.h или что-то, что более точно описывает и ограничивает объем этого файла. - person abbood; 12.01.2015
comment
в любом случае, я как бы создал свое собственное решение на основе вашего, что дает возможность переопределить глобальный уровень журнала на на файловой основе - person abbood; 12.01.2015

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

Вам не нужен уже устаревший файл .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

Логгер.м

#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__);
}
person Cameron Lowell Palmer    schedule 13.11.2014
comment
В CocoaLumberjack 2.0 тип ddLogLevel изменен на DDLogLevel (github.com/CocoaLumberjack/CocoaLumberjack) . Так и должно быть extern DDLogLevel ddLogLevel; - person franklsf95; 18.03.2015
comment
Когда именно предварительно скомпилированный заголовок устарел? Это кажется немного вводящим в заблуждение. В них нет ничего плохого, если их правильно использовать. - person Greg; 02.02.2017
comment
Они были удалены из значений проекта по умолчанию в Xcode 6 по уважительной причине. Я полагаю, что в то время Крис Латтнер даже упомянул на WWDC в том году плохую идею, от которой нужно было отказаться. - person Cameron Lowell Palmer; 02.02.2017
comment
@Greg Итак, вкратце, как было написано в другом месте, PCH был чрезмерно используемым костылем, в них нет необходимости, и Apple удалила их из проектов по умолчанию, чтобы воспрепятствовать / прекратить их использование. Модули разрешили единственный допустимый вариант использования — импорт Foundation. В конце концов, вы всегда можете установить глобальный заголовок, но тогда вам придется заниматься глобальными переменными. Пока вы этим занимаетесь, вы можете наполнить AppDelegate значительное количество кода. - person Cameron Lowell Palmer; 03.02.2017

Вы можете использовать это в файле *.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];

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

person DareDevil    schedule 09.12.2013
comment
.pch не следует использовать, они устарели - person LightMan; 08.10.2015

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

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 с желаемым уровнем.

person IdoT    schedule 30.04.2014

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

dynamicLogLevel = .verbose

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

person Jamie McDaniel    schedule 26.07.2020

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

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

  1. Import DSLogging.h header (two ways):
  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://stackoverflow.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

    • Global level (can be mutable)
    • Позволяет вам «переопределить» глобальный уровень локальным уровнем (может быть изменен)
  2. Это не сокращает функции CocoaLumberjack.

    • Uses variable to set level, so it can be used with advanced features of CocoaLumberjack.

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

person DanSkeel    schedule 24.04.2015

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

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

static const int ddLogLevel = LOG_LEVEL_VERBOSE;

и все довольны :)

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

person abbood    schedule 12.01.2015

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

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

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

person OliverD    schedule 22.05.2015
comment
Но все равно у вас будет эта ошибка: DDLogInfo(@test info); -> Использование необъявленного идентификатора «ddLogLevel» - person LightMan; 08.10.2015
comment
Это работает с версией 2.0.0, обновление до 2.0.1 ломает это решение. Это обсуждается здесь: github.com/CocoaLumberjack/CocoaLumberjack/issues/542 - person OliverD; 09.10.2015

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

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

основной.м

#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

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

person user808667    schedule 06.06.2015

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

person PaulCapestany    schedule 01.02.2012
comment
Пожалуйста, избегайте ответов, в которых единственным источником информации является внешняя ссылка. Хотя бы цитируйте существенные моменты ресурса, во избежание загнивания ссылок. - person electronix384128; 22.04.2014

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

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

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

Я использую свой инструмент, я создаю новый файл заголовка (например, mylog.h) для пользовательских настроек дровосека. таким образом, я использую оператор #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
person ZwEin    schedule 04.06.2014