2017-12-31

2017-12-31  本文已影响0人  张霸天

// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
//   to endorse or promote products derived from this software without specific
//   prior written permission of Deusty, LLC.

// Disable legacy macros
#ifndef DD_LEGACY_MACROS
    #define DD_LEGACY_MACROS 0
#endif

#import "DDLog.h"

/**
 * This class provides an abstract implementation of a database logger.
 *
 * That is, it provides the base implementation for a database logger to build atop of.
 * All that is needed for a concrete database logger is to extend this class
 * and override the methods in the implementation file that are prefixed with "db_".
 **/
@interface DDAbstractDatabaseLogger : DDAbstractLogger {
    
@protected
    NSUInteger _saveThreshold;
    NSTimeInterval _saveInterval;
    NSTimeInterval _maxAge;
    NSTimeInterval _deleteInterval;
    BOOL _deleteOnEverySave;
    
    BOOL _saveTimerSuspended;
    NSUInteger _unsavedCount;
    dispatch_time_t _unsavedTime;
    // 时间控制的
    dispatch_source_t _saveTimer;
    dispatch_time_t _lastDeleteTime;
    dispatch_source_t _deleteTimer;
}


// 漂亮,每多久记录一次的好方法
/**
 * Specifies how often to save the data to disk.
 * Since saving is an expensive operation (disk io) it is not done after every log statement.
 * These properties allow you to configure how/when the logger saves to disk.
 *
 * A save is done when either (whichever happens first):
 *
 * - The number of unsaved log entries reaches saveThreshold
 * - The amount of time since the oldest unsaved log entry was created reaches saveInterval
 *
 * You can optionally disable the saveThreshold by setting it to zero.
 * If you disable the saveThreshold you are entirely dependent on the saveInterval.
 *
 * You can optionally disable the saveInterval by setting it to zero (or a negative value).
 * If you disable the saveInterval you are entirely dependent on the saveThreshold.
 *
 * It's not wise to disable both saveThreshold and saveInterval.
 *
 * The default saveThreshold is 500.
 * The default saveInterval is 60 seconds.
 **/


// threshold 是临界值的意思,用来批量设置,棒棒的

@property (assign, readwrite) NSUInteger saveThreshold;

/**
 *  See the description for the `saveThreshold` property
 */
@property (assign, readwrite) NSTimeInterval saveInterval;

/**
 * It is likely you don't want the log entries to persist forever.
 * Doing so would allow the database to grow infinitely large over time.
 *
 * The maxAge property provides a way to specify how old a log statement can get
 * before it should get deleted from the database.
 *
 * The deleteInterval specifies how often to sweep for old log entries.
 * Since deleting is an expensive operation (disk io) is is done on a fixed interval.
 *
 * An alternative to the deleteInterval is the deleteOnEverySave option.
 * This specifies that old log entries should be deleted during every save operation.
 *
 * You can optionally disable the maxAge by setting it to zero (or a negative value).
 * If you disable the maxAge then old log statements are not deleted.
 *
 * You can optionally disable the deleteInterval by setting it to zero (or a negative value).
 *
 * If you disable both deleteInterval and deleteOnEverySave then old log statements are not deleted.
 *
 * It's not wise to enable both deleteInterval and deleteOnEverySave.
 *
 * The default maxAge is 7 days.
 * The default deleteInterval is 5 minutes.
 * The default deleteOnEverySave is NO.
 **/
@property (assign, readwrite) NSTimeInterval maxAge;

/**
 *  See the description for the `maxAge` property
 */
@property (assign, readwrite) NSTimeInterval deleteInterval;

/**
 *  See the description for the `maxAge` property
 */
@property (assign, readwrite) BOOL deleteOnEverySave;

/**
 * Forces a save of any pending log entries (flushes log entries to disk).
 **/
- (void)savePendingLogEntries;

/**
 * Removes any log entries that are older than maxAge.
 **/
- (void)deleteOldLogEntries;

@end




// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2016, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
//   to endorse or promote products derived from this software without specific
//   prior written permission of Deusty, LLC.

#import "DDAbstractDatabaseLogger.h"
#import <math.h>


#if !__has_feature(objc_arc)
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif

@interface DDAbstractDatabaseLogger ()

- (void)destroySaveTimer;
- (void)destroyDeleteTimer;

@end

#pragma mark -

@implementation DDAbstractDatabaseLogger

- (instancetype)init {
    if ((self = [super init])) {
        _saveThreshold = 500;
        _saveInterval = 60;           // 60 seconds
        _maxAge = (60 * 60 * 24 * 7); //  7 days
        _deleteInterval = (60 * 5);   //  5 minutes
    }

    return self;
}

- (void)dealloc {
    [self destroySaveTimer];
    [self destroyDeleteTimer];
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Override Me
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (BOOL)db_log:(DDLogMessage *)logMessage {
    // Override me and add your implementation.
    //
    // Return YES if an item was added to the buffer.
    // Return NO if the logMessage was ignored.

    return NO;
}

- (void)db_save {
    // Override me and add your implementation.
}

- (void)db_delete {
    // Override me and add your implementation.
}

- (void)db_saveAndDelete {
    // Override me and add your implementation.
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Private API
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 用来执行保存操作
- (void)performSaveAndSuspendSaveTimer {
    //保存了
    if (_unsavedCount > 0) {
        if (_deleteOnEverySave) {
            [self db_saveAndDelete];
        } else {
            [self db_save];
        }
    }
    // 将没保存设置为0
    // 将没保存的数量设置为0
    _unsavedCount = 0;
    _unsavedTime = 0;

    
    // 如果_有savetime这个线程,并且线程没有被挂起
    // 就把这个线程挂起
    if (_saveTimer && !_saveTimerSuspended) {
        dispatch_suspend(_saveTimer);
        _saveTimerSuspended = YES;
    }
}

// 删除数据
- (void)performDelete {
    if (_maxAge > 0.0) {
        [self db_delete];

        _lastDeleteTime = dispatch_time(DISPATCH_TIME_NOW, 0);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Timers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)destroySaveTimer {
    if (_saveTimer) {
        
        // 用来cancel 线程
        dispatch_source_cancel(_saveTimer);
        // 将_save 重置
        if (_saveTimerSuspended) {
            // Must resume a timer before releasing it (or it will crash)
            dispatch_resume(_saveTimer);
            _saveTimerSuspended = NO;
        }

        #if !OS_OBJECT_USE_OBJC
        dispatch_release(_saveTimer);
        #endif
        _saveTimer = NULL;
    }
}

// 更新timer 的正确方法
- (void)updateAndResumeSaveTimer {
    if ((_saveTimer != NULL) && (_saveInterval > 0.0) && (_unsavedTime > 0.0)) {
        
        // 使用timeinterval 的正确方法
        uint64_t interval = (uint64_t)(_saveInterval * (NSTimeInterval) NSEC_PER_SEC);
        // 设置每一次的savetime 为从unsavedtime 开始每隔interval save 一次
        dispatch_time_t startTime = dispatch_time(_unsavedTime, interval);

        // 使用dispatch_source 开始了
        dispatch_source_set_timer(_saveTimer, startTime, interval, 1ull * NSEC_PER_SEC);
        
        // 开始save timer 这个source
        if (_saveTimerSuspended) {
            dispatch_resume(_saveTimer);
            _saveTimerSuspended = NO;
        }
    }
}

- (void)createSuspendedSaveTimer {
    
    //  初始化sourcetimer
    if ((_saveTimer == NULL) && (_saveInterval > 0.0)) {
        _saveTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue);
        // 漂亮, 什么都不用多写
        dispatch_source_set_event_handler(_saveTimer, ^{ @autoreleasepool {
                                                            [self performSaveAndSuspendSaveTimer];
                                                        } });
        // 使用savetimer suspend 来 做标志位
        _saveTimerSuspended = YES;
    }
}

- (void)destroyDeleteTimer {
    if (_deleteTimer) {
        dispatch_source_cancel(_deleteTimer);
        #if !OS_OBJECT_USE_OBJC
        dispatch_release(_deleteTimer);
        #endif
        _deleteTimer = NULL;
    }
}

- (void)updateDeleteTimer {
    if ((_deleteTimer != NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) {
        uint64_t interval = (uint64_t)(_deleteInterval * (NSTimeInterval) NSEC_PER_SEC);
        dispatch_time_t startTime;
        // 我去标准化流程 😂
        if (_lastDeleteTime > 0) {
            startTime = dispatch_time(_lastDeleteTime, interval);
        } else {
            startTime = dispatch_time(DISPATCH_TIME_NOW, interval);
        }

        dispatch_source_set_timer(_deleteTimer, startTime, interval, 1ull * NSEC_PER_SEC);
    }
}

- (void)createAndStartDeleteTimer {
    if ((_deleteTimer == NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) {
        _deleteTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue);

        if (_deleteTimer != NULL) {
            dispatch_source_set_event_handler(_deleteTimer, ^{ @autoreleasepool {
                                                                  [self performDelete];
                                                              } });

            [self updateDeleteTimer];

            if (_deleteTimer != NULL) {
                dispatch_resume(_deleteTimer);
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Configuration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (NSUInteger)saveThreshold {
    // The design of this method is taken from the DDAbstractLogger implementation.
    // For extensive documentation please refer to the DDAbstractLogger implementation.

    // Note: The internal implementation MUST access the colorsEnabled variable directly,
    // This method is designed explicitly for external access.
    //
    // Using "self." syntax to go through this method will cause immediate deadlock.
    // This is the intended result. Fix it by accessing the ivar directly.
    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.

    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
    // 来吧 耦合吧
    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];

    __block NSUInteger result;

    // 设置都是async, sync是用来读取的,
    // 然后再使用当前的logger queue
    dispatch_sync(globalLoggingQueue, ^{
        dispatch_sync(self.loggerQueue, ^{
            result = _saveThreshold;
        });
    });

    return result;
}

- (void)setSaveThreshold:(NSUInteger)threshold {
    dispatch_block_t block = ^{
        @autoreleasepool {
            // 这里有个细节
            // 先更改save的数值,在使用保存函数
            if (_saveThreshold != threshold) {
                _saveThreshold = threshold;

                // Since the saveThreshold has changed,
                // we check to see if the current unsavedCount has surpassed the new threshold.
                //
                // If it has, we immediately save the log.

                if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) {
                    [self performSaveAndSuspendSaveTimer];
                }
            }
        }
    };

    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
    // For documentation please refer to the DDAbstractLogger implementation.

    if ([self isOnInternalLoggerQueue]) {
        block();
    } else {
        // 漂亮,强制使用 queue 检查
        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
        // 这里所有的操作都在大的loggerqueue中,而且,小的async, 大的也是async
        dispatch_async(globalLoggingQueue, ^{
            dispatch_async(self.loggerQueue, block);
        });
    }
}

- (NSTimeInterval)saveInterval {
    // The design of this method is taken from the DDAbstractLogger implementation.
    // For extensive documentation please refer to the DDAbstractLogger implementation.

    // Note: The internal implementation MUST access the colorsEnabled variable directly,
    // This method is designed explicitly for external access.
    //
    // Using "self." syntax to go through this method will cause immediate deadlock.
    // This is the intended result. Fix it by accessing the ivar directly.
    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.

    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");

    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];

    __block NSTimeInterval result;
    // 只要是设置,就使用sync
    dispatch_sync(globalLoggingQueue, ^{
        dispatch_sync(self.loggerQueue, ^{
            result = _saveInterval;
        });
    });

    return result;
}

- (void)setSaveInterval:(NSTimeInterval)interval {
    dispatch_block_t block = ^{
        @autoreleasepool {
            // C99 recommended floating point comparison macro
            // Read: isLessThanOrGreaterThan(floatA, floatB)
            // 最佳实践
            if (/* saveInterval != interval */ isle99issgreater(_saveInterval, interval)) {
                _saveInterval = interval;

                // There are several cases we need to handle here.
                //
                // 1. If the saveInterval was previously enabled and it just got disabled,
                //    then we need to stop the saveTimer. (And we might as well release it.)
                //
                // 2. If the saveInterval was previously disabled and it just got enabled,
                //    then we need to setup the saveTimer. (Plus we might need to do an immediate save.)
                //
                // 3. If the saveInterval increased, then we need to reset the timer so that it fires at the later date.
                //
                // 4. If the saveInterval decreased, then we need to reset the timer so that it fires at an earlier date.
                //    (Plus we might need to do an immediate save.)

                if (_saveInterval > 0.0) {
                    if (_saveTimer == NULL) {
                        // Handles #2
                        //
                        // Since the saveTimer uses the unsavedTime to calculate it's first fireDate,
                        // if a save is needed the timer will fire immediately.

                        [self createSuspendedSaveTimer];
                        [self updateAndResumeSaveTimer];
                    } else {
                        // Handles #3
                        // Handles #4
                        //
                        // Since the saveTimer uses the unsavedTime to calculate it's first fireDate,
                        // if a save is needed the timer will fire immediately.

                        [self updateAndResumeSaveTimer];
                    }
                } else if (_saveTimer) {
                    // Handles #1

                    [self destroySaveTimer];
                }
            }
        }
    };

    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
    // For documentation please refer to the DDAbstractLogger implementation.

    if ([self isOnInternalLoggerQueue]) {
        block();
    } else {
        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");

        dispatch_async(globalLoggingQueue, ^{
            dispatch_async(self.loggerQueue, block);
        });
    }
}

- (NSTimeInterval)maxAge {
    // The design of this method is taken from the DDAbstractLogger implementation.
    // For extensive documentation please refer to the DDAbstractLogger implementation.

    // Note: The internal implementation MUST access the colorsEnabled variable directly,
    // This method is designed explicitly for external access.
    //
    // Using "self." syntax to go through this method will cause immediate deadlock.
    // This is the intended result. Fix it by accessing the ivar directly.
    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.

    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");

    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];

    __block NSTimeInterval result;

    dispatch_sync(globalLoggingQueue, ^{
        dispatch_sync(self.loggerQueue, ^{
            result = _maxAge;
        });
    });

    return result;
}

- (void)setMaxAge:(NSTimeInterval)interval {
    dispatch_block_t block = ^{
        @autoreleasepool {
            // C99 recommended floating point comparison macro
            // Read: isLessThanOrGreaterThan(floatA, floatB)

            if (/* maxAge != interval */ islessgreater(_maxAge, interval)) {
                NSTimeInterval oldMaxAge = _maxAge;
                NSTimeInterval newMaxAge = interval;

                _maxAge = interval;

                // There are several cases we need to handle here.
                //
                // 1. If the maxAge was previously enabled and it just got disabled,
                //    then we need to stop the deleteTimer. (And we might as well release it.)
                //
                // 2. If the maxAge was previously disabled and it just got enabled,
                //    then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.)
                //
                // 3. If the maxAge was increased,
                //    then we don't need to do anything.
                //
                // 4. If the maxAge was decreased,
                //    then we should do an immediate delete.

                BOOL shouldDeleteNow = NO;

                if (oldMaxAge > 0.0) {
                    if (newMaxAge <= 0.0) {
                        // Handles #1

                        [self destroyDeleteTimer];
                    } else if (oldMaxAge > newMaxAge) {
                        // Handles #4
                        shouldDeleteNow = YES;
                    }
                } else if (newMaxAge > 0.0) {
                    // Handles #2
                    shouldDeleteNow = YES;
                }

                if (shouldDeleteNow) {
                    [self performDelete];

                    if (_deleteTimer) {
                        [self updateDeleteTimer];
                    } else {
                        [self createAndStartDeleteTimer];
                    }
                }
            }
        }
    };

    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
    // For documentation please refer to the DDAbstractLogger implementation.

    if ([self isOnInternalLoggerQueue]) {
        block();
    } else {
        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");

        dispatch_async(globalLoggingQueue, ^{
            dispatch_async(self.loggerQueue, block);
        });
    }
}

- (NSTimeInterval)deleteInterval {
    // The design of this method is taken from the DDAbstractLogger implementation.
    // For extensive documentation please refer to the DDAbstractLogger implementation.

    // Note: The internal implementation MUST access the colorsEnabled variable directly,
    // This method is designed explicitly for external access.
    //
    // Using "self." syntax to go through this method will cause immediate deadlock.
    // This is the intended result. Fix it by accessing the ivar directly.
    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.

    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");

    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];

    __block NSTimeInterval result;

    dispatch_sync(globalLoggingQueue, ^{
        dispatch_sync(self.loggerQueue, ^{
            result = _deleteInterval;
        });
    });

    return result;
}

- (void)setDeleteInterval:(NSTimeInterval)interval {
    dispatch_block_t block = ^{
        @autoreleasepool {
            // C99 recommended floating point comparison macro
            // Read: isLessThanOrGreaterThan(floatA, floatB)

            if (/* deleteInterval != interval */ islessgreater(_deleteInterval, interval)) {
                _deleteInterval = interval;

                // There are several cases we need to handle here.
                //
                // 1. If the deleteInterval was previously enabled and it just got disabled,
                //    then we need to stop the deleteTimer. (And we might as well release it.)
                //
                // 2. If the deleteInterval was previously disabled and it just got enabled,
                //    then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.)
                //
                // 3. If the deleteInterval increased, then we need to reset the timer so that it fires at the later date.
                //
                // 4. If the deleteInterval decreased, then we need to reset the timer so that it fires at an earlier date.
                //    (Plus we might need to do an immediate delete.)

                if (_deleteInterval > 0.0) {
                    if (_deleteTimer == NULL) {
                        // Handles #2
                        //
                        // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate,
                        // if a delete is needed the timer will fire immediately.

                        [self createAndStartDeleteTimer];
                    } else {
                        // Handles #3
                        // Handles #4
                        //
                        // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate,
                        // if a save is needed the timer will fire immediately.

                        [self updateDeleteTimer];
                    }
                } else if (_deleteTimer) {
                    // Handles #1

                    [self destroyDeleteTimer];
                }
            }
        }
    };

    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
    // For documentation please refer to the DDAbstractLogger implementation.

    if ([self isOnInternalLoggerQueue]) {
        block();
    } else {
        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");

        dispatch_async(globalLoggingQueue, ^{
            dispatch_async(self.loggerQueue, block);
        });
    }
}

- (BOOL)deleteOnEverySave {
    // The design of this method is taken from the DDAbstractLogger implementation.
    // For extensive documentation please refer to the DDAbstractLogger implementation.

    // Note: The internal implementation MUST access the colorsEnabled variable directly,
    // This method is designed explicitly for external access.
    //
    // Using "self." syntax to go through this method will cause immediate deadlock.
    // This is the intended result. Fix it by accessing the ivar directly.
    // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.

    NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
    NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");

    dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];

    __block BOOL result;

    dispatch_sync(globalLoggingQueue, ^{
        dispatch_sync(self.loggerQueue, ^{
            result = _deleteOnEverySave;
        });
    });

    return result;
}

- (void)setDeleteOnEverySave:(BOOL)flag {
    dispatch_block_t block = ^{
        _deleteOnEverySave = flag;
    };

    // The design of the setter logic below is taken from the DDAbstractLogger implementation.
    // For documentation please refer to the DDAbstractLogger implementation.

    if ([self isOnInternalLoggerQueue]) {
        block();
    } else {
        dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
        NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");

        dispatch_async(globalLoggingQueue, ^{
            dispatch_async(self.loggerQueue, block);
        });
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Public API
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)savePendingLogEntries {
    dispatch_block_t block = ^{
        @autoreleasepool {
            [self performSaveAndSuspendSaveTimer];
        }
    };

    if ([self isOnInternalLoggerQueue]) {
        block();
    } else {
        dispatch_async(self.loggerQueue, block);
    }
}

- (void)deleteOldLogEntries {
    dispatch_block_t block = ^{
        @autoreleasepool {
            [self performDelete];
        }
    };

    if ([self isOnInternalLoggerQueue]) {
        block();
    } else {
        dispatch_async(self.loggerQueue, block);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark DDLogger
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)didAddLogger {
    // If you override me be sure to invoke [super didAddLogger];

    [self createSuspendedSaveTimer];

    [self createAndStartDeleteTimer];
}

- (void)willRemoveLogger {
    // If you override me be sure to invoke [super willRemoveLogger];

    [self performSaveAndSuspendSaveTimer];

    [self destroySaveTimer];
    [self destroyDeleteTimer];
}

- (void)logMessage:(DDLogMessage *)logMessage {
    if ([self db_log:logMessage]) {
        BOOL firstUnsavedEntry = (++_unsavedCount == 1);

        if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) {
            [self performSaveAndSuspendSaveTimer];
        } else if (firstUnsavedEntry) {
            _unsavedTime = dispatch_time(DISPATCH_TIME_NOW, 0);
            [self updateAndResumeSaveTimer];
        }
    }
}

- (void)flush {
    // This method is invoked by DDLog's flushLog method.
    //
    // It is called automatically when the application quits,
    // or if the developer invokes DDLog's flushLog method prior to crashing or something.

    [self performSaveAndSuspendSaveTimer];
}

@end


上一篇下一篇

猜你喜欢

热点阅读