ios - Nivel de registro global para CocoaLumberjack
objective-c logging (11)
No más encabezados de prefijo, por favor.
No necesita el archivo .pch
ahora en desuso, simplemente incluya un archivo de encabezado donde sea necesario.
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;
Cambios para CocoaLumberjack 2.x
#import <CocoaLumberjack/CocoaLumberjack.h>
int ddLogLevel = DDLogLevelVerbose;
Si la sintaxis cambia cuando 2.0 está fuera de beta, coméntelo o edítelo.
Ejemplo de uso en 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__);
}
Estoy usando CocoaLumberjack en un proyecto de iPhone, para registrar algo de información.
He seguido la guía de introducción y todo funciona bien, pero hay una cosa que me molesta: no parece haber una forma elegante de definir un nivel de registro para toda la aplicación. Para que funcione, necesito definir una constante en cada archivo fuente, como este:
static const int ddLogLevel = LOG_LEVEL_VERBOSE;
Entonces, ¿hay alguna manera de definir un nivel de registro global para la aplicación?
Encontré este artículo sobre el tema, pero aún necesito agregar un #import en cada archivo ...
Aquí hay un ejemplo de registro dinámico, que utiliza el código DanSkeels DSLogging de abajo:
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;
}
salida de este código:
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
Por favor, comenten, si malinterpreté o mal uso algo ...
Como respondió FreeAsInBeer, puede definir esta constante en el archivo .pch. Puede hacer esto en el archivo .pch.
// include Lumberjack header file
#import <Lumberjack/Lumberjack.h>
// define ddLogLevel constant
static const int ddLogLevel = LOG_LEVEL_VERBOSE;
Soy mi implemento, creo un nuevo archivo de encabezado (por ejemplo, mylog.h) para configuraciones personalizadas de Lumberjack. de esta manera, uso la instrucción # #import
en mi archivo .pch para incluir mylog.h. A este archivo de encabezado personalizado le puede gustar esto.
// 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
Comparta mi configuración para CocoaLumberjack 2.0.0 con global log level
y local log level
opcional con la característica preservada DynamicLogLevels .
Mi solución incluye el archivo de encabezado simple DSLogging.h
(y su homólogo) que importa CocoaLumberjack.h
y define macros de conveniencia para configurar los archivos que usan las macros de registro CocoaLumberjack. Aquí es cómo debes usarlo:
- Importar encabezado
DSLogging.h
(dos formas):- Importe en cada archivo que use CocoaLumberjack. Tal como lo propone la documentación del framework nativo .
- Importe en
.pch
archivo.pch
una vez. Considera esto antes de ir por este camino.
- Use
DSLogLevelSetup...
macros para establecer el nivel de registro para el archivo. Nota: debe haber macros en CADA archivo fuente que utiliza el registro.
Ver documentación adentro para más detalles. Descargar gist .
DSLogging.h
encabezado:
//
// 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://.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
fuente:
//
// Created by DanSkeel on 23.04.15.
#import "DSLogging.h"
DDLogLevel ddLogLevel = DDLogLevelVerbose;
Por qué creo que es un buen enfoque:
Es un poco mejor que solo CocoaLumberjack
- Nivel global (puede ser mutable)
- Le permite "anular" el nivel global por nivel local (puede ser mutable)
No corta las funciones CocoaLumberjack
- Utiliza el nivel variable para establecer, por lo que se puede utilizar con funciones avanzadas de CocoaLumberjack.
Soy nuevo en CocoaLumberjack y puedo ser demasiado optimista sobre mi enfoque, estaría feliz de escuchar a tus críticos si miro en algún momento.
Hay una aplicación de ejemplo incluida con CocoaLumberjack que muestra cómo establecer un nivel de registro global que puede encontrar aquí https://github.com/robbiehanson/CocoaLumberjack/tree/master/Xcode/GlobalLogLevel
Hay una manera mucho más fácil de resolver esto, puede establecer el nivel de registro en la instanciación de Logger:
#ifdef DEBUG
[DDLog addLogger:[DDTTYLogger sharedInstance] withLevel:DDLogLevelDebug];
#else
[DDLog addLogger:[DDTTYLogger sharedInstance] withLevel:DDLogLevelError];
#endif
Entonces no hay necesidad de importaciones adicionales o archivo .pch.
La forma en que lo hice se inspiró en this respuesta. Sin embargo, así es como lo hice de manera diferente para poder tener un nivel de registro global y poder anular el nivel de registro global dentro de cada archivo si así lo elegí:
- En lugar de llamar al archivo
Constants.h
lo llaméGlobalDebugLevel.h
. Esto se debe a que no tiene sentido incluir otras constantes globales en este archivo, a menos que realmente siempre use el nivel de depuración global y no tenga uso para los niveles de registro específicos del archivo. - En los archivos que quiero tener es su propio nivel de registro. Simplemente comento el `#import ''GlobalLogLevel.h" y luego incluyo algo como esto:
static const int ddLogLevel = LOG_LEVEL_VERBOSE;
y todos están felices :)
ps esta es una solución libre de .pch
.. Inicialmente lo intenté pero luego el compilador se quejaría de que ddLogLevel
ya está definido siempre que quisiera sobrescribirlo en un nivel de archivo
No encontré una manera mejor de hacerlo que la explicada en el artículo que mencioné en la pregunta.
Constant.h
extern int const ddLogLevel;
Constant.m
#import "Constants.h"
#import "DDLog.h"
int const ddLogLevel = LOG_LEVEL_VERBOSE;
Configuración del registrador
#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];
...
Importa tu clase
#import "DDLog.h"
#import "Constants.h"
...
- (void)someMethod {
DDLogVerbose(@"Log this message");
}
Para inyectar dinámicamente el nivel de registro (por ejemplo, desde el archivo de configuración):
1) Crea una nueva clase llamada DDLogLevel con el siguiente código:
#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) En DDLogLevel.h, busque la fila que contiene la siguiente declaración:
#ifndef LOG_LEVEL_DEF
#define LOG_LEVEL_DEF ddLogLevel
#endif
Y reemplázalo con:
#ifndef LOG_LEVEL_DEF
#define LOG_LEVEL_DEF [DDLogLevel ddLogLevel]
#endif
3) Finalmente, llame desde su proceso de inicialización (quizás desde appDelegate) a ddSetLogLevel con el nivel deseado.
Puede usar esto en su archivo * .pch para obtener automáticamente diferentes niveles de registro global dependiendo de su configuración de compilación actual. [Para xcode 4+]
#ifdef DEBUG
static const int ddLogLevel = LOG_LEVEL_VERBOSE;
#else
static const int ddLogLevel = LOG_LEVEL_WARN;
#endif
o Si necesita un nivel de registro diferente para cada registrador, puede lograrlo fácilmente usando el método DDLog + addLogger: withLogLevel :.
[DDLog addLogger:[DDASLLogger sharedInstance] withLogLevel:LOG_LEVEL_INFO];
[DDLog addLogger:[DDTTYLogger sharedInstance] withLogLevel:LOG_LEVEL_DEBUG];
Definir un nivel de registro en cada archivo fuente que mencionó tiene un beneficio. Puede usar el nivel de registro detallado solo para la parte en la que está trabajando actualmente. Para la parte de descanso, puede usar otro nivel como información, advertir, error.
Puede usar una instrucción #include
en su archivo * .pch para que se incluya automáticamente en todos los archivos de su proyecto.