Comments (7)
Great question.
Using a technique like [DDLog indent] would run into problems with multithreaded code.
Another alternative would be embedding the indent level in the log message itself. By this, I mean putting the indent level in the DDLogMessage object. This object has a "id tag" variable that is designed to be used for just such a thing. It would entail defining your own macro, but could make things pretty easy.
Let me know what you think, or if you have any questions.
from cocoalumberjack.
Good point. You could associate the indent level with the thread id. I suppose that does affect performance though, for a specific use case.
The macro approach may yield a less than elegant api, but I'll look into it. Thanks.
On Apr 4, 2012, at 7:50 PM, Robbie Hanson wrote:
Great question.
Using a technique like [DDLog indent] would run into problems with multithreaded code.
Another alternative would be embedding the indent level in the log message itself. By this, I mean putting the indent level in the DDLogMessage object. This object has a "id tag" variable that is designed to be used for just such a thing. It would entail defining your own macro, but could make things pretty easy.
Let me know what you think, or if you have any questions.
Reply to this email directly or view it on GitHub:
#28 (comment)
from cocoalumberjack.
I believe the macro approach may yield an elegant api.
Also, for recursive calls, it would be great to take advantage of asynchronous logging.
The end result would look something like this:
DDLogIndent(i, @"Lumberjack is:");
DDLogIndent(++i, @"- Fast");
DDLogIndent(i, @"- Simple");
DDLogIndent(i, @"- Powerful");
DDLogIndent(i--, @"- Flexible");
DDLogIndent(i, @"But don't take my word for it.");
DDLogIndent(i, @"Try it yourself.");
I tested it out in the CustomFormatters example, and got it to spit out this:
CustomFormattersAppDelegate | applicationDidFinishLaunching: @ 42 | Lumberjack is:
CustomFormattersAppDelegate | applicationDidFinishLaunching: @ 43 | - Fast
CustomFormattersAppDelegate | applicationDidFinishLaunching: @ 44 | - Simple
CustomFormattersAppDelegate | applicationDidFinishLaunching: @ 45 | - Powerful
CustomFormattersAppDelegate | applicationDidFinishLaunching: @ 46 | - Flexible
CustomFormattersAppDelegate | applicationDidFinishLaunching: @ 47 | But don't take my word for it.
CustomFormattersAppDelegate | applicationDidFinishLaunching: @ 48 | Try it yourself.
Here's how I did it. There are several macros defined in DDLog.h, but they all boil down to calling a single objective-c class method (that takes all the parameters for creating a DDLogMessage).
So I added a define that looks like this:
#define DDLogIndent(indentLevel, frmt, ...) \
[DDLog log:YES /* Asynchronous */ \
level:ddLogLevel /* Current log level */ \
flag:LOG_FLAG_VERBOSE /* Log if verbose enabled */ \
context:0 /* Normal app context */ \
file:__FILE__ \
function:sel_getName(_cmd) \
line:__LINE__ \
tag:[NSNumber numberWithInt:indentLevel] /* Special sauce*/ \
format:(frmt), ##__VA_ARGS__]
And then I tweaked the formatter to look like this:
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage
{
NSMutableString *str = [NSMutableString stringWithCapacity:32];
[str appendFormat:@"%@ | %s @ %i | ", logMessage.fileName, logMessage->function, logMessage->lineNumber];
NSNumber *indentLevelNumber = (NSNumber *)logMessage->tag;
int indentLevel = [indentLevelNumber intValue];
for (int i = 0; i < indentLevel; i++)
{
[str appendString:@" "];
}
[str appendFormat:@"%@", logMessage->logMsg];
return str;
}
Let me know what you think of this idea.
from cocoalumberjack.
Sorry, got caught up in pressing matters. Thanks for this, Robbie.
It's as I was thinking though; I'm going to need to track the indent variable, which adds to the footprint on other code. Still, it is fast. Thanks again!
from cocoalumberjack.
You're right. For looping, the code works great. For recursion, not so much. So I have a better idea:
Store the indent level in the formatter. You can maintain thread safety by using a dictionary, with the thread ID as the key, and the indent level as the value. But how to tell formatter to indent / unindent? Use the tag! Similar to the example above.
I'll post some example code when I get some time. Swamped next few days.
from cocoalumberjack.
How about something like this:
RecursionFormatter.h
#import <Foundation/Foundation.h>
#import "DDLog.h"
extern id const DDLogIncrementIndentLevel;
extern id const DDLogDecrementIndentLevel;
#define DDLogIndent() \
[DDLog log:YES \
level:0 \
flag:0 \
context:0 \
file:NULL \
function:NULL \
line:0 \
tag:DDLogIncrementIndentLevel \
format:@""]
#define DDLogUnindent() \
[DDLog log:YES \
level:0 \
flag:0 \
context:0 \
file:NULL \
function:NULL \
line:0 \
tag:DDLogDecrementIndentLevel \
format:@""]
@interface RecursionFormatter : NSObject <DDLogFormatter>
@end
RecursionFormatter.m
#import "RecursionFormatter.h"
#import <pthread.h>
id const DDLogIncrementIndentLevel = @"DDLogIncrementIndentLevel";
id const DDLogDecrementIndentLevel = @"DDLogDecrementIndentLevel";
@implementation RecursionFormatter
{
dispatch_queue_t indentQueue;
NSMutableDictionary *indentDict;
}
- (id)init
{
if ((self = [super init]))
{
indentQueue = dispatch_queue_create("TestFormatter", NULL);
indentDict = [[NSMutableDictionary alloc] init];
}
return self;
}
- (NSUInteger)indentLevel:(mach_port_t)threadID
{
__block NSUInteger indentLevel;
dispatch_sync(indentQueue, ^{
NSNumber *key = [NSNumber numberWithUnsignedInt:threadID];
indentLevel = [[indentDict objectForKey:key] unsignedIntegerValue];
NSLog(@"indentLevel: %lu", (unsigned long)indentLevel);
});
return indentLevel;
}
- (void)indent:(mach_port_t)threadID
{
dispatch_async(indentQueue, ^{
NSNumber *key = [NSNumber numberWithUnsignedInt:threadID];
NSUInteger oldIndentLevel = [[indentDict objectForKey:key] unsignedIntegerValue];
NSUInteger newIndentLevel = oldIndentLevel + 1;
NSLog(@"indent : %lu -> %lu", (unsigned long)oldIndentLevel, (unsigned long)newIndentLevel);
[indentDict setObject:[NSNumber numberWithUnsignedInteger:newIndentLevel] forKey:key];
});
}
- (void)unindent:(mach_port_t)threadID
{
dispatch_async(indentQueue, ^{
NSNumber *key = [NSNumber numberWithUnsignedInt:threadID];
NSUInteger oldIndentLevel = [[indentDict objectForKey:key] unsignedIntegerValue];
NSUInteger newIndentLevel = oldIndentLevel > 0 ? oldIndentLevel - 1 : 0;
NSLog(@"unindent: %lu -> %lu", (unsigned long)oldIndentLevel, (unsigned long)newIndentLevel);
[indentDict setObject:[NSNumber numberWithUnsignedInteger:newIndentLevel] forKey:key];
});
}
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage
{
if (logMessage->tag == DDLogIncrementIndentLevel)
{
[self indent:logMessage->machThreadID];
return nil;
}
if (logMessage->tag == DDLogDecrementIndentLevel)
{
[self unindent:logMessage->machThreadID];
return nil;
}
NSMutableString *str = [[NSMutableString alloc] init];
[str appendFormat:@"%@ | ", logMessage.fileName];
NSUInteger indentLevel = [self indentLevel:logMessage->machThreadID];
NSUInteger i;
for (i = 0; i < indentLevel; i++)
{
[str appendString:@" "];
}
[str appendString:logMessage->logMsg];
return str;
}
@end
AppDelegate.m
- (void)recursiveMethod:(NSUInteger)i
{
DDLogIndent();
if (i > 0)
{
DDLogInfo(@"pre-recursion");
[self recursiveMethod:(i-1)];
DDLogInfo(@"post-recursion");
}
DDLogUnindent();
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Setup logging (with our custom formatter)
formatter = [[RecursionFormatter alloc] init];
[[DDTTYLogger sharedInstance] setLogFormatter:formatter];
[DDLog addLogger:[DDTTYLogger sharedInstance]];
[self recursiveMethod:4];
}
from cocoalumberjack.
Very nice! Thanks!
from cocoalumberjack.
Related Issues (20)
- crash in [DDLogMessage initWithFormat:args:level:flag:context:file:function:line:tag:options:timestamp] HOT 3
- Log messages dispatched using the swift-log backend are missing normal swift-log formatting. HOT 1
- The `dynamicLogLevel` isn't taken in account when using `swift-log` HOT 3
- Question about CocoaLumberjack Behavior - Deleting All Files when logFilesDiskQuota is Reached HOT 1
- Deprecated message at DDLogInfo
- Thread running at QOS_CLASS_USER_INTERACTIVE waiting on a lower QoS thread running at QOS_CLASS_BACKGROUND. Investigate ways to avoid priority inversions HOT 2
- Privacy manifest for new sensitive APIs HOT 5
- Race condition when configuring DDLogFileManagerDefault HOT 1
- Library is not visible in ObjC when using SPM HOT 6
- pod 'CocoaLumberjack/Swift' 报错:Function Parameter Count Violation: Function should have 5 parameters or less: it currently has 10 (function_parameter_count) HOT 2
- Bump `IPHONEOS_DEPLOYMENT_TARGET` in podspec to appease Cocoapods on Xcode15 HOT 2
- NSGenericDeallocHandler release crash when calling registeredClasses HOT 1
- CocoaLumberjack v3.8.3 - Privacy Manifest - Missing an expected key: 'NSPrivacyCollectedDataTypes' HOT 3
- Multiple commands produce PrivacyInfo.xcprivacy HOT 8
- DDOSLogger Info, Warning, Debug, and Verbose logs do not appear in Console.app when streaming from iOS simulator. HOT 4
- Add optional custom format specifiers to DDLogMessageFormat HOT 1
- Compilation Error with Xcode 15 during Archive Operation HOT 1
- Confused about DDFileLog。 HOT 2
- When will visionOS be supported
- osLogTypeForLogFlag for FAULT HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cocoalumberjack.