motion-yapper 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -2
- data/.travis.yml +2 -0
- data/Gemfile +1 -0
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/lib/motion-yapper.rb +1 -0
- data/lib/yapper.rb +3 -5
- data/lib/yapper/config.rb +2 -0
- data/lib/yapper/db.rb +105 -40
- data/lib/yapper/document.rb +7 -4
- data/lib/yapper/document/callbacks.rb +0 -7
- data/lib/yapper/document/{persistance.rb → persistence.rb} +27 -21
- data/lib/yapper/document/relation.rb +29 -22
- data/lib/yapper/document/selection.rb +122 -54
- data/lib/yapper/extensions.rb +12 -24
- data/lib/yapper/settings.rb +43 -0
- data/lib/yapper/timestamps.rb +2 -0
- data/lib/yapper/version.rb +1 -1
- data/{yapper.gemspec → motion-yapper.gemspec} +0 -0
- data/spec/integration/{where_spec.rb → criteria_spec.rb} +78 -10
- data/spec/integration/db_spec.rb +70 -0
- data/spec/integration/defaults_spec.rb +37 -0
- data/spec/integration/extensions_spec.rb +14 -0
- data/spec/integration/{persistance_spec.rb → persistence_spec.rb} +0 -0
- data/spec/integration/relation_spec.rb +4 -4
- data/vendor/Podfile.lock +9 -11
- data/vendor/Pods/.build/libPods-CocoaLumberjack.a +0 -0
- data/vendor/Pods/.build/libPods-NSData+MD5Digest.a +0 -0
- data/vendor/Pods/.build/libPods-YapDatabase.a +0 -0
- data/vendor/Pods/.build/libPods.a +0 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h +4 -4
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h +14 -14
- data/vendor/Pods/{CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.h → BuildHeaders/CocoaLumberjack/DDContextFilterLogFormatter.h} +6 -8
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/{DispatchQueueLogFormatter.h → DDDispatchQueueLogFormatter.h} +18 -6
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h +67 -32
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog+LOGV.h +99 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog.h +98 -65
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDMultiFormatter.h +30 -0
- data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h +39 -25
- data/vendor/Pods/BuildHeaders/YapDatabase/NSDictionary+YapDatabase.h +8 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapCache.h +1 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapCollectionKey.h +3 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabase.h +4 -4
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseConnection.h +21 -19
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseDefaults.h +1 -1
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionPrivate.h +35 -31
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredView.h +8 -35
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewPrivate.h +0 -2
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTransaction.h +17 -17
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTypes.h +32 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchPrivate.h +8 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabasePrivate.h +43 -21
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationship.h +35 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipConnection.h +29 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdge.h +163 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdgePrivate.h +79 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipNode.h +99 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipOptions.h +59 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipPrivate.h +125 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipTransaction.h +384 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndex.h +49 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +10 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexSetupPrivate.h +18 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseTransaction.h +131 -21
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseView.h +48 -107
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewChange.h +2 -2
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewConnection.h +1 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewMappings.h +17 -0
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewOptions.h +10 -3
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPrivate.h +18 -1
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTransaction.h +75 -24
- data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTypes.h +99 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h +4 -4
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m +51 -50
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h +14 -14
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m +546 -546
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h +67 -32
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m +1093 -907
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog+LOGV.h +99 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.h +98 -65
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.m +873 -748
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h +39 -25
- data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m +1284 -1243
- data/vendor/Pods/{BuildHeaders/CocoaLumberjack/ContextFilterLogFormatter.h → CocoaLumberjack/Lumberjack/Extensions/DDContextFilterLogFormatter.h} +6 -8
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/{ContextFilterLogFormatter.m → DDContextFilterLogFormatter.m} +70 -70
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/{DispatchQueueLogFormatter.h → DDDispatchQueueLogFormatter.h} +18 -6
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDDispatchQueueLogFormatter.m +253 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.h +30 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.m +127 -0
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/README.txt +1 -1
- data/vendor/Pods/CocoaLumberjack/README.markdown +52 -15
- data/vendor/Pods/Headers/CocoaLumberjack/DDASLLogger.h +4 -4
- data/vendor/Pods/Headers/CocoaLumberjack/DDAbstractDatabaseLogger.h +14 -14
- data/vendor/Pods/Headers/CocoaLumberjack/{ContextFilterLogFormatter.h → DDContextFilterLogFormatter.h} +6 -8
- data/vendor/Pods/Headers/CocoaLumberjack/{DispatchQueueLogFormatter.h → DDDispatchQueueLogFormatter.h} +18 -6
- data/vendor/Pods/Headers/CocoaLumberjack/DDFileLogger.h +67 -32
- data/vendor/Pods/Headers/CocoaLumberjack/DDLog+LOGV.h +99 -0
- data/vendor/Pods/Headers/CocoaLumberjack/DDLog.h +98 -65
- data/vendor/Pods/Headers/CocoaLumberjack/DDMultiFormatter.h +30 -0
- data/vendor/Pods/Headers/CocoaLumberjack/DDTTYLogger.h +39 -25
- data/vendor/Pods/Headers/YapDatabase/YapCollectionKey.h +3 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabase.h +4 -4
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnection.h +21 -19
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredView.h +8 -35
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTransaction.h +17 -17
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTypes.h +32 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationship.h +35 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipConnection.h +29 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipEdge.h +163 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipNode.h +99 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipOptions.h +59 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipTransaction.h +384 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndex.h +49 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseTransaction.h +131 -21
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseView.h +48 -107
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChange.h +2 -2
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewConnection.h +1 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappings.h +17 -0
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewOptions.h +10 -3
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTransaction.h +75 -24
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTypes.h +99 -0
- data/vendor/Pods/Headers/____Pods-CocoaLumberjack-prefix.h +2 -0
- data/vendor/Pods/Headers/____Pods-environment.h +15 -15
- data/vendor/Pods/Manifest.lock +9 -11
- data/vendor/Pods/Pods-CocoaLumberjack-Private.xcconfig +1 -1
- data/vendor/Pods/Pods-CocoaLumberjack-prefix.pch +2 -0
- data/vendor/Pods/Pods-NSData+MD5Digest-Private.xcconfig +1 -1
- data/vendor/Pods/Pods-YapDatabase-Private.xcconfig +1 -1
- data/vendor/Pods/{Pods-Acknowledgements.markdown → Pods-acknowledgements.markdown} +0 -37
- data/vendor/Pods/{Pods-Acknowledgements.plist → Pods-acknowledgements.plist} +0 -45
- data/vendor/Pods/Pods-environment.h +15 -15
- data/vendor/Pods/Pods.xcconfig +3 -3
- data/vendor/Pods/Pods.xcodeproj/project.pbxproj +2426 -3155
- data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-CocoaLumberjack.xcscheme +59 -0
- data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-NSData+MD5Digest.xcscheme +59 -0
- data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-YapDatabase.xcscheme +59 -0
- data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods.xcscheme +59 -0
- data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/xcschememanagement.plist +31 -0
- data/vendor/Pods/YapDatabase/README.md +3 -1
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/Internal/YapDatabaseFilteredViewPrivate.h +0 -2
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.h +8 -35
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.m +25 -41
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.h +17 -17
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.m +403 -134
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTypes.h +32 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/Internal/YapDatabaseFullTextSearchPrivate.h +8 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchConnection.m +8 -8
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchTransaction.m +113 -62
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/Internal/YapDatabaseExtensionPrivate.h +35 -31
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtension.m +25 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionConnection.m +1 -1
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionTransaction.m +25 -1
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipEdgePrivate.h +79 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipPrivate.h +125 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.h +35 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.m +129 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.h +29 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.m +802 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.h +163 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.m +408 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipNode.h +99 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.h +59 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.m +29 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.h +384 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.m +5254 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexPrivate.h +10 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexSetupPrivate.h +18 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.h +49 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.m +12 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexConnection.m +9 -8
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexSetup.m +62 -1
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexTransaction.m +148 -45
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPrivate.h +18 -1
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.h +2 -2
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.m +15 -9
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.h +17 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.m +211 -64
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.h +48 -107
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.m +10 -7
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.h +1 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.m +13 -22
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewOptions.h +10 -3
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.h +75 -24
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.m +725 -244
- data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTypes.h +99 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.h +8 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.m +19 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.h +1 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.m +12 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.h +1 -1
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.m +3 -3
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabasePrivate.h +43 -21
- data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapNull.m +4 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.h +3 -0
- data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.m +5 -0
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.h +4 -4
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.m +84 -93
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.h +21 -19
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.m +381 -209
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.h +131 -21
- data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.m +587 -267
- data/vendor/Pods/{Pods.bridgesupport → build-iPhoneSimulator/Pods.bridgesupport} +633 -2557
- data/vendor/Pods/build-iPhoneSimulator/libPods.a +0 -0
- data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.bridgesupport +2 -1
- data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.h +2 -1
- data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.m +4 -2
- metadata +80 -108
- data/Gemfile.lock +0 -63
- data/lib/yapper/attachment.rb +0 -48
- data/lib/yapper/document/attachment.rb +0 -26
- data/lib/yapper/sync.rb +0 -134
- data/lib/yapper/sync/data.rb +0 -12
- data/lib/yapper/sync/event.rb +0 -194
- data/lib/yapper/sync/queue.rb +0 -164
- data/spec/integration/all_spec.rb +0 -40
- data/spec/integration/sync_spec.rb +0 -42
- data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPClient.h +0 -641
- data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPClient.m +0 -1396
- data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h +0 -133
- data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m +0 -327
- data/vendor/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h +0 -113
- data/vendor/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m +0 -321
- data/vendor/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h +0 -71
- data/vendor/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m +0 -150
- data/vendor/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h +0 -75
- data/vendor/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m +0 -157
- data/vendor/Pods/AFNetworking/AFNetworking/AFNetworking.h +0 -43
- data/vendor/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h +0 -68
- data/vendor/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m +0 -143
- data/vendor/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h +0 -370
- data/vendor/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m +0 -848
- data/vendor/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h +0 -89
- data/vendor/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m +0 -167
- data/vendor/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h +0 -78
- data/vendor/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m +0 -191
- data/vendor/Pods/AFNetworking/LICENSE +0 -19
- data/vendor/Pods/AFNetworking/README.md +0 -208
- data/vendor/Pods/BuildHeaders/AFNetworking/AFHTTPClient.h +0 -641
- data/vendor/Pods/BuildHeaders/AFNetworking/AFHTTPRequestOperation.h +0 -133
- data/vendor/Pods/BuildHeaders/AFNetworking/AFImageRequestOperation.h +0 -113
- data/vendor/Pods/BuildHeaders/AFNetworking/AFJSONRequestOperation.h +0 -71
- data/vendor/Pods/BuildHeaders/AFNetworking/AFNetworkActivityIndicatorManager.h +0 -75
- data/vendor/Pods/BuildHeaders/AFNetworking/AFNetworking.h +0 -43
- data/vendor/Pods/BuildHeaders/AFNetworking/AFPropertyListRequestOperation.h +0 -68
- data/vendor/Pods/BuildHeaders/AFNetworking/AFURLConnectionOperation.h +0 -370
- data/vendor/Pods/BuildHeaders/AFNetworking/AFXMLRequestOperation.h +0 -89
- data/vendor/Pods/BuildHeaders/AFNetworking/UIImageView+AFNetworking.h +0 -78
- data/vendor/Pods/BuildHeaders/Reachability/Reachability.h +0 -109
- data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.m +0 -251
- data/vendor/Pods/Headers/AFNetworking/AFHTTPClient.h +0 -641
- data/vendor/Pods/Headers/AFNetworking/AFHTTPRequestOperation.h +0 -133
- data/vendor/Pods/Headers/AFNetworking/AFImageRequestOperation.h +0 -113
- data/vendor/Pods/Headers/AFNetworking/AFJSONRequestOperation.h +0 -71
- data/vendor/Pods/Headers/AFNetworking/AFNetworkActivityIndicatorManager.h +0 -75
- data/vendor/Pods/Headers/AFNetworking/AFNetworking.h +0 -43
- data/vendor/Pods/Headers/AFNetworking/AFPropertyListRequestOperation.h +0 -68
- data/vendor/Pods/Headers/AFNetworking/AFURLConnectionOperation.h +0 -370
- data/vendor/Pods/Headers/AFNetworking/AFXMLRequestOperation.h +0 -89
- data/vendor/Pods/Headers/AFNetworking/UIImageView+AFNetworking.h +0 -78
- data/vendor/Pods/Headers/Reachability/Reachability.h +0 -109
- data/vendor/Pods/Headers/YapDatabase/YapCache.h +0 -90
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnectionState.h +0 -29
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseDefaults.h +0 -37
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionPrivate.h +0 -440
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewPrivate.h +0 -19
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchPrivate.h +0 -69
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseLogging.h +0 -158
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseManager.h +0 -17
- data/vendor/Pods/Headers/YapDatabase/YapDatabasePrivate.h +0 -424
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +0 -73
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseStatement.h +0 -13
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseString.h +0 -121
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChangePrivate.h +0 -94
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappingsPrivate.h +0 -72
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPage.h +0 -36
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPageMetadata.h +0 -27
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPrivate.h +0 -153
- data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewRangeOptionsPrivate.h +0 -17
- data/vendor/Pods/Headers/YapDatabase/YapMemoryTable.h +0 -74
- data/vendor/Pods/Headers/YapDatabase/YapNull.h +0 -17
- data/vendor/Pods/Headers/YapDatabase/YapTouch.h +0 -15
- data/vendor/Pods/Headers/____Pods-AFNetworking-prefix.h +0 -17
- data/vendor/Pods/Headers/____Pods-Reachability-prefix.h +0 -5
- data/vendor/Pods/Pods-AFNetworking-Private.xcconfig +0 -5
- data/vendor/Pods/Pods-AFNetworking-dummy.m +0 -5
- data/vendor/Pods/Pods-AFNetworking-prefix.pch +0 -17
- data/vendor/Pods/Pods-AFNetworking.xcconfig +0 -1
- data/vendor/Pods/Pods-Reachability-Private.xcconfig +0 -5
- data/vendor/Pods/Pods-Reachability-dummy.m +0 -5
- data/vendor/Pods/Pods-Reachability-prefix.pch +0 -5
- data/vendor/Pods/Pods-Reachability.xcconfig +0 -1
- data/vendor/Pods/Reachability/LICENCE.txt +0 -24
- data/vendor/Pods/Reachability/README.md +0 -65
- data/vendor/Pods/Reachability/Reachability.h +0 -109
- data/vendor/Pods/Reachability/Reachability.m +0 -527
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* Welcome to Cocoa Lumberjack!
|
|
8
8
|
*
|
|
9
9
|
* The project page has a wealth of documentation if you have any questions.
|
|
10
|
-
* https://github.com/
|
|
10
|
+
* https://github.com/CocoaLumberjack/CocoaLumberjack
|
|
11
11
|
*
|
|
12
12
|
* If you're new to the project you may wish to read the "Getting Started" wiki.
|
|
13
|
-
* https://github.com/
|
|
13
|
+
* https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted
|
|
14
14
|
*
|
|
15
15
|
*
|
|
16
16
|
* This class provides a logger to write log statements to a file.
|
|
@@ -108,19 +108,47 @@
|
|
|
108
108
|
* On Mac, this is in ~/Library/Logs/<Application Name>.
|
|
109
109
|
* On iPhone, this is in ~/Library/Caches/Logs.
|
|
110
110
|
*
|
|
111
|
-
* Log files are named "log
|
|
112
|
-
*
|
|
111
|
+
* Log files are named "<bundle identifier> <date> <time>.log"
|
|
112
|
+
* Example: com.organization.myapp 2013-12-03 17-14.log
|
|
113
113
|
*
|
|
114
114
|
* Archived log files are automatically deleted according to the maximumNumberOfLogFiles property.
|
|
115
115
|
**/
|
|
116
116
|
@interface DDLogFileManagerDefault : NSObject <DDLogFileManager>
|
|
117
117
|
{
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
NSUInteger maximumNumberOfLogFiles;
|
|
119
|
+
NSString *_logsDirectory;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
- (id)init;
|
|
123
|
-
- (
|
|
123
|
+
- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory;
|
|
124
|
+
|
|
125
|
+
/*
|
|
126
|
+
* Methods to override.
|
|
127
|
+
*
|
|
128
|
+
* Log files are named "<bundle identifier> <date> <time>.log"
|
|
129
|
+
* Example: com.organization.myapp 2013-12-03 17-14.log
|
|
130
|
+
*
|
|
131
|
+
* If you wish to change default filename, you can override following two methods.
|
|
132
|
+
* - newLogFileName method would be called on new logfile creation.
|
|
133
|
+
* - isLogFile: method would be called to filter logfiles from all other files in logsDirectory.
|
|
134
|
+
* You have to parse given filename and return YES if it is logFile.
|
|
135
|
+
*
|
|
136
|
+
* **NOTE**
|
|
137
|
+
* newLogFileName returns filename. If appropriate file already exists, number would be added
|
|
138
|
+
* to filename before extension. You have to handle this case in isLogFile: method.
|
|
139
|
+
*
|
|
140
|
+
* Example:
|
|
141
|
+
* - newLogFileName returns "com.organization.myapp 2013-12-03.log",
|
|
142
|
+
* file "com.organization.myapp 2013-12-03.log" would be created.
|
|
143
|
+
* - after some time "com.organization.myapp 2013-12-03.log" is archived
|
|
144
|
+
* - newLogFileName again returns "com.organization.myapp 2013-12-03.log",
|
|
145
|
+
* file "com.organization.myapp 2013-12-03 2.log" would be created.
|
|
146
|
+
* - after some time "com.organization.myapp 2013-12-03 1.log" is archived
|
|
147
|
+
* - newLogFileName again returns "com.organization.myapp 2013-12-03.log",
|
|
148
|
+
* file "com.organization.myapp 2013-12-03 3.log" would be created.
|
|
149
|
+
**/
|
|
150
|
+
- (NSString *)newLogFileName;
|
|
151
|
+
- (BOOL)isLogFile:(NSString *)fileName;
|
|
124
152
|
|
|
125
153
|
/* Inherited from DDLogFileManager protocol:
|
|
126
154
|
|
|
@@ -156,11 +184,11 @@
|
|
|
156
184
|
**/
|
|
157
185
|
@interface DDLogFileFormatterDefault : NSObject <DDLogFormatter>
|
|
158
186
|
{
|
|
159
|
-
|
|
187
|
+
NSDateFormatter *dateFormatter;
|
|
160
188
|
}
|
|
161
189
|
|
|
162
190
|
- (id)init;
|
|
163
|
-
- (
|
|
191
|
+
- (instancetype)initWithDateFormatter:(NSDateFormatter *)dateFormatter;
|
|
164
192
|
|
|
165
193
|
@end
|
|
166
194
|
|
|
@@ -170,19 +198,20 @@
|
|
|
170
198
|
|
|
171
199
|
@interface DDFileLogger : DDAbstractLogger <DDLogger>
|
|
172
200
|
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
201
|
+
__strong id <DDLogFileManager> logFileManager;
|
|
202
|
+
|
|
203
|
+
DDLogFileInfo *currentLogFileInfo;
|
|
204
|
+
NSFileHandle *currentLogFileHandle;
|
|
205
|
+
|
|
206
|
+
dispatch_source_t currentLogFileVnode;
|
|
207
|
+
dispatch_source_t rollingTimer;
|
|
208
|
+
|
|
209
|
+
unsigned long long maximumFileSize;
|
|
210
|
+
NSTimeInterval rollingFrequency;
|
|
182
211
|
}
|
|
183
212
|
|
|
184
213
|
- (id)init;
|
|
185
|
-
- (
|
|
214
|
+
- (instancetype)initWithLogFileManager:(id <DDLogFileManager>)logFileManager;
|
|
186
215
|
|
|
187
216
|
/**
|
|
188
217
|
* Log File Rolling:
|
|
@@ -228,8 +257,13 @@
|
|
|
228
257
|
|
|
229
258
|
|
|
230
259
|
// You can optionally force the current log file to be rolled with this method.
|
|
260
|
+
// CompletionBlock will be called on main queue.
|
|
261
|
+
|
|
262
|
+
- (void)rollLogFileWithCompletionBlock:(void (^)())completionBlock;
|
|
263
|
+
|
|
264
|
+
// Method is deprecated. Use rollLogFileWithCompletionBlock: method instead.
|
|
231
265
|
|
|
232
|
-
- (void)rollLogFile;
|
|
266
|
+
- (void)rollLogFile __attribute((deprecated));
|
|
233
267
|
|
|
234
268
|
// Inherited from DDAbstractLogger
|
|
235
269
|
|
|
@@ -258,15 +292,15 @@
|
|
|
258
292
|
**/
|
|
259
293
|
@interface DDLogFileInfo : NSObject
|
|
260
294
|
{
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
295
|
+
__strong NSString *filePath;
|
|
296
|
+
__strong NSString *fileName;
|
|
297
|
+
|
|
298
|
+
__strong NSDictionary *fileAttributes;
|
|
299
|
+
|
|
300
|
+
__strong NSDate *creationDate;
|
|
301
|
+
__strong NSDate *modificationDate;
|
|
302
|
+
|
|
303
|
+
unsigned long long fileSize;
|
|
270
304
|
}
|
|
271
305
|
|
|
272
306
|
@property (strong, nonatomic, readonly) NSString *filePath;
|
|
@@ -283,9 +317,9 @@
|
|
|
283
317
|
|
|
284
318
|
@property (nonatomic, readwrite) BOOL isArchived;
|
|
285
319
|
|
|
286
|
-
+ (
|
|
320
|
+
+ (instancetype)logFileWithPath:(NSString *)filePath;
|
|
287
321
|
|
|
288
|
-
- (
|
|
322
|
+
- (instancetype)initWithFilePath:(NSString *)filePath;
|
|
289
323
|
|
|
290
324
|
- (void)reset;
|
|
291
325
|
- (void)renameFile:(NSString *)newFileName;
|
|
@@ -309,7 +343,8 @@
|
|
|
309
343
|
// On the simulator we add an attribute by appending a filename extension.
|
|
310
344
|
//
|
|
311
345
|
// For example:
|
|
312
|
-
//
|
|
346
|
+
// "mylog.txt" -> "mylog.archived.txt"
|
|
347
|
+
// "mylog" -> "mylog.archived"
|
|
313
348
|
|
|
314
349
|
- (BOOL)hasExtensionAttributeWithName:(NSString *)attrName;
|
|
315
350
|
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
* Welcome to Cocoa Lumberjack!
|
|
10
10
|
*
|
|
11
11
|
* The project page has a wealth of documentation if you have any questions.
|
|
12
|
-
* https://github.com/
|
|
12
|
+
* https://github.com/CocoaLumberjack/CocoaLumberjack
|
|
13
13
|
*
|
|
14
14
|
* If you're new to the project you may wish to read the "Getting Started" wiki.
|
|
15
|
-
* https://github.com/
|
|
15
|
+
* https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted
|
|
16
16
|
**/
|
|
17
17
|
|
|
18
18
|
#if ! __has_feature(objc_arc)
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
#define NSLogError(frmt, ...) do{ if(LOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
|
|
32
32
|
#define NSLogWarn(frmt, ...) do{ if(LOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
|
|
33
33
|
#define NSLogInfo(frmt, ...) do{ if(LOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
|
|
34
|
-
#define
|
|
34
|
+
#define NSLogDebug(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
|
|
35
|
+
#define NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0)
|
|
35
36
|
|
|
36
37
|
@interface DDLogFileManagerDefault (PrivateAPI)
|
|
37
38
|
|
|
@@ -48,6 +49,10 @@
|
|
|
48
49
|
|
|
49
50
|
@end
|
|
50
51
|
|
|
52
|
+
#if TARGET_OS_IPHONE
|
|
53
|
+
BOOL doesAppRunInBackground(void);
|
|
54
|
+
#endif
|
|
55
|
+
|
|
51
56
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
52
57
|
#pragma mark -
|
|
53
58
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -58,33 +63,39 @@
|
|
|
58
63
|
|
|
59
64
|
- (id)init
|
|
60
65
|
{
|
|
61
|
-
|
|
66
|
+
return [self initWithLogsDirectory:nil];
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
- (
|
|
69
|
+
- (instancetype)initWithLogsDirectory:(NSString *)aLogsDirectory
|
|
65
70
|
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
71
|
+
if ((self = [super init]))
|
|
72
|
+
{
|
|
73
|
+
maximumNumberOfLogFiles = DEFAULT_LOG_MAX_NUM_LOG_FILES;
|
|
74
|
+
|
|
75
|
+
if (aLogsDirectory)
|
|
76
|
+
_logsDirectory = [aLogsDirectory copy];
|
|
77
|
+
else
|
|
78
|
+
_logsDirectory = [[self defaultLogsDirectory] copy];
|
|
79
|
+
|
|
80
|
+
NSKeyValueObservingOptions kvoOptions = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
|
|
81
|
+
|
|
82
|
+
[self addObserver:self forKeyPath:NSStringFromSelector(@selector(maximumNumberOfLogFiles)) options:kvoOptions context:nil];
|
|
83
|
+
|
|
84
|
+
NSLogVerbose(@"DDFileLogManagerDefault: logsDirectory:\n%@", [self logsDirectory]);
|
|
85
|
+
NSLogVerbose(@"DDFileLogManagerDefault: sortedLogFileNames:\n%@", [self sortedLogFileNames]);
|
|
86
|
+
}
|
|
87
|
+
return self;
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
- (void)dealloc
|
|
86
91
|
{
|
|
87
|
-
|
|
92
|
+
// try-catch because the observer might be removed or never added. In this case, removeObserver throws and exception
|
|
93
|
+
@try {
|
|
94
|
+
[self removeObserver:self forKeyPath:NSStringFromSelector(@selector(maximumNumberOfLogFiles))];
|
|
95
|
+
}
|
|
96
|
+
@catch (NSException *exception) {
|
|
97
|
+
|
|
98
|
+
}
|
|
88
99
|
}
|
|
89
100
|
|
|
90
101
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -96,24 +107,24 @@
|
|
|
96
107
|
change:(NSDictionary *)change
|
|
97
108
|
context:(void *)context
|
|
98
109
|
{
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
110
|
+
NSNumber *old = [change objectForKey:NSKeyValueChangeOldKey];
|
|
111
|
+
NSNumber *new = [change objectForKey:NSKeyValueChangeNewKey];
|
|
112
|
+
|
|
113
|
+
if ([old isEqual:new])
|
|
114
|
+
{
|
|
115
|
+
// No change in value - don't bother with any processing.
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if ([keyPath isEqualToString:NSStringFromSelector(@selector(maximumNumberOfLogFiles))])
|
|
120
|
+
{
|
|
121
|
+
NSLogInfo(@"DDFileLogManagerDefault: Responding to configuration change: maximumNumberOfLogFiles");
|
|
122
|
+
|
|
123
|
+
dispatch_async([DDLog loggingQueue], ^{ @autoreleasepool {
|
|
124
|
+
|
|
125
|
+
[self deleteOldLogFiles];
|
|
126
|
+
}});
|
|
127
|
+
}
|
|
117
128
|
}
|
|
118
129
|
|
|
119
130
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -125,55 +136,55 @@
|
|
|
125
136
|
**/
|
|
126
137
|
- (void)deleteOldLogFiles
|
|
127
138
|
{
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
139
|
+
NSLogVerbose(@"DDLogFileManagerDefault: deleteOldLogFiles");
|
|
140
|
+
|
|
141
|
+
NSUInteger maxNumLogFiles = self.maximumNumberOfLogFiles;
|
|
142
|
+
if (maxNumLogFiles == 0)
|
|
143
|
+
{
|
|
144
|
+
// Unlimited - don't delete any log files
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
|
|
149
|
+
|
|
150
|
+
// Do we consider the first file?
|
|
151
|
+
// We are only supposed to be deleting archived files.
|
|
152
|
+
// In most cases, the first file is likely the log file that is currently being written to.
|
|
153
|
+
// So in most cases, we do not want to consider this file for deletion.
|
|
154
|
+
|
|
155
|
+
NSUInteger count = [sortedLogFileInfos count];
|
|
156
|
+
BOOL excludeFirstFile = NO;
|
|
157
|
+
|
|
158
|
+
if (count > 0)
|
|
159
|
+
{
|
|
160
|
+
DDLogFileInfo *logFileInfo = [sortedLogFileInfos objectAtIndex:0];
|
|
161
|
+
|
|
162
|
+
if (!logFileInfo.isArchived)
|
|
163
|
+
{
|
|
164
|
+
excludeFirstFile = YES;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
NSArray *sortedArchivedLogFileInfos;
|
|
169
|
+
if (excludeFirstFile)
|
|
170
|
+
{
|
|
171
|
+
count--;
|
|
172
|
+
sortedArchivedLogFileInfos = [sortedLogFileInfos subarrayWithRange:NSMakeRange(1, count)];
|
|
173
|
+
}
|
|
174
|
+
else
|
|
175
|
+
{
|
|
176
|
+
sortedArchivedLogFileInfos = sortedLogFileInfos;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
NSUInteger i;
|
|
180
|
+
for (i = maxNumLogFiles; i < count; i++)
|
|
181
|
+
{
|
|
182
|
+
DDLogFileInfo *logFileInfo = [sortedArchivedLogFileInfos objectAtIndex:i];
|
|
183
|
+
|
|
184
|
+
NSLogInfo(@"DDLogFileManagerDefault: Deleting file: %@", logFileInfo.fileName);
|
|
185
|
+
|
|
186
|
+
[[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:nil];
|
|
187
|
+
}
|
|
177
188
|
}
|
|
178
189
|
|
|
179
190
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -187,64 +198,97 @@
|
|
|
187
198
|
- (NSString *)defaultLogsDirectory
|
|
188
199
|
{
|
|
189
200
|
#if TARGET_OS_IPHONE
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
201
|
+
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
|
202
|
+
NSString *baseDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
|
|
203
|
+
NSString *logsDirectory = [baseDir stringByAppendingPathComponent:@"Logs"];
|
|
193
204
|
|
|
194
205
|
#else
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
206
|
+
NSString *appName = [[NSProcessInfo processInfo] processName];
|
|
207
|
+
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
|
|
208
|
+
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
|
|
209
|
+
NSString *logsDirectory = [[basePath stringByAppendingPathComponent:@"Logs"] stringByAppendingPathComponent:appName];
|
|
199
210
|
|
|
200
211
|
#endif
|
|
201
212
|
|
|
202
|
-
|
|
213
|
+
return logsDirectory;
|
|
203
214
|
}
|
|
204
215
|
|
|
205
216
|
- (NSString *)logsDirectory
|
|
206
217
|
{
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
218
|
+
// We could do this check once, during initalization, and not bother again.
|
|
219
|
+
// But this way the code continues to work if the directory gets deleted while the code is running.
|
|
220
|
+
|
|
221
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:_logsDirectory])
|
|
222
|
+
{
|
|
223
|
+
NSError *err = nil;
|
|
224
|
+
if (![[NSFileManager defaultManager] createDirectoryAtPath:_logsDirectory
|
|
225
|
+
withIntermediateDirectories:YES attributes:nil error:&err])
|
|
226
|
+
{
|
|
227
|
+
NSLogError(@"DDFileLogManagerDefault: Error creating logsDirectory: %@", err);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return _logsDirectory;
|
|
221
232
|
}
|
|
222
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Default log file name is "<bundle identifier> <date> <time>.log".
|
|
236
|
+
* Example: MobileSafari 2013-12-03 17-14.log
|
|
237
|
+
*
|
|
238
|
+
* You can change it by overriding newLogFileName and isLogFile: methods.
|
|
239
|
+
**/
|
|
223
240
|
- (BOOL)isLogFile:(NSString *)fileName
|
|
224
241
|
{
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
242
|
+
NSString *appName = [self applicationName];
|
|
243
|
+
|
|
244
|
+
BOOL hasProperPrefix = [fileName hasPrefix:appName];
|
|
245
|
+
BOOL hasProperSuffix = [fileName hasSuffix:@".log"];
|
|
246
|
+
BOOL hasProperDate = NO;
|
|
247
|
+
|
|
248
|
+
if (hasProperPrefix && hasProperSuffix)
|
|
249
|
+
{
|
|
250
|
+
NSUInteger lengthOfMiddle = fileName.length - appName.length - @".log".length;
|
|
251
|
+
|
|
252
|
+
// Date string should have at least 16 characters - " 2013-12-03 17-14"
|
|
253
|
+
if (lengthOfMiddle >= 17)
|
|
254
|
+
{
|
|
255
|
+
NSRange range = NSMakeRange(appName.length, lengthOfMiddle);
|
|
256
|
+
|
|
257
|
+
NSString *middle = [fileName substringWithRange:range];
|
|
258
|
+
NSArray *components = [middle componentsSeparatedByString:@" "];
|
|
259
|
+
|
|
260
|
+
// When creating logfile if there is existing file with the same name, we append attemp number at the end.
|
|
261
|
+
// Thats why here we can have three or four components. For details see createNewLogFile method.
|
|
262
|
+
//
|
|
263
|
+
// Components:
|
|
264
|
+
// "", "2013-12-03", "17-14"
|
|
265
|
+
// or
|
|
266
|
+
// "", "2013-12-03", "17-14", "1"
|
|
267
|
+
if (components.count == 3 || components.count == 4)
|
|
268
|
+
{
|
|
269
|
+
NSString *dateString = [NSString stringWithFormat:@"%@ %@", components[1], components[2]];
|
|
270
|
+
NSDateFormatter *dateFormatter = [self logFileDateFormatter];
|
|
271
|
+
|
|
272
|
+
NSDate *date = [dateFormatter dateFromString:dateString];
|
|
273
|
+
|
|
274
|
+
if (date)
|
|
275
|
+
{
|
|
276
|
+
hasProperDate = YES;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return (hasProperPrefix && hasProperDate && hasProperSuffix);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
- (NSDateFormatter *)logFileDateFormatter
|
|
286
|
+
{
|
|
287
|
+
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
|
288
|
+
[dateFormatter setDateFormat:@"yyyy'-'MM'-'dd' 'HH'-'mm'"];
|
|
289
|
+
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
|
|
290
|
+
|
|
291
|
+
return dateFormatter;
|
|
248
292
|
}
|
|
249
293
|
|
|
250
294
|
/**
|
|
@@ -253,24 +297,35 @@
|
|
|
253
297
|
**/
|
|
254
298
|
- (NSArray *)unsortedLogFilePaths
|
|
255
299
|
{
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
300
|
+
NSString *logsDirectory = [self logsDirectory];
|
|
301
|
+
NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logsDirectory error:nil];
|
|
302
|
+
|
|
303
|
+
NSMutableArray *unsortedLogFilePaths = [NSMutableArray arrayWithCapacity:[fileNames count]];
|
|
304
|
+
|
|
305
|
+
for (NSString *fileName in fileNames)
|
|
306
|
+
{
|
|
307
|
+
// Filter out any files that aren't log files. (Just for extra safety)
|
|
308
|
+
|
|
309
|
+
#if TARGET_IPHONE_SIMULATOR
|
|
310
|
+
// In case of iPhone simulator there can be 'archived' extension. isLogFile:
|
|
311
|
+
// method knows nothing about it. Thus removing it for this method.
|
|
312
|
+
//
|
|
313
|
+
// See full explanation in the header file.
|
|
314
|
+
NSString *theFileName = [fileName stringByReplacingOccurrencesOfString:@".archived"
|
|
315
|
+
withString:@""];
|
|
316
|
+
|
|
317
|
+
if ([self isLogFile:theFileName])
|
|
318
|
+
#else
|
|
319
|
+
if ([self isLogFile:fileName])
|
|
320
|
+
#endif
|
|
321
|
+
{
|
|
322
|
+
NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName];
|
|
323
|
+
|
|
324
|
+
[unsortedLogFilePaths addObject:filePath];
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return unsortedLogFilePaths;
|
|
274
329
|
}
|
|
275
330
|
|
|
276
331
|
/**
|
|
@@ -279,16 +334,16 @@
|
|
|
279
334
|
**/
|
|
280
335
|
- (NSArray *)unsortedLogFileNames
|
|
281
336
|
{
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
337
|
+
NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
|
|
338
|
+
|
|
339
|
+
NSMutableArray *unsortedLogFileNames = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
|
|
340
|
+
|
|
341
|
+
for (NSString *filePath in unsortedLogFilePaths)
|
|
342
|
+
{
|
|
343
|
+
[unsortedLogFileNames addObject:[filePath lastPathComponent]];
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return unsortedLogFileNames;
|
|
292
347
|
}
|
|
293
348
|
|
|
294
349
|
/**
|
|
@@ -298,66 +353,66 @@
|
|
|
298
353
|
**/
|
|
299
354
|
- (NSArray *)unsortedLogFileInfos
|
|
300
355
|
{
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
356
|
+
NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
|
|
357
|
+
|
|
358
|
+
NSMutableArray *unsortedLogFileInfos = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
|
|
359
|
+
|
|
360
|
+
for (NSString *filePath in unsortedLogFilePaths)
|
|
361
|
+
{
|
|
362
|
+
DDLogFileInfo *logFileInfo = [[DDLogFileInfo alloc] initWithFilePath:filePath];
|
|
363
|
+
|
|
364
|
+
[unsortedLogFileInfos addObject:logFileInfo];
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return unsortedLogFileInfos;
|
|
313
368
|
}
|
|
314
369
|
|
|
315
370
|
/**
|
|
316
371
|
* Just like the unsortedLogFilePaths method, but sorts the array.
|
|
317
|
-
* The items in the array are sorted by
|
|
318
|
-
* The first item in the array will be the most recently
|
|
372
|
+
* The items in the array are sorted by creation date.
|
|
373
|
+
* The first item in the array will be the most recently created log file.
|
|
319
374
|
**/
|
|
320
375
|
- (NSArray *)sortedLogFilePaths
|
|
321
376
|
{
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
377
|
+
NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
|
|
378
|
+
|
|
379
|
+
NSMutableArray *sortedLogFilePaths = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
|
|
380
|
+
|
|
381
|
+
for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
|
|
382
|
+
{
|
|
383
|
+
[sortedLogFilePaths addObject:[logFileInfo filePath]];
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return sortedLogFilePaths;
|
|
332
387
|
}
|
|
333
388
|
|
|
334
389
|
/**
|
|
335
390
|
* Just like the unsortedLogFileNames method, but sorts the array.
|
|
336
|
-
* The items in the array are sorted by
|
|
337
|
-
* The first item in the array will be the most recently
|
|
391
|
+
* The items in the array are sorted by creation date.
|
|
392
|
+
* The first item in the array will be the most recently created log file.
|
|
338
393
|
**/
|
|
339
394
|
- (NSArray *)sortedLogFileNames
|
|
340
395
|
{
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
396
|
+
NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
|
|
397
|
+
|
|
398
|
+
NSMutableArray *sortedLogFileNames = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
|
|
399
|
+
|
|
400
|
+
for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
|
|
401
|
+
{
|
|
402
|
+
[sortedLogFileNames addObject:[logFileInfo fileName]];
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return sortedLogFileNames;
|
|
351
406
|
}
|
|
352
407
|
|
|
353
408
|
/**
|
|
354
409
|
* Just like the unsortedLogFileInfos method, but sorts the array.
|
|
355
|
-
* The items in the array are sorted by
|
|
356
|
-
* The first item in the array will be the most recently
|
|
410
|
+
* The items in the array are sorted by creation date.
|
|
411
|
+
* The first item in the array will be the most recently created log file.
|
|
357
412
|
**/
|
|
358
413
|
- (NSArray *)sortedLogFileInfos
|
|
359
414
|
{
|
|
360
|
-
|
|
415
|
+
return [[self unsortedLogFileInfos] sortedArrayUsingSelector:@selector(reverseCompareByCreationDate:)];
|
|
361
416
|
}
|
|
362
417
|
|
|
363
418
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -365,20 +420,19 @@
|
|
|
365
420
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
366
421
|
|
|
367
422
|
/**
|
|
368
|
-
* Generates
|
|
369
|
-
*
|
|
423
|
+
* Generates log file name with default format "<bundle identifier> <date> <time>.log"
|
|
424
|
+
* Example: MobileSafari 2013-12-03 17-14.log
|
|
425
|
+
*
|
|
426
|
+
* You can change it by overriding newLogFileName and isLogFile: methods.
|
|
370
427
|
**/
|
|
371
|
-
- (NSString *)
|
|
428
|
+
- (NSString *)newLogFileName
|
|
372
429
|
{
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
CFRelease(uuid);
|
|
380
|
-
|
|
381
|
-
return result;
|
|
430
|
+
NSString *appName = [self applicationName];
|
|
431
|
+
|
|
432
|
+
NSDateFormatter *dateFormatter = [self logFileDateFormatter];
|
|
433
|
+
NSString *formattedDate = [dateFormatter stringFromDate:[NSDate date]];
|
|
434
|
+
|
|
435
|
+
return [NSString stringWithFormat:@"%@ %@.log", appName, formattedDate];
|
|
382
436
|
}
|
|
383
437
|
|
|
384
438
|
/**
|
|
@@ -386,28 +440,82 @@
|
|
|
386
440
|
**/
|
|
387
441
|
- (NSString *)createNewLogFile
|
|
388
442
|
{
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
443
|
+
NSString *fileName = [self newLogFileName];
|
|
444
|
+
NSString *logsDirectory = [self logsDirectory];
|
|
445
|
+
|
|
446
|
+
NSUInteger attempt = 1;
|
|
447
|
+
do
|
|
448
|
+
{
|
|
449
|
+
NSString *actualFileName = fileName;
|
|
450
|
+
|
|
451
|
+
if (attempt > 1) {
|
|
452
|
+
NSString *extension = [actualFileName pathExtension];
|
|
453
|
+
|
|
454
|
+
actualFileName = [actualFileName stringByDeletingPathExtension];
|
|
455
|
+
actualFileName = [actualFileName stringByAppendingFormat:@" %lu", (unsigned long)attempt];
|
|
456
|
+
if (extension.length) {
|
|
457
|
+
actualFileName = [actualFileName stringByAppendingPathExtension:extension];
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
NSString *filePath = [logsDirectory stringByAppendingPathComponent:actualFileName];
|
|
462
|
+
|
|
463
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath])
|
|
464
|
+
{
|
|
465
|
+
NSLogVerbose(@"DDLogFileManagerDefault: Creating new log file: %@", actualFileName);
|
|
466
|
+
|
|
467
|
+
NSDictionary *attributes = nil;
|
|
468
|
+
|
|
469
|
+
#if TARGET_OS_IPHONE
|
|
470
|
+
// When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
|
|
471
|
+
//
|
|
472
|
+
// But in case if app is able to launch from background we need to have an ability to open log file any time we
|
|
473
|
+
// want (even if device is locked). Thats why that attribute have to be changed to
|
|
474
|
+
// NSFileProtectionCompleteUntilFirstUserAuthentication.
|
|
475
|
+
|
|
476
|
+
NSString *key = doesAppRunInBackground() ?
|
|
477
|
+
NSFileProtectionCompleteUntilFirstUserAuthentication : NSFileProtectionCompleteUnlessOpen;
|
|
478
|
+
|
|
479
|
+
attributes = @{ NSFileProtectionKey : key };
|
|
480
|
+
#endif
|
|
481
|
+
|
|
482
|
+
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:attributes];
|
|
483
|
+
|
|
484
|
+
// Since we just created a new log file, we may need to delete some old log files
|
|
485
|
+
[self deleteOldLogFiles];
|
|
486
|
+
|
|
487
|
+
return filePath;
|
|
488
|
+
} else {
|
|
489
|
+
attempt++;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
} while(YES);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
496
|
+
#pragma mark Utility
|
|
497
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
498
|
+
|
|
499
|
+
- (NSString *)applicationName
|
|
500
|
+
{
|
|
501
|
+
static NSString *_appName;
|
|
502
|
+
static dispatch_once_t onceToken;
|
|
503
|
+
|
|
504
|
+
dispatch_once(&onceToken, ^{
|
|
505
|
+
_appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
|
|
506
|
+
|
|
507
|
+
if (! _appName)
|
|
508
|
+
{
|
|
509
|
+
_appName = [[NSProcessInfo processInfo] processName];
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (! _appName)
|
|
513
|
+
{
|
|
514
|
+
_appName = @"";
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
return _appName;
|
|
411
519
|
}
|
|
412
520
|
|
|
413
521
|
@end
|
|
@@ -420,32 +528,32 @@
|
|
|
420
528
|
|
|
421
529
|
- (id)init
|
|
422
530
|
{
|
|
423
|
-
|
|
531
|
+
return [self initWithDateFormatter:nil];
|
|
424
532
|
}
|
|
425
533
|
|
|
426
|
-
- (
|
|
534
|
+
- (instancetype)initWithDateFormatter:(NSDateFormatter *)aDateFormatter
|
|
427
535
|
{
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
536
|
+
if ((self = [super init]))
|
|
537
|
+
{
|
|
538
|
+
if (aDateFormatter)
|
|
539
|
+
{
|
|
540
|
+
dateFormatter = aDateFormatter;
|
|
541
|
+
}
|
|
542
|
+
else
|
|
543
|
+
{
|
|
544
|
+
dateFormatter = [[NSDateFormatter alloc] init];
|
|
545
|
+
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style
|
|
546
|
+
[dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return self;
|
|
442
550
|
}
|
|
443
551
|
|
|
444
552
|
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage
|
|
445
553
|
{
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
554
|
+
NSString *dateAndTime = [dateFormatter stringFromDate:(logMessage->timestamp)];
|
|
555
|
+
|
|
556
|
+
return [NSString stringWithFormat:@"%@ %@", dateAndTime, logMessage->logMsg];
|
|
449
557
|
}
|
|
450
558
|
|
|
451
559
|
@end
|
|
@@ -458,35 +566,40 @@
|
|
|
458
566
|
|
|
459
567
|
- (id)init
|
|
460
568
|
{
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
569
|
+
DDLogFileManagerDefault *defaultLogFileManager = [[DDLogFileManagerDefault alloc] init];
|
|
570
|
+
|
|
571
|
+
return [self initWithLogFileManager:defaultLogFileManager];
|
|
464
572
|
}
|
|
465
573
|
|
|
466
|
-
- (
|
|
574
|
+
- (instancetype)initWithLogFileManager:(id <DDLogFileManager>)aLogFileManager
|
|
467
575
|
{
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
576
|
+
if ((self = [super init]))
|
|
577
|
+
{
|
|
578
|
+
maximumFileSize = DEFAULT_LOG_MAX_FILE_SIZE;
|
|
579
|
+
rollingFrequency = DEFAULT_LOG_ROLLING_FREQUENCY;
|
|
580
|
+
|
|
581
|
+
logFileManager = aLogFileManager;
|
|
582
|
+
|
|
583
|
+
formatter = [[DDLogFileFormatterDefault alloc] init];
|
|
584
|
+
}
|
|
585
|
+
return self;
|
|
478
586
|
}
|
|
479
587
|
|
|
480
588
|
- (void)dealloc
|
|
481
589
|
{
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
590
|
+
[currentLogFileHandle synchronizeFile];
|
|
591
|
+
[currentLogFileHandle closeFile];
|
|
592
|
+
|
|
593
|
+
if (currentLogFileVnode) {
|
|
594
|
+
dispatch_source_cancel(currentLogFileVnode);
|
|
595
|
+
currentLogFileVnode = NULL;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (rollingTimer)
|
|
599
|
+
{
|
|
600
|
+
dispatch_source_cancel(rollingTimer);
|
|
601
|
+
rollingTimer = NULL;
|
|
602
|
+
}
|
|
490
603
|
}
|
|
491
604
|
|
|
492
605
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -497,119 +610,119 @@
|
|
|
497
610
|
|
|
498
611
|
- (unsigned long long)maximumFileSize
|
|
499
612
|
{
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
613
|
+
__block unsigned long long result;
|
|
614
|
+
|
|
615
|
+
dispatch_block_t block = ^{
|
|
616
|
+
result = maximumFileSize;
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
// The design of this method is taken from the DDAbstractLogger implementation.
|
|
620
|
+
// For extensive documentation please refer to the DDAbstractLogger implementation.
|
|
621
|
+
|
|
622
|
+
// Note: The internal implementation MUST access the maximumFileSize variable directly,
|
|
623
|
+
// This method is designed explicitly for external access.
|
|
624
|
+
//
|
|
625
|
+
// Using "self." syntax to go through this method will cause immediate deadlock.
|
|
626
|
+
// This is the intended result. Fix it by accessing the ivar directly.
|
|
627
|
+
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
|
628
|
+
|
|
629
|
+
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
|
630
|
+
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
|
631
|
+
|
|
632
|
+
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
|
633
|
+
|
|
634
|
+
dispatch_sync(globalLoggingQueue, ^{
|
|
635
|
+
dispatch_sync(loggerQueue, block);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
return result;
|
|
526
639
|
}
|
|
527
640
|
|
|
528
641
|
- (void)setMaximumFileSize:(unsigned long long)newMaximumFileSize
|
|
529
642
|
{
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
643
|
+
dispatch_block_t block = ^{ @autoreleasepool {
|
|
644
|
+
|
|
645
|
+
maximumFileSize = newMaximumFileSize;
|
|
646
|
+
[self maybeRollLogFileDueToSize];
|
|
647
|
+
|
|
648
|
+
}};
|
|
649
|
+
|
|
650
|
+
// The design of this method is taken from the DDAbstractLogger implementation.
|
|
651
|
+
// For extensive documentation please refer to the DDAbstractLogger implementation.
|
|
652
|
+
|
|
653
|
+
// Note: The internal implementation MUST access the maximumFileSize variable directly,
|
|
654
|
+
// This method is designed explicitly for external access.
|
|
655
|
+
//
|
|
656
|
+
// Using "self." syntax to go through this method will cause immediate deadlock.
|
|
657
|
+
// This is the intended result. Fix it by accessing the ivar directly.
|
|
658
|
+
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
|
659
|
+
|
|
660
|
+
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
|
661
|
+
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
|
662
|
+
|
|
663
|
+
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
|
664
|
+
|
|
665
|
+
dispatch_async(globalLoggingQueue, ^{
|
|
666
|
+
dispatch_async(loggerQueue, block);
|
|
667
|
+
});
|
|
555
668
|
}
|
|
556
669
|
|
|
557
670
|
- (NSTimeInterval)rollingFrequency
|
|
558
671
|
{
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
672
|
+
__block NSTimeInterval result;
|
|
673
|
+
|
|
674
|
+
dispatch_block_t block = ^{
|
|
675
|
+
result = rollingFrequency;
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
// The design of this method is taken from the DDAbstractLogger implementation.
|
|
679
|
+
// For extensive documentation please refer to the DDAbstractLogger implementation.
|
|
680
|
+
|
|
681
|
+
// Note: The internal implementation should access the rollingFrequency variable directly,
|
|
682
|
+
// This method is designed explicitly for external access.
|
|
683
|
+
//
|
|
684
|
+
// Using "self." syntax to go through this method will cause immediate deadlock.
|
|
685
|
+
// This is the intended result. Fix it by accessing the ivar directly.
|
|
686
|
+
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
|
687
|
+
|
|
688
|
+
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
|
689
|
+
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
|
690
|
+
|
|
691
|
+
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
|
692
|
+
|
|
693
|
+
dispatch_sync(globalLoggingQueue, ^{
|
|
694
|
+
dispatch_sync(loggerQueue, block);
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
return result;
|
|
585
698
|
}
|
|
586
699
|
|
|
587
700
|
- (void)setRollingFrequency:(NSTimeInterval)newRollingFrequency
|
|
588
701
|
{
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
702
|
+
dispatch_block_t block = ^{ @autoreleasepool {
|
|
703
|
+
|
|
704
|
+
rollingFrequency = newRollingFrequency;
|
|
705
|
+
[self maybeRollLogFileDueToAge];
|
|
706
|
+
}};
|
|
707
|
+
|
|
708
|
+
// The design of this method is taken from the DDAbstractLogger implementation.
|
|
709
|
+
// For extensive documentation please refer to the DDAbstractLogger implementation.
|
|
710
|
+
|
|
711
|
+
// Note: The internal implementation should access the rollingFrequency variable directly,
|
|
712
|
+
// This method is designed explicitly for external access.
|
|
713
|
+
//
|
|
714
|
+
// Using "self." syntax to go through this method will cause immediate deadlock.
|
|
715
|
+
// This is the intended result. Fix it by accessing the ivar directly.
|
|
716
|
+
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
|
717
|
+
|
|
718
|
+
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
|
719
|
+
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
|
720
|
+
|
|
721
|
+
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
|
722
|
+
|
|
723
|
+
dispatch_async(globalLoggingQueue, ^{
|
|
724
|
+
dispatch_async(loggerQueue, block);
|
|
725
|
+
});
|
|
613
726
|
}
|
|
614
727
|
|
|
615
728
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -618,139 +731,157 @@
|
|
|
618
731
|
|
|
619
732
|
- (void)scheduleTimerToRollLogFileDueToAge
|
|
620
733
|
{
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
734
|
+
if (rollingTimer)
|
|
735
|
+
{
|
|
736
|
+
dispatch_source_cancel(rollingTimer);
|
|
737
|
+
rollingTimer = NULL;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
if (currentLogFileInfo == nil || rollingFrequency <= 0.0)
|
|
741
|
+
{
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
NSDate *logFileCreationDate = [currentLogFileInfo creationDate];
|
|
746
|
+
|
|
747
|
+
NSTimeInterval ti = [logFileCreationDate timeIntervalSinceReferenceDate];
|
|
748
|
+
ti += rollingFrequency;
|
|
749
|
+
|
|
750
|
+
NSDate *logFileRollingDate = [NSDate dateWithTimeIntervalSinceReferenceDate:ti];
|
|
751
|
+
|
|
752
|
+
NSLogVerbose(@"DDFileLogger: scheduleTimerToRollLogFileDueToAge");
|
|
753
|
+
|
|
754
|
+
NSLogVerbose(@"DDFileLogger: logFileCreationDate: %@", logFileCreationDate);
|
|
755
|
+
NSLogVerbose(@"DDFileLogger: logFileRollingDate : %@", logFileRollingDate);
|
|
756
|
+
|
|
757
|
+
rollingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, loggerQueue);
|
|
758
|
+
|
|
759
|
+
dispatch_source_set_event_handler(rollingTimer, ^{ @autoreleasepool {
|
|
760
|
+
|
|
761
|
+
[self maybeRollLogFileDueToAge];
|
|
762
|
+
|
|
763
|
+
}});
|
|
764
|
+
|
|
765
|
+
#if !OS_OBJECT_USE_OBJC
|
|
766
|
+
dispatch_source_t theRollingTimer = rollingTimer;
|
|
767
|
+
dispatch_source_set_cancel_handler(rollingTimer, ^{
|
|
768
|
+
dispatch_release(theRollingTimer);
|
|
769
|
+
});
|
|
770
|
+
#endif
|
|
771
|
+
|
|
772
|
+
uint64_t delay = (uint64_t)([logFileRollingDate timeIntervalSinceNow] * NSEC_PER_SEC);
|
|
773
|
+
dispatch_time_t fireTime = dispatch_time(DISPATCH_TIME_NOW, delay);
|
|
774
|
+
|
|
775
|
+
dispatch_source_set_timer(rollingTimer, fireTime, DISPATCH_TIME_FOREVER, 1.0);
|
|
776
|
+
dispatch_resume(rollingTimer);
|
|
664
777
|
}
|
|
665
778
|
|
|
779
|
+
|
|
666
780
|
- (void)rollLogFile
|
|
667
781
|
{
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
782
|
+
[self rollLogFileWithCompletionBlock:nil];
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
- (void)rollLogFileWithCompletionBlock:(void (^)())completionBlock
|
|
786
|
+
{
|
|
787
|
+
// This method is public.
|
|
788
|
+
// We need to execute the rolling on our logging thread/queue.
|
|
789
|
+
|
|
790
|
+
dispatch_block_t block = ^{ @autoreleasepool {
|
|
791
|
+
|
|
792
|
+
[self rollLogFileNow];
|
|
793
|
+
|
|
794
|
+
if (completionBlock)
|
|
795
|
+
{
|
|
796
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
797
|
+
completionBlock();
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
}};
|
|
801
|
+
|
|
802
|
+
// The design of this method is taken from the DDAbstractLogger implementation.
|
|
803
|
+
// For extensive documentation please refer to the DDAbstractLogger implementation.
|
|
804
|
+
|
|
805
|
+
if ([self isOnInternalLoggerQueue])
|
|
806
|
+
{
|
|
807
|
+
block();
|
|
808
|
+
}
|
|
809
|
+
else
|
|
810
|
+
{
|
|
811
|
+
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
|
812
|
+
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
|
813
|
+
|
|
814
|
+
dispatch_async(globalLoggingQueue, ^{
|
|
815
|
+
dispatch_async(loggerQueue, block);
|
|
816
|
+
});
|
|
817
|
+
}
|
|
692
818
|
}
|
|
693
819
|
|
|
694
820
|
- (void)rollLogFileNow
|
|
695
821
|
{
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
822
|
+
NSLogVerbose(@"DDFileLogger: rollLogFileNow");
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
if (currentLogFileHandle == nil) return;
|
|
826
|
+
|
|
827
|
+
[currentLogFileHandle synchronizeFile];
|
|
828
|
+
[currentLogFileHandle closeFile];
|
|
829
|
+
currentLogFileHandle = nil;
|
|
830
|
+
|
|
831
|
+
currentLogFileInfo.isArchived = YES;
|
|
832
|
+
|
|
833
|
+
if ([logFileManager respondsToSelector:@selector(didRollAndArchiveLogFile:)])
|
|
834
|
+
{
|
|
835
|
+
[logFileManager didRollAndArchiveLogFile:(currentLogFileInfo.filePath)];
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
currentLogFileInfo = nil;
|
|
839
|
+
|
|
840
|
+
if (currentLogFileVnode) {
|
|
841
|
+
dispatch_source_cancel(currentLogFileVnode);
|
|
842
|
+
currentLogFileVnode = NULL;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (rollingTimer)
|
|
846
|
+
{
|
|
847
|
+
dispatch_source_cancel(rollingTimer);
|
|
848
|
+
rollingTimer = NULL;
|
|
849
|
+
}
|
|
719
850
|
}
|
|
720
851
|
|
|
721
852
|
- (void)maybeRollLogFileDueToAge
|
|
722
853
|
{
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
854
|
+
if (rollingFrequency > 0.0 && currentLogFileInfo.age >= rollingFrequency)
|
|
855
|
+
{
|
|
856
|
+
NSLogVerbose(@"DDFileLogger: Rolling log file due to age...");
|
|
857
|
+
|
|
858
|
+
[self rollLogFileNow];
|
|
859
|
+
}
|
|
860
|
+
else
|
|
861
|
+
{
|
|
862
|
+
[self scheduleTimerToRollLogFileDueToAge];
|
|
863
|
+
}
|
|
733
864
|
}
|
|
734
865
|
|
|
735
866
|
- (void)maybeRollLogFileDueToSize
|
|
736
867
|
{
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
868
|
+
// This method is called from logMessage.
|
|
869
|
+
// Keep it FAST.
|
|
870
|
+
|
|
871
|
+
// Note: Use direct access to maximumFileSize variable.
|
|
872
|
+
// We specifically wrote our own getter/setter method to allow us to do this (for performance reasons).
|
|
873
|
+
|
|
874
|
+
if (maximumFileSize > 0)
|
|
875
|
+
{
|
|
876
|
+
unsigned long long fileSize = [currentLogFileHandle offsetInFile];
|
|
877
|
+
|
|
878
|
+
if (fileSize >= maximumFileSize)
|
|
879
|
+
{
|
|
880
|
+
NSLogVerbose(@"DDFileLogger: Rolling log file due to size (%qu)...", fileSize);
|
|
881
|
+
|
|
882
|
+
[self rollLogFileNow];
|
|
883
|
+
}
|
|
884
|
+
}
|
|
754
885
|
}
|
|
755
886
|
|
|
756
887
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -766,120 +897,175 @@
|
|
|
766
897
|
**/
|
|
767
898
|
- (DDLogFileInfo *)currentLogFileInfo
|
|
768
899
|
{
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
900
|
+
if (currentLogFileInfo == nil)
|
|
901
|
+
{
|
|
902
|
+
NSArray *sortedLogFileInfos = [logFileManager sortedLogFileInfos];
|
|
903
|
+
|
|
904
|
+
if ([sortedLogFileInfos count] > 0)
|
|
905
|
+
{
|
|
906
|
+
DDLogFileInfo *mostRecentLogFileInfo = [sortedLogFileInfos objectAtIndex:0];
|
|
907
|
+
|
|
908
|
+
BOOL useExistingLogFile = YES;
|
|
909
|
+
BOOL shouldArchiveMostRecent = NO;
|
|
910
|
+
|
|
911
|
+
if (mostRecentLogFileInfo.isArchived)
|
|
912
|
+
{
|
|
913
|
+
useExistingLogFile = NO;
|
|
914
|
+
shouldArchiveMostRecent = NO;
|
|
915
|
+
}
|
|
916
|
+
else if (maximumFileSize > 0 && mostRecentLogFileInfo.fileSize >= maximumFileSize)
|
|
917
|
+
{
|
|
918
|
+
useExistingLogFile = NO;
|
|
919
|
+
shouldArchiveMostRecent = YES;
|
|
920
|
+
}
|
|
921
|
+
else if (rollingFrequency > 0.0 && mostRecentLogFileInfo.age >= rollingFrequency)
|
|
922
|
+
{
|
|
923
|
+
useExistingLogFile = NO;
|
|
924
|
+
shouldArchiveMostRecent = YES;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
#if TARGET_OS_IPHONE
|
|
929
|
+
// When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
|
|
930
|
+
//
|
|
931
|
+
// But in case if app is able to launch from background we need to have an ability to open log file any time we
|
|
932
|
+
// want (even if device is locked). Thats why that attribute have to be changed to
|
|
933
|
+
// NSFileProtectionCompleteUntilFirstUserAuthentication.
|
|
934
|
+
//
|
|
935
|
+
// If previous log was created when app wasn't running in background, but now it is - we archive it and create
|
|
936
|
+
// a new one.
|
|
937
|
+
|
|
938
|
+
if (useExistingLogFile && doesAppRunInBackground()) {
|
|
939
|
+
NSString *key = mostRecentLogFileInfo.fileAttributes[NSFileProtectionKey];
|
|
940
|
+
|
|
941
|
+
if (! [key isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication]) {
|
|
942
|
+
useExistingLogFile = NO;
|
|
943
|
+
shouldArchiveMostRecent = YES;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
#endif
|
|
947
|
+
|
|
948
|
+
if (useExistingLogFile)
|
|
949
|
+
{
|
|
950
|
+
NSLogVerbose(@"DDFileLogger: Resuming logging with file %@", mostRecentLogFileInfo.fileName);
|
|
951
|
+
|
|
952
|
+
currentLogFileInfo = mostRecentLogFileInfo;
|
|
953
|
+
}
|
|
954
|
+
else
|
|
955
|
+
{
|
|
956
|
+
if (shouldArchiveMostRecent)
|
|
957
|
+
{
|
|
958
|
+
mostRecentLogFileInfo.isArchived = YES;
|
|
959
|
+
|
|
960
|
+
if ([logFileManager respondsToSelector:@selector(didArchiveLogFile:)])
|
|
961
|
+
{
|
|
962
|
+
[logFileManager didArchiveLogFile:(mostRecentLogFileInfo.filePath)];
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
if (currentLogFileInfo == nil)
|
|
969
|
+
{
|
|
970
|
+
NSString *currentLogFilePath = [logFileManager createNewLogFile];
|
|
971
|
+
|
|
972
|
+
currentLogFileInfo = [[DDLogFileInfo alloc] initWithFilePath:currentLogFilePath];
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
return currentLogFileInfo;
|
|
825
977
|
}
|
|
826
978
|
|
|
827
979
|
- (NSFileHandle *)currentLogFileHandle
|
|
828
980
|
{
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
981
|
+
if (currentLogFileHandle == nil)
|
|
982
|
+
{
|
|
983
|
+
NSString *logFilePath = [[self currentLogFileInfo] filePath];
|
|
984
|
+
|
|
985
|
+
currentLogFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
|
|
986
|
+
[currentLogFileHandle seekToEndOfFile];
|
|
987
|
+
|
|
988
|
+
if (currentLogFileHandle)
|
|
989
|
+
{
|
|
990
|
+
[self scheduleTimerToRollLogFileDueToAge];
|
|
991
|
+
|
|
992
|
+
// Here we are monitoring the log file. In case if it would be deleted ormoved
|
|
993
|
+
// somewhere we want to roll it and use a new one.
|
|
994
|
+
currentLogFileVnode = dispatch_source_create(
|
|
995
|
+
DISPATCH_SOURCE_TYPE_VNODE,
|
|
996
|
+
[currentLogFileHandle fileDescriptor],
|
|
997
|
+
DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME,
|
|
998
|
+
loggerQueue
|
|
999
|
+
);
|
|
1000
|
+
|
|
1001
|
+
dispatch_source_set_event_handler(currentLogFileVnode, ^{ @autoreleasepool {
|
|
1002
|
+
NSLogInfo(@"DDFileLogger: Current logfile was moved. Rolling it and creating a new one");
|
|
1003
|
+
[self rollLogFileNow];
|
|
1004
|
+
}});
|
|
1005
|
+
|
|
1006
|
+
#if !OS_OBJECT_USE_OBJC
|
|
1007
|
+
dispatch_source_t vnode = currentLogFileVnode;
|
|
1008
|
+
dispatch_source_set_cancel_handler(currentLogFileVnode, ^{
|
|
1009
|
+
dispatch_release(vnode);
|
|
1010
|
+
});
|
|
1011
|
+
#endif
|
|
1012
|
+
|
|
1013
|
+
dispatch_resume(currentLogFileVnode);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
return currentLogFileHandle;
|
|
843
1018
|
}
|
|
844
1019
|
|
|
845
1020
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
846
1021
|
#pragma mark DDLogger Protocol
|
|
847
1022
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
848
1023
|
|
|
1024
|
+
static int exception_count = 0;
|
|
849
1025
|
- (void)logMessage:(DDLogMessage *)logMessage
|
|
850
1026
|
{
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1027
|
+
NSString *logMsg = logMessage->logMsg;
|
|
1028
|
+
|
|
1029
|
+
if (formatter)
|
|
1030
|
+
{
|
|
1031
|
+
logMsg = [formatter formatLogMessage:logMessage];
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
if (logMsg)
|
|
1035
|
+
{
|
|
1036
|
+
if (![logMsg hasSuffix:@"\n"])
|
|
1037
|
+
{
|
|
1038
|
+
logMsg = [logMsg stringByAppendingString:@"\n"];
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
NSData *logData = [logMsg dataUsingEncoding:NSUTF8StringEncoding];
|
|
1042
|
+
|
|
1043
|
+
@try {
|
|
1044
|
+
[[self currentLogFileHandle] writeData:logData];
|
|
1045
|
+
|
|
1046
|
+
[self maybeRollLogFileDueToSize];
|
|
1047
|
+
}
|
|
1048
|
+
@catch (NSException *exception) {
|
|
1049
|
+
exception_count++;
|
|
1050
|
+
if (exception_count <= 10) {
|
|
1051
|
+
NSLogError(@"DDFileLogger.logMessage: %@", exception);
|
|
1052
|
+
if (exception_count == 10)
|
|
1053
|
+
NSLogError(@"DDFileLogger.logMessage: Too many exceptions -- will not log any more of them.");
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
871
1057
|
}
|
|
872
1058
|
|
|
873
1059
|
- (void)willRemoveLogger
|
|
874
1060
|
{
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
1061
|
+
// If you override me be sure to invoke [super willRemoveLogger];
|
|
1062
|
+
|
|
1063
|
+
[self rollLogFileNow];
|
|
878
1064
|
}
|
|
879
1065
|
|
|
880
1066
|
- (NSString *)loggerName
|
|
881
1067
|
{
|
|
882
|
-
|
|
1068
|
+
return @"cocoa.lumberjack.fileLogger";
|
|
883
1069
|
}
|
|
884
1070
|
|
|
885
1071
|
@end
|
|
@@ -910,18 +1096,18 @@
|
|
|
910
1096
|
|
|
911
1097
|
#pragma mark Lifecycle
|
|
912
1098
|
|
|
913
|
-
+ (
|
|
1099
|
+
+ (instancetype)logFileWithPath:(NSString *)aFilePath
|
|
914
1100
|
{
|
|
915
|
-
|
|
1101
|
+
return [[self alloc] initWithFilePath:aFilePath];
|
|
916
1102
|
}
|
|
917
1103
|
|
|
918
|
-
- (
|
|
1104
|
+
- (instancetype)initWithFilePath:(NSString *)aFilePath
|
|
919
1105
|
{
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1106
|
+
if ((self = [super init]))
|
|
1107
|
+
{
|
|
1108
|
+
filePath = [aFilePath copy];
|
|
1109
|
+
}
|
|
1110
|
+
return self;
|
|
925
1111
|
}
|
|
926
1112
|
|
|
927
1113
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -930,101 +1116,66 @@
|
|
|
930
1116
|
|
|
931
1117
|
- (NSDictionary *)fileAttributes
|
|
932
1118
|
{
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1119
|
+
if (fileAttributes == nil)
|
|
1120
|
+
{
|
|
1121
|
+
fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
|
|
1122
|
+
}
|
|
1123
|
+
return fileAttributes;
|
|
938
1124
|
}
|
|
939
1125
|
|
|
940
1126
|
- (NSString *)fileName
|
|
941
1127
|
{
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1128
|
+
if (fileName == nil)
|
|
1129
|
+
{
|
|
1130
|
+
fileName = [filePath lastPathComponent];
|
|
1131
|
+
}
|
|
1132
|
+
return fileName;
|
|
947
1133
|
}
|
|
948
1134
|
|
|
949
1135
|
- (NSDate *)modificationDate
|
|
950
1136
|
{
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1137
|
+
if (modificationDate == nil)
|
|
1138
|
+
{
|
|
1139
|
+
modificationDate = [[self fileAttributes] objectForKey:NSFileModificationDate];
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
return modificationDate;
|
|
957
1143
|
}
|
|
958
1144
|
|
|
959
1145
|
- (NSDate *)creationDate
|
|
960
1146
|
{
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
const char *path = [filePath UTF8String];
|
|
967
|
-
|
|
968
|
-
struct attrlist attrList;
|
|
969
|
-
memset(&attrList, 0, sizeof(attrList));
|
|
970
|
-
attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
|
|
971
|
-
attrList.commonattr = ATTR_CMN_CRTIME;
|
|
972
|
-
|
|
973
|
-
struct {
|
|
974
|
-
u_int32_t attrBufferSizeInBytes;
|
|
975
|
-
struct timespec crtime;
|
|
976
|
-
} attrBuffer;
|
|
977
|
-
|
|
978
|
-
int result = getattrlist(path, &attrList, &attrBuffer, sizeof(attrBuffer), 0);
|
|
979
|
-
if (result == 0)
|
|
980
|
-
{
|
|
981
|
-
double seconds = (double)(attrBuffer.crtime.tv_sec);
|
|
982
|
-
double nanos = (double)(attrBuffer.crtime.tv_nsec);
|
|
983
|
-
|
|
984
|
-
NSTimeInterval ti = seconds + (nanos / 1000000000.0);
|
|
985
|
-
|
|
986
|
-
creationDate = [NSDate dateWithTimeIntervalSince1970:ti];
|
|
987
|
-
}
|
|
988
|
-
else
|
|
989
|
-
{
|
|
990
|
-
NSLogError(@"DDLogFileInfo: creationDate(%@): getattrlist result = %i", self.fileName, result);
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
#else
|
|
994
|
-
|
|
995
|
-
creationDate = [[self fileAttributes] objectForKey:NSFileCreationDate];
|
|
996
|
-
|
|
997
|
-
#endif
|
|
998
|
-
|
|
999
|
-
}
|
|
1000
|
-
return creationDate;
|
|
1147
|
+
if (creationDate == nil)
|
|
1148
|
+
{
|
|
1149
|
+
creationDate = [[self fileAttributes] objectForKey:NSFileCreationDate];
|
|
1150
|
+
}
|
|
1151
|
+
return creationDate;
|
|
1001
1152
|
}
|
|
1002
1153
|
|
|
1003
1154
|
- (unsigned long long)fileSize
|
|
1004
1155
|
{
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1156
|
+
if (fileSize == 0)
|
|
1157
|
+
{
|
|
1158
|
+
fileSize = [[[self fileAttributes] objectForKey:NSFileSize] unsignedLongLongValue];
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
return fileSize;
|
|
1011
1162
|
}
|
|
1012
1163
|
|
|
1013
1164
|
- (NSTimeInterval)age
|
|
1014
1165
|
{
|
|
1015
|
-
|
|
1166
|
+
return [[self creationDate] timeIntervalSinceNow] * -1.0;
|
|
1016
1167
|
}
|
|
1017
1168
|
|
|
1018
1169
|
- (NSString *)description
|
|
1019
1170
|
{
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1171
|
+
return [@{@"filePath": self.filePath ?: @"",
|
|
1172
|
+
@"fileName": self.fileName ?: @"",
|
|
1173
|
+
@"fileAttributes": self.fileAttributes ?: @"",
|
|
1174
|
+
@"creationDate": self.creationDate ?: @"",
|
|
1175
|
+
@"modificationDate": self.modificationDate ?: @"",
|
|
1176
|
+
@"fileSize": @(self.fileSize),
|
|
1177
|
+
@"age": @(self.age),
|
|
1178
|
+
@"isArchived": @(self.isArchived)} description];
|
|
1028
1179
|
}
|
|
1029
1180
|
|
|
1030
1181
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -1033,43 +1184,43 @@
|
|
|
1033
1184
|
|
|
1034
1185
|
- (BOOL)isArchived
|
|
1035
1186
|
{
|
|
1036
|
-
|
|
1187
|
+
|
|
1037
1188
|
#if TARGET_IPHONE_SIMULATOR
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1189
|
+
|
|
1190
|
+
// Extended attributes don't work properly on the simulator.
|
|
1191
|
+
// So we have to use a less attractive alternative.
|
|
1192
|
+
// See full explanation in the header file.
|
|
1193
|
+
|
|
1194
|
+
return [self hasExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
|
|
1195
|
+
|
|
1045
1196
|
#else
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1197
|
+
|
|
1198
|
+
return [self hasExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
|
|
1199
|
+
|
|
1049
1200
|
#endif
|
|
1050
1201
|
}
|
|
1051
1202
|
|
|
1052
1203
|
- (void)setIsArchived:(BOOL)flag
|
|
1053
1204
|
{
|
|
1054
|
-
|
|
1205
|
+
|
|
1055
1206
|
#if TARGET_IPHONE_SIMULATOR
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1207
|
+
|
|
1208
|
+
// Extended attributes don't work properly on the simulator.
|
|
1209
|
+
// So we have to use a less attractive alternative.
|
|
1210
|
+
// See full explanation in the header file.
|
|
1211
|
+
|
|
1212
|
+
if (flag)
|
|
1213
|
+
[self addExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
|
|
1214
|
+
else
|
|
1215
|
+
[self removeExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
|
|
1216
|
+
|
|
1066
1217
|
#else
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1218
|
+
|
|
1219
|
+
if (flag)
|
|
1220
|
+
[self addExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
|
|
1221
|
+
else
|
|
1222
|
+
[self removeExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
|
|
1223
|
+
|
|
1073
1224
|
#endif
|
|
1074
1225
|
}
|
|
1075
1226
|
|
|
@@ -1079,36 +1230,43 @@
|
|
|
1079
1230
|
|
|
1080
1231
|
- (void)reset
|
|
1081
1232
|
{
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1233
|
+
fileName = nil;
|
|
1234
|
+
fileAttributes = nil;
|
|
1235
|
+
creationDate = nil;
|
|
1236
|
+
modificationDate = nil;
|
|
1086
1237
|
}
|
|
1087
1238
|
|
|
1088
1239
|
- (void)renameFile:(NSString *)newFileName
|
|
1089
1240
|
{
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1241
|
+
// This method is only used on the iPhone simulator, where normal extended attributes are broken.
|
|
1242
|
+
// See full explanation in the header file.
|
|
1243
|
+
|
|
1244
|
+
if (![newFileName isEqualToString:[self fileName]])
|
|
1245
|
+
{
|
|
1246
|
+
NSString *fileDir = [filePath stringByDeletingLastPathComponent];
|
|
1247
|
+
|
|
1248
|
+
NSString *newFilePath = [fileDir stringByAppendingPathComponent:newFileName];
|
|
1249
|
+
|
|
1250
|
+
NSLogVerbose(@"DDLogFileInfo: Renaming file: '%@' -> '%@'", self.fileName, newFileName);
|
|
1251
|
+
|
|
1252
|
+
NSError *error = nil;
|
|
1253
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:newFilePath]){
|
|
1254
|
+
if([[NSFileManager defaultManager] removeItemAtPath:newFilePath error:&error]){
|
|
1255
|
+
NSLogError(@"DDLogFileInfo: Error deleting archive (%@): %@", self.fileName, error);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
if (![[NSFileManager defaultManager] moveItemAtPath:filePath toPath:newFilePath error:&error])
|
|
1260
|
+
{
|
|
1261
|
+
NSLogError(@"DDLogFileInfo: Error renaming file (%@): %@", self.fileName, error);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
filePath = newFilePath;
|
|
1265
|
+
[self reset];
|
|
1266
|
+
}
|
|
1110
1267
|
}
|
|
1111
1268
|
|
|
1269
|
+
|
|
1112
1270
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
1113
1271
|
#pragma mark Attribute Management
|
|
1114
1272
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -1121,183 +1279,185 @@
|
|
|
1121
1279
|
|
|
1122
1280
|
- (BOOL)hasExtensionAttributeWithName:(NSString *)attrName
|
|
1123
1281
|
{
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
{
|
|
1152
|
-
return YES;
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
return NO;
|
|
1282
|
+
// This method is only used on the iPhone simulator, where normal extended attributes are broken.
|
|
1283
|
+
// See full explanation in the header file.
|
|
1284
|
+
|
|
1285
|
+
// Split the file name into components. File name may have various format, but generally
|
|
1286
|
+
// structure is same:
|
|
1287
|
+
//
|
|
1288
|
+
// <name part>.<extension part> and <name part>.archived.<extension part>
|
|
1289
|
+
// or
|
|
1290
|
+
// <name part> and <name part>.archived
|
|
1291
|
+
//
|
|
1292
|
+
// So we want to search for the attrName in the components (ignoring the first array index).
|
|
1293
|
+
|
|
1294
|
+
NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
|
|
1295
|
+
|
|
1296
|
+
// Watch out for file names without an extension
|
|
1297
|
+
|
|
1298
|
+
for (NSUInteger i = 1; i < components.count; i++)
|
|
1299
|
+
{
|
|
1300
|
+
NSString *attr = [components objectAtIndex:i];
|
|
1301
|
+
|
|
1302
|
+
if ([attrName isEqualToString:attr])
|
|
1303
|
+
{
|
|
1304
|
+
return YES;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
return NO;
|
|
1157
1309
|
}
|
|
1158
1310
|
|
|
1159
1311
|
- (void)addExtensionAttributeWithName:(NSString *)attrName
|
|
1160
1312
|
{
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1313
|
+
// This method is only used on the iPhone simulator, where normal extended attributes are broken.
|
|
1314
|
+
// See full explanation in the header file.
|
|
1315
|
+
|
|
1316
|
+
if ([attrName length] == 0) return;
|
|
1317
|
+
|
|
1318
|
+
// Example:
|
|
1319
|
+
// attrName = "archived"
|
|
1320
|
+
//
|
|
1321
|
+
// "mylog.txt" -> "mylog.archived.txt"
|
|
1322
|
+
// "mylog" -> "mylog.archived"
|
|
1323
|
+
|
|
1324
|
+
NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
|
|
1325
|
+
|
|
1326
|
+
NSUInteger count = [components count];
|
|
1327
|
+
|
|
1328
|
+
NSUInteger estimatedNewLength = [[self fileName] length] + [attrName length] + 1;
|
|
1329
|
+
NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
|
|
1330
|
+
|
|
1331
|
+
if (count > 0)
|
|
1332
|
+
{
|
|
1333
|
+
[newFileName appendString:[components objectAtIndex:0]];
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
NSString *lastExt = @"";
|
|
1337
|
+
|
|
1338
|
+
NSUInteger i;
|
|
1339
|
+
for (i = 1; i < count; i++)
|
|
1340
|
+
{
|
|
1341
|
+
NSString *attr = [components objectAtIndex:i];
|
|
1342
|
+
if ([attr length] == 0)
|
|
1343
|
+
{
|
|
1344
|
+
continue;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
if ([attrName isEqualToString:attr])
|
|
1348
|
+
{
|
|
1349
|
+
// Extension attribute already exists in file name
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
if ([lastExt length] > 0)
|
|
1354
|
+
{
|
|
1355
|
+
[newFileName appendFormat:@".%@", lastExt];
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
lastExt = attr;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
[newFileName appendFormat:@".%@", attrName];
|
|
1362
|
+
|
|
1363
|
+
if ([lastExt length] > 0)
|
|
1364
|
+
{
|
|
1365
|
+
[newFileName appendFormat:@".%@", lastExt];
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
[self renameFile:newFileName];
|
|
1216
1369
|
}
|
|
1217
1370
|
|
|
1218
1371
|
- (void)removeExtensionAttributeWithName:(NSString *)attrName
|
|
1219
1372
|
{
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1373
|
+
// This method is only used on the iPhone simulator, where normal extended attributes are broken.
|
|
1374
|
+
// See full explanation in the header file.
|
|
1375
|
+
|
|
1376
|
+
if ([attrName length] == 0) return;
|
|
1377
|
+
|
|
1378
|
+
// Example:
|
|
1379
|
+
// attrName = "archived"
|
|
1380
|
+
//
|
|
1381
|
+
// "mylog.archived.txt" -> "mylog.txt"
|
|
1382
|
+
// "mylog.archived" -> "mylog"
|
|
1383
|
+
|
|
1384
|
+
NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
|
|
1385
|
+
|
|
1386
|
+
NSUInteger count = [components count];
|
|
1387
|
+
|
|
1388
|
+
NSUInteger estimatedNewLength = [[self fileName] length];
|
|
1389
|
+
NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
|
|
1390
|
+
|
|
1391
|
+
if (count > 0)
|
|
1392
|
+
{
|
|
1393
|
+
[newFileName appendString:[components objectAtIndex:0]];
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
BOOL found = NO;
|
|
1397
|
+
|
|
1398
|
+
NSUInteger i;
|
|
1399
|
+
for (i = 1; i < count; i++)
|
|
1400
|
+
{
|
|
1401
|
+
NSString *attr = [components objectAtIndex:i];
|
|
1402
|
+
|
|
1403
|
+
if ([attrName isEqualToString:attr])
|
|
1404
|
+
{
|
|
1405
|
+
found = YES;
|
|
1406
|
+
}
|
|
1407
|
+
else
|
|
1408
|
+
{
|
|
1409
|
+
[newFileName appendFormat:@".%@", attr];
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
if (found)
|
|
1414
|
+
{
|
|
1415
|
+
[self renameFile:newFileName];
|
|
1416
|
+
}
|
|
1263
1417
|
}
|
|
1264
1418
|
|
|
1265
1419
|
#else
|
|
1266
1420
|
|
|
1267
1421
|
- (BOOL)hasExtendedAttributeWithName:(NSString *)attrName
|
|
1268
1422
|
{
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1423
|
+
const char *path = [filePath UTF8String];
|
|
1424
|
+
const char *name = [attrName UTF8String];
|
|
1425
|
+
|
|
1426
|
+
ssize_t result = getxattr(path, name, NULL, 0, 0, 0);
|
|
1427
|
+
|
|
1428
|
+
return (result >= 0);
|
|
1275
1429
|
}
|
|
1276
1430
|
|
|
1277
1431
|
- (void)addExtendedAttributeWithName:(NSString *)attrName
|
|
1278
1432
|
{
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1433
|
+
const char *path = [filePath UTF8String];
|
|
1434
|
+
const char *name = [attrName UTF8String];
|
|
1435
|
+
|
|
1436
|
+
int result = setxattr(path, name, NULL, 0, 0, 0);
|
|
1437
|
+
|
|
1438
|
+
if (result < 0)
|
|
1439
|
+
{
|
|
1440
|
+
NSLogError(@"DDLogFileInfo: setxattr(%@, %@): error = %s",
|
|
1441
|
+
attrName,
|
|
1442
|
+
self.fileName,
|
|
1443
|
+
strerror(errno));
|
|
1444
|
+
}
|
|
1288
1445
|
}
|
|
1289
1446
|
|
|
1290
1447
|
- (void)removeExtendedAttributeWithName:(NSString *)attrName
|
|
1291
1448
|
{
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1449
|
+
const char *path = [filePath UTF8String];
|
|
1450
|
+
const char *name = [attrName UTF8String];
|
|
1451
|
+
|
|
1452
|
+
int result = removexattr(path, name, 0);
|
|
1453
|
+
|
|
1454
|
+
if (result < 0 && errno != ENOATTR)
|
|
1455
|
+
{
|
|
1456
|
+
NSLogError(@"DDLogFileInfo: removexattr(%@, %@): error = %s",
|
|
1457
|
+
attrName,
|
|
1458
|
+
self.fileName,
|
|
1459
|
+
strerror(errno));
|
|
1460
|
+
}
|
|
1301
1461
|
}
|
|
1302
1462
|
|
|
1303
1463
|
#endif
|
|
@@ -1308,46 +1468,72 @@
|
|
|
1308
1468
|
|
|
1309
1469
|
- (BOOL)isEqual:(id)object
|
|
1310
1470
|
{
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1471
|
+
if ([object isKindOfClass:[self class]])
|
|
1472
|
+
{
|
|
1473
|
+
DDLogFileInfo *another = (DDLogFileInfo *)object;
|
|
1474
|
+
|
|
1475
|
+
return [filePath isEqualToString:[another filePath]];
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
return NO;
|
|
1319
1479
|
}
|
|
1320
1480
|
|
|
1321
1481
|
- (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another
|
|
1322
1482
|
{
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1483
|
+
NSDate *us = [self creationDate];
|
|
1484
|
+
NSDate *them = [another creationDate];
|
|
1485
|
+
|
|
1486
|
+
NSComparisonResult result = [us compare:them];
|
|
1487
|
+
|
|
1488
|
+
if (result == NSOrderedAscending)
|
|
1489
|
+
return NSOrderedDescending;
|
|
1490
|
+
|
|
1491
|
+
if (result == NSOrderedDescending)
|
|
1492
|
+
return NSOrderedAscending;
|
|
1493
|
+
|
|
1494
|
+
return NSOrderedSame;
|
|
1335
1495
|
}
|
|
1336
1496
|
|
|
1337
1497
|
- (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another
|
|
1338
1498
|
{
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1499
|
+
NSDate *us = [self modificationDate];
|
|
1500
|
+
NSDate *them = [another modificationDate];
|
|
1501
|
+
|
|
1502
|
+
NSComparisonResult result = [us compare:them];
|
|
1503
|
+
|
|
1504
|
+
if (result == NSOrderedAscending)
|
|
1505
|
+
return NSOrderedDescending;
|
|
1506
|
+
|
|
1507
|
+
if (result == NSOrderedDescending)
|
|
1508
|
+
return NSOrderedAscending;
|
|
1509
|
+
|
|
1510
|
+
return NSOrderedSame;
|
|
1351
1511
|
}
|
|
1352
1512
|
|
|
1353
1513
|
@end
|
|
1514
|
+
|
|
1515
|
+
#if TARGET_OS_IPHONE
|
|
1516
|
+
/**
|
|
1517
|
+
* When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen.
|
|
1518
|
+
*
|
|
1519
|
+
* But in case if app is able to launch from background we need to have an ability to open log file any time we
|
|
1520
|
+
* want (even if device is locked). Thats why that attribute have to be changed to
|
|
1521
|
+
* NSFileProtectionCompleteUntilFirstUserAuthentication.
|
|
1522
|
+
*/
|
|
1523
|
+
BOOL doesAppRunInBackground()
|
|
1524
|
+
{
|
|
1525
|
+
BOOL answer = NO;
|
|
1526
|
+
|
|
1527
|
+
NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
|
|
1528
|
+
|
|
1529
|
+
for (NSString *mode in backgroundModes) {
|
|
1530
|
+
if (mode.length > 0) {
|
|
1531
|
+
answer = YES;
|
|
1532
|
+
break;
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
return answer;
|
|
1537
|
+
}
|
|
1538
|
+
#endif
|
|
1539
|
+
|