【问题标题】:Global log level for CocoaLumberjackCocoaLumberjack 的全局日志级别
【发布时间】:2011-07-04 08:01:18
【问题描述】:

我在一个 iPhone 项目中使用CocoaLumberjack 来记录一些信息。

我关注了the Getting started guide,一切正常,但有一件事让我很头疼:似乎没有一种优雅的方式来为整个应用程序定义日志级别。为了使它工作,我需要在每个源文件中定义一个常量,如下所示:

static const int ddLogLevel = LOG_LEVEL_VERBOSE;

那么,有没有办法为应用程序定义一个全局日志级别?

我在这个主题上找到了this article,但我仍然需要在每个文件中添加一个#import...

【问题讨论】:

    标签: ios objective-c logging cocoalumberjack


    【解决方案1】:

    您可以在 *.pch 文件中使用 #include 语句,以便它自动包含在您的所有项目文件中。

    【讨论】:

    • Also - 要基于每个文件进行自定义,请将 ddLogLevel 更改为非常量,并将其设置在特定文件的类 +initialize 方法中(这是因为每个 .m 文件都有自己的静态 ddLogLevel 变量)。注意:类可能会调用其父类的 +initialize 方法,因此为避免潜在的错误,请在方法中使用if (self == [ClassName self])
    • 问题在于 Xcode 项目中默认不再提供 .pch 文件。您可能应该认为它们已被弃用。
    【解决方案2】:

    我没有找到比我在问题中提到的the article 中解释的更好的方法。

    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");
    }
    

    【讨论】:

    • 有没有办法用这个做动态日志记录?
    • 请避免答案的唯一来源是外部链接。至少引用资源的要点,以免链接失效。
    • 我知道你在做什么@Marcos Crispino.. 但我猜这只有在Constants.h 中定义的唯一常量是日志常量时才有效(即,而不是全部您在该文件中的全局常量).. 在这种情况下,名称 Constants.h 具有误导性,因为它特定于日志级别.. 我将其称为 GlobalLogLevel.h 或更准确地描述和限制此范围的名称文件
    • 无论如何,我根据你的创建了自己的solution,这增加了能够基于每个文件覆盖全局日志级别的好处
    【解决方案3】:

    请不要再添加前缀标题。

    您不需要现在已弃用的.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
    

    记录器.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__);
    }
    

    【讨论】:

    • 在 CocoaLumberjack 2.0 中,ddLogLevel 的类型更改为 DDLogLevel (github.com/CocoaLumberjack/CocoaLumberjack)。所以应该是extern DDLogLevel ddLogLevel;
    • 预编译头文件究竟是什么时候被弃用的?这似乎有点误导。如果使用得当,它们没有任何问题。
    • 出于充分的理由,它们已从 Xcode 6 中的项目默认设置中删除。我相信当时 Chris Lattner 甚至提到那年的 WWDC 是一个需要放弃的坏主意
    • @Greg 总之,正如其他地方所写的那样,PCH 是一种过度使用的拐杖,不需要它们,Apple 将它们从默认项目中删除以阻止/终止它们的使用。模块解决了一个合法用例,即导入 Foundation。最后,您始终可以建立一个全局标头,但随后您将从事全局业务。当您使用它时,您可以在 AppDelegate 中填充大量代码。
    【解决方案4】:

    您可以在 *.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];
    

    在您提到的每个源文件中定义日志级别是有好处的。您可以仅对当前正在处理的部分使用详细日志记录级别。对于其余部分,您可以使用其他级别,如信息、警告、错误。

    【讨论】:

    • .pch 不应使用,它们已被弃用
    【解决方案5】:

    为了动态注入日志级别(例如,从配置文件):

    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。

    【讨论】:

      【解决方案6】:

      对于使用 CocoaLumberjackSwift 的用户,您只需在代码中的任意位置设置以下全局变量:

      dynamicLogLevel = .verbose
      

      Discussion here

      【讨论】:

        【解决方案7】:

        使用global log level 和可选的local log level 与保留的DynamicLogLevels feature 共享我对CocoaLumberjack 2.0.0 的配置。

        我的解决方案包括简单的头文件 DSLogging.h(和它的对应),它导入 CocoaLumberjack.h 并定义方便的宏来设置使用 CocoaLumberjack 日志宏的文件。以下是您应该如何使用它:

        1. 导入DSLogging.h标头(两种方式):
        2. 使用DSLogLevelSetup... 宏来设置文件的日志级别。注意:每个源文件中都应该有使用日志记录的宏。

        有关详细信息,请参阅内部文档。 Download gist.

        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 好一点

          • 全局级别(可以是可变的)
          • 允许您按本地级别“覆盖”全局级别(可以是可变的)
        2. 它不会削减 CocoaLumberjack 的功能

          • 使用变量设置级别,因此可以与 CocoaLumberjack 的高级功能一起使用。

        我是 CocoaLumberjack 的新手,我可能对我的方法过于乐观,如果我在某个时候撒谎,我会很高兴听到你的批评。

        【讨论】:

          【解决方案8】:

          我这样做的方式是受到this 答案的启发。但是这就是我不同的做法,以便我可以同时拥有全局级别的日志级别能够覆盖全局如果我选择了每个文件中的日志级别:

          • 我没有将文件称为Constants.h,而是将其称为GlobalDebugLevel.h。这是因为在此文件中包含任何其他全局常量没有意义,除非您真的始终使用全局调试级别并且不使用文件特定的日志级别。
          • 在我想要拥有自己的日志级别的文件中。我只需注释掉 `#import "GlobalLogLevel.h",然后包含以下内容:

          static const int ddLogLevel = LOG_LEVEL_VERBOSE;

          每个人都很高兴:)

          附言这是一个.pch 免费解决方案.. 最初我尝试过,但编译器会抱怨ddLogLevel 已经定义,每当我想在文件级别覆盖它时

          【讨论】:

            【解决方案9】:

            有一个更简单的方法可以解决这个问题,你可以在 Logger 实例化时设置日志级别:

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

            因此不需要额外的导入或 .pch 文件。

            【讨论】:

            【解决方案10】:

            这是一个动态日志记录示例,它使用下面的 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
            

            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
            

            请发表评论,如果我误解或误用了什么......

            【讨论】:

              【解决方案11】:

              CocoaLumberjack 包含一个示例应用程序,它展示了如何设置全局日志级别,您可以在此处找到 https://github.com/robbiehanson/CocoaLumberjack/tree/master/Xcode/GlobalLogLevel

              【讨论】:

              • 请避免答案的唯一来源是外部链接。至少引用资源的要点,以免链接失效。
              【解决方案12】:

              正如 FreeAsInBeer 所回答的,您可以在 .pch 文件中定义此常量。您可以在 .pch 文件中这样做。

              // include Lumberjack header file 
              #import <Lumberjack/Lumberjack.h>
              
              // define ddLogLevel constant
              static const int ddLogLevel = LOG_LEVEL_VERBOSE;
              

              我是我的工具,我为自定义 Lumberjack 设置创建了一个新的头文件(例如 mylog.h)。这样,我在我的.pch 文件中使用#import 语句来包含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
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-01-13
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多