// create concurrent queue
dispatch_queue_t _queue;
_queue = dispatch_queue_create("cocoa.lumberjack.multiformatter", DISPATCH_QUEUE_CONCURRENT);
// sync concurrent queue 多读,并发执行
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
__block NSString *line = logMessage->_message;
dispatch_sync(_queue, ^{
for (id<DDLogFormatter> formatter in self->_formatters) {
DDLogMessage *message = [self logMessageForLine:line originalMessage:logMessage];
line = [formatter formatLogMessage:message];
if (!line) {
break;
}
}
});
return line;
}
// 多读,并发执行
- (NSArray *)formatters {
__block NSArray *formatters;
dispatch_sync(_queue, ^{
formatters = [self->_formatters copy];
});
return formatters;
}
- (BOOL)isFormattingWithFormatter:(id<DDLogFormatter>)formatter {
__block BOOL hasFormatter;
dispatch_sync(_queue, ^{
hasFormatter = [self->_formatters containsObject:formatter];
});
return hasFormatter;
}
// 异步 独写
- (void)addFormatter:(id<DDLogFormatter>)formatter {
dispatch_barrier_async(_queue, ^{
[self->_formatters addObject:formatter];
});
}
- (void)removeFormatter:(id<DDLogFormatter>)formatter {
dispatch_barrier_async(_queue, ^{
[self->_formatters removeObject:formatter];
});
}
- (void)removeAllFormatters {
dispatch_barrier_async(_queue, ^{
[self->_formatters removeAllObjects];
});
}
并发读,单写 dispatch_barrier_async, dispatch_sync 并发读
// create timer
_saveTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue);
// set event handler
dispatch_source_set_event_handler(_saveTimer, ^{ @autoreleasepool {
[self performSaveAndSuspendSaveTimer];
} });
// start source
dispatch_resume(_deleteTimer);
// source cancel
dispatch_source_cancel(_deleteTimer);
source timer, gcd的定时器实现,可以cancel, 可以 resume, 可以 set event hander 等.
// 监听系统的通知
notify_register_dispatch(kNotifyASLDBUpdate, ¬ifyToken, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int token)
{
// At least one message has been posted; build a search query.
@autoreleasepool
{
aslmsg query = asl_new(ASL_TYPE_QUERY);
char stringValue[64];
if (lastSeenID > 0) {
snprintf(stringValue, sizeof stringValue, "%llu", lastSeenID);
asl_set_query(query, ASL_KEY_MSG_ID, stringValue, ASL_QUERY_OP_GREATER | ASL_QUERY_OP_NUMERIC);
} else {
snprintf(stringValue, sizeof stringValue, "%llu", startTime);
asl_set_query(query, ASL_KEY_TIME, stringValue, ASL_QUERY_OP_GREATER_EQUAL | ASL_QUERY_OP_NUMERIC);
}
[self configureAslQuery:query];
// Iterate over new messages.
aslmsg msg;
aslresponse response = asl_search(NULL, query);
while ((msg = asl_next(response)))
{
[self aslMessageReceived:msg];
// Keep track of which messages we've seen.
lastSeenID = (unsigned long long)atoll(asl_get(msg, ASL_KEY_MSG_ID));
}
asl_release(response);
asl_free(query);
if (_cancel) {
notify_cancel(token);
return;
}
}
});
int notifyToken = 0;
// Can be used to unregister with notify_cancel().
notify_register_dispatch_ 接收系统的通知信息. 可以做进程,线程的处理.
notify_cancel 可以关闭通知
// async 异步操作,并发删除文件,没过block ,都独立触发
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Since we just created a new log file, we may need to delete some old log files
[self deleteOldLogFiles];
});
// create vnode source 监控文件的变化 flags 来确定变化的部分
dispatch_source_vnode_flags_t flags = DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE;
_currentLogFileVnode = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,
(uintptr_t)[_currentLogFileHandle fileDescriptor],
flags,
_loggerQueue);
// set vnode event handler
__weak __auto_type weakSelf = self;
dispatch_source_set_event_handler(_currentLogFileVnode, ^{ @autoreleasepool {
NSLogInfo(@"DDFileLogger: Current logfile was moved. Rolling it and creating a new one");
[weakSelf lt_rollLogFileNow];
} });
// cancel vnode
dispatch_source_t vnode = _currentLogFileVnode;
dispatch_source_set_cancel_handler(_currentLogFileVnode, ^{
dispatch_release(vnode);
});
// start source
dispatch_resume(_currentLogFileVnode);
// cancel source
if (_currentLogFileVnode) {
dispatch_source_cancel(_currentLogFileVnode);
_currentLogFileVnode = NULL;
}
// create timer
_rollingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _loggerQueue);
// cacel source timer
if (_rollingTimer) {
dispatch_source_cancel(_rollingTimer);
_rollingTimer = NULL;
}
// timer hander
__weak __auto_type weakSelf = self;
dispatch_source_set_event_handler(_rollingTimer, ^{ @autoreleasepool {
[weakSelf lt_maybeRollLogFileDueToAge];
} });
// timer cancel
dispatch_source_t theRollingTimer = _rollingTimer;
dispatch_source_set_cancel_handler(_rollingTimer, ^{
dispatch_release(theRollingTimer);
});
// set timer
static NSTimeInterval const kDDMaxTimerDelay = LLONG_MAX / NSEC_PER_SEC;
int64_t delay = (int64_t)(MIN([logFileRollingDate timeIntervalSinceNow], kDDMaxTimerDelay) * (NSTimeInterval) NSEC_PER_SEC);
dispatch_time_t fireTime = dispatch_time(DISPATCH_TIME_NOW, delay);
dispatch_source_set_timer(_rollingTimer, fireTime, DISPATCH_TIME_FOREVER, (uint64_t)kDDRollingLeeway * NSEC_PER_SEC);
// start timer
dispatch_resume(_rollingTimer);
// 串行队列执行任务,保证资源释放安全
- (void)dealloc {
if (self.isOnInternalLoggerQueue) {
[self lt_cleanup];
} else {
dispatch_sync(self.loggerQueue, ^{
[self lt_cleanup];
});
}
}
Source timer 不用说了
source vnode 监控文件, 文件变更时,能收到事件通知.
block 内部执行频繁操作,可以 @autoreleasepool 来辅助优化控制内存
网友评论