motion-yapper 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (296) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/.travis.yml +2 -0
  4. data/Gemfile +1 -0
  5. data/README.md +1 -1
  6. data/Rakefile +1 -1
  7. data/lib/motion-yapper.rb +1 -0
  8. data/lib/yapper.rb +3 -5
  9. data/lib/yapper/config.rb +2 -0
  10. data/lib/yapper/db.rb +105 -40
  11. data/lib/yapper/document.rb +7 -4
  12. data/lib/yapper/document/callbacks.rb +0 -7
  13. data/lib/yapper/document/{persistance.rb → persistence.rb} +27 -21
  14. data/lib/yapper/document/relation.rb +29 -22
  15. data/lib/yapper/document/selection.rb +122 -54
  16. data/lib/yapper/extensions.rb +12 -24
  17. data/lib/yapper/settings.rb +43 -0
  18. data/lib/yapper/timestamps.rb +2 -0
  19. data/lib/yapper/version.rb +1 -1
  20. data/{yapper.gemspec → motion-yapper.gemspec} +0 -0
  21. data/spec/integration/{where_spec.rb → criteria_spec.rb} +78 -10
  22. data/spec/integration/db_spec.rb +70 -0
  23. data/spec/integration/defaults_spec.rb +37 -0
  24. data/spec/integration/extensions_spec.rb +14 -0
  25. data/spec/integration/{persistance_spec.rb → persistence_spec.rb} +0 -0
  26. data/spec/integration/relation_spec.rb +4 -4
  27. data/vendor/Podfile.lock +9 -11
  28. data/vendor/Pods/.build/libPods-CocoaLumberjack.a +0 -0
  29. data/vendor/Pods/.build/libPods-NSData+MD5Digest.a +0 -0
  30. data/vendor/Pods/.build/libPods-YapDatabase.a +0 -0
  31. data/vendor/Pods/.build/libPods.a +0 -0
  32. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h +4 -4
  33. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h +14 -14
  34. data/vendor/Pods/{CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.h → BuildHeaders/CocoaLumberjack/DDContextFilterLogFormatter.h} +6 -8
  35. data/vendor/Pods/BuildHeaders/CocoaLumberjack/{DispatchQueueLogFormatter.h → DDDispatchQueueLogFormatter.h} +18 -6
  36. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h +67 -32
  37. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog+LOGV.h +99 -0
  38. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDLog.h +98 -65
  39. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDMultiFormatter.h +30 -0
  40. data/vendor/Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h +39 -25
  41. data/vendor/Pods/BuildHeaders/YapDatabase/NSDictionary+YapDatabase.h +8 -0
  42. data/vendor/Pods/BuildHeaders/YapDatabase/YapCache.h +1 -0
  43. data/vendor/Pods/BuildHeaders/YapDatabase/YapCollectionKey.h +3 -0
  44. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabase.h +4 -4
  45. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseConnection.h +21 -19
  46. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseDefaults.h +1 -1
  47. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseExtensionPrivate.h +35 -31
  48. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredView.h +8 -35
  49. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewPrivate.h +0 -2
  50. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTransaction.h +17 -17
  51. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFilteredViewTypes.h +32 -0
  52. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseFullTextSearchPrivate.h +8 -0
  53. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabasePrivate.h +43 -21
  54. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationship.h +35 -0
  55. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipConnection.h +29 -0
  56. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdge.h +163 -0
  57. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipEdgePrivate.h +79 -0
  58. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipNode.h +99 -0
  59. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipOptions.h +59 -0
  60. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipPrivate.h +125 -0
  61. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseRelationshipTransaction.h +384 -0
  62. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndex.h +49 -0
  63. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +10 -0
  64. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseSecondaryIndexSetupPrivate.h +18 -0
  65. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseTransaction.h +131 -21
  66. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseView.h +48 -107
  67. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewChange.h +2 -2
  68. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewConnection.h +1 -0
  69. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewMappings.h +17 -0
  70. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewOptions.h +10 -3
  71. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewPrivate.h +18 -1
  72. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTransaction.h +75 -24
  73. data/vendor/Pods/BuildHeaders/YapDatabase/YapDatabaseViewTypes.h +99 -0
  74. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h +4 -4
  75. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m +51 -50
  76. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h +14 -14
  77. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m +546 -546
  78. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h +67 -32
  79. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m +1093 -907
  80. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog+LOGV.h +99 -0
  81. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.h +98 -65
  82. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDLog.m +873 -748
  83. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h +39 -25
  84. data/vendor/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m +1284 -1243
  85. data/vendor/Pods/{BuildHeaders/CocoaLumberjack/ContextFilterLogFormatter.h → CocoaLumberjack/Lumberjack/Extensions/DDContextFilterLogFormatter.h} +6 -8
  86. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/{ContextFilterLogFormatter.m → DDContextFilterLogFormatter.m} +70 -70
  87. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/{DispatchQueueLogFormatter.h → DDDispatchQueueLogFormatter.h} +18 -6
  88. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDDispatchQueueLogFormatter.m +253 -0
  89. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.h +30 -0
  90. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DDMultiFormatter.m +127 -0
  91. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/README.txt +1 -1
  92. data/vendor/Pods/CocoaLumberjack/README.markdown +52 -15
  93. data/vendor/Pods/Headers/CocoaLumberjack/DDASLLogger.h +4 -4
  94. data/vendor/Pods/Headers/CocoaLumberjack/DDAbstractDatabaseLogger.h +14 -14
  95. data/vendor/Pods/Headers/CocoaLumberjack/{ContextFilterLogFormatter.h → DDContextFilterLogFormatter.h} +6 -8
  96. data/vendor/Pods/Headers/CocoaLumberjack/{DispatchQueueLogFormatter.h → DDDispatchQueueLogFormatter.h} +18 -6
  97. data/vendor/Pods/Headers/CocoaLumberjack/DDFileLogger.h +67 -32
  98. data/vendor/Pods/Headers/CocoaLumberjack/DDLog+LOGV.h +99 -0
  99. data/vendor/Pods/Headers/CocoaLumberjack/DDLog.h +98 -65
  100. data/vendor/Pods/Headers/CocoaLumberjack/DDMultiFormatter.h +30 -0
  101. data/vendor/Pods/Headers/CocoaLumberjack/DDTTYLogger.h +39 -25
  102. data/vendor/Pods/Headers/YapDatabase/YapCollectionKey.h +3 -0
  103. data/vendor/Pods/Headers/YapDatabase/YapDatabase.h +4 -4
  104. data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnection.h +21 -19
  105. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredView.h +8 -35
  106. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTransaction.h +17 -17
  107. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewTypes.h +32 -0
  108. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationship.h +35 -0
  109. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipConnection.h +29 -0
  110. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipEdge.h +163 -0
  111. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipNode.h +99 -0
  112. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipOptions.h +59 -0
  113. data/vendor/Pods/Headers/YapDatabase/YapDatabaseRelationshipTransaction.h +384 -0
  114. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndex.h +49 -0
  115. data/vendor/Pods/Headers/YapDatabase/YapDatabaseTransaction.h +131 -21
  116. data/vendor/Pods/Headers/YapDatabase/YapDatabaseView.h +48 -107
  117. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChange.h +2 -2
  118. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewConnection.h +1 -0
  119. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappings.h +17 -0
  120. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewOptions.h +10 -3
  121. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTransaction.h +75 -24
  122. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewTypes.h +99 -0
  123. data/vendor/Pods/Headers/____Pods-CocoaLumberjack-prefix.h +2 -0
  124. data/vendor/Pods/Headers/____Pods-environment.h +15 -15
  125. data/vendor/Pods/Manifest.lock +9 -11
  126. data/vendor/Pods/Pods-CocoaLumberjack-Private.xcconfig +1 -1
  127. data/vendor/Pods/Pods-CocoaLumberjack-prefix.pch +2 -0
  128. data/vendor/Pods/Pods-NSData+MD5Digest-Private.xcconfig +1 -1
  129. data/vendor/Pods/Pods-YapDatabase-Private.xcconfig +1 -1
  130. data/vendor/Pods/{Pods-Acknowledgements.markdown → Pods-acknowledgements.markdown} +0 -37
  131. data/vendor/Pods/{Pods-Acknowledgements.plist → Pods-acknowledgements.plist} +0 -45
  132. data/vendor/Pods/Pods-environment.h +15 -15
  133. data/vendor/Pods/Pods.xcconfig +3 -3
  134. data/vendor/Pods/Pods.xcodeproj/project.pbxproj +2426 -3155
  135. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-CocoaLumberjack.xcscheme +59 -0
  136. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-NSData+MD5Digest.xcscheme +59 -0
  137. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods-YapDatabase.xcscheme +59 -0
  138. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/Pods.xcscheme +59 -0
  139. data/vendor/Pods/Pods.xcodeproj/xcuserdata/kareemk.xcuserdatad/xcschemes/xcschememanagement.plist +31 -0
  140. data/vendor/Pods/YapDatabase/README.md +3 -1
  141. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/Internal/YapDatabaseFilteredViewPrivate.h +0 -2
  142. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.h +8 -35
  143. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredView.m +25 -41
  144. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.h +17 -17
  145. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTransaction.m +403 -134
  146. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FilteredViews/YapDatabaseFilteredViewTypes.h +32 -0
  147. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/Internal/YapDatabaseFullTextSearchPrivate.h +8 -0
  148. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchConnection.m +8 -8
  149. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/FullTextSearch/YapDatabaseFullTextSearchTransaction.m +113 -62
  150. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/Internal/YapDatabaseExtensionPrivate.h +35 -31
  151. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtension.m +25 -0
  152. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionConnection.m +1 -1
  153. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Protocol/YapDatabaseExtensionTransaction.m +25 -1
  154. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipEdgePrivate.h +79 -0
  155. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/Internal/YapDatabaseRelationshipPrivate.h +125 -0
  156. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.h +35 -0
  157. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationship.m +129 -0
  158. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.h +29 -0
  159. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipConnection.m +802 -0
  160. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.h +163 -0
  161. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipEdge.m +408 -0
  162. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipNode.h +99 -0
  163. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.h +59 -0
  164. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipOptions.m +29 -0
  165. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.h +384 -0
  166. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Relationships/YapDatabaseRelationshipTransaction.m +5254 -0
  167. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexPrivate.h +10 -0
  168. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/Internal/YapDatabaseSecondaryIndexSetupPrivate.h +18 -0
  169. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.h +49 -0
  170. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndex.m +12 -0
  171. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexConnection.m +9 -8
  172. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexSetup.m +62 -1
  173. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/SecondaryIndex/YapDatabaseSecondaryIndexTransaction.m +148 -45
  174. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Internal/YapDatabaseViewPrivate.h +18 -1
  175. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.h +2 -2
  176. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewChange.m +15 -9
  177. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.h +17 -0
  178. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/Utilities/YapDatabaseViewMappings.m +211 -64
  179. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.h +48 -107
  180. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseView.m +10 -7
  181. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.h +1 -0
  182. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewConnection.m +13 -22
  183. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewOptions.h +10 -3
  184. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.h +75 -24
  185. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.m +725 -244
  186. data/vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTypes.h +99 -0
  187. data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.h +8 -0
  188. data/vendor/Pods/YapDatabase/YapDatabase/Internal/NSDictionary+YapDatabase.m +19 -0
  189. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.h +1 -0
  190. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapCache.m +12 -0
  191. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.h +1 -1
  192. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabaseDefaults.m +3 -3
  193. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapDatabasePrivate.h +43 -21
  194. data/vendor/Pods/YapDatabase/YapDatabase/Internal/YapNull.m +4 -0
  195. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.h +3 -0
  196. data/vendor/Pods/YapDatabase/YapDatabase/Utilities/YapCollectionKey.m +5 -0
  197. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.h +4 -4
  198. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabase.m +84 -93
  199. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.h +21 -19
  200. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseConnection.m +381 -209
  201. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.h +131 -21
  202. data/vendor/Pods/YapDatabase/YapDatabase/YapDatabaseTransaction.m +587 -267
  203. data/vendor/Pods/{Pods.bridgesupport → build-iPhoneSimulator/Pods.bridgesupport} +633 -2557
  204. data/vendor/Pods/build-iPhoneSimulator/libPods.a +0 -0
  205. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.bridgesupport +2 -1
  206. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.h +2 -1
  207. data/vendor/YapDatabaseRubyMotion/YapDatabaseRubyMotion.m +4 -2
  208. metadata +80 -108
  209. data/Gemfile.lock +0 -63
  210. data/lib/yapper/attachment.rb +0 -48
  211. data/lib/yapper/document/attachment.rb +0 -26
  212. data/lib/yapper/sync.rb +0 -134
  213. data/lib/yapper/sync/data.rb +0 -12
  214. data/lib/yapper/sync/event.rb +0 -194
  215. data/lib/yapper/sync/queue.rb +0 -164
  216. data/spec/integration/all_spec.rb +0 -40
  217. data/spec/integration/sync_spec.rb +0 -42
  218. data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPClient.h +0 -641
  219. data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPClient.m +0 -1396
  220. data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h +0 -133
  221. data/vendor/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m +0 -327
  222. data/vendor/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h +0 -113
  223. data/vendor/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m +0 -321
  224. data/vendor/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h +0 -71
  225. data/vendor/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m +0 -150
  226. data/vendor/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h +0 -75
  227. data/vendor/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m +0 -157
  228. data/vendor/Pods/AFNetworking/AFNetworking/AFNetworking.h +0 -43
  229. data/vendor/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h +0 -68
  230. data/vendor/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m +0 -143
  231. data/vendor/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h +0 -370
  232. data/vendor/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m +0 -848
  233. data/vendor/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h +0 -89
  234. data/vendor/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m +0 -167
  235. data/vendor/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h +0 -78
  236. data/vendor/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m +0 -191
  237. data/vendor/Pods/AFNetworking/LICENSE +0 -19
  238. data/vendor/Pods/AFNetworking/README.md +0 -208
  239. data/vendor/Pods/BuildHeaders/AFNetworking/AFHTTPClient.h +0 -641
  240. data/vendor/Pods/BuildHeaders/AFNetworking/AFHTTPRequestOperation.h +0 -133
  241. data/vendor/Pods/BuildHeaders/AFNetworking/AFImageRequestOperation.h +0 -113
  242. data/vendor/Pods/BuildHeaders/AFNetworking/AFJSONRequestOperation.h +0 -71
  243. data/vendor/Pods/BuildHeaders/AFNetworking/AFNetworkActivityIndicatorManager.h +0 -75
  244. data/vendor/Pods/BuildHeaders/AFNetworking/AFNetworking.h +0 -43
  245. data/vendor/Pods/BuildHeaders/AFNetworking/AFPropertyListRequestOperation.h +0 -68
  246. data/vendor/Pods/BuildHeaders/AFNetworking/AFURLConnectionOperation.h +0 -370
  247. data/vendor/Pods/BuildHeaders/AFNetworking/AFXMLRequestOperation.h +0 -89
  248. data/vendor/Pods/BuildHeaders/AFNetworking/UIImageView+AFNetworking.h +0 -78
  249. data/vendor/Pods/BuildHeaders/Reachability/Reachability.h +0 -109
  250. data/vendor/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.m +0 -251
  251. data/vendor/Pods/Headers/AFNetworking/AFHTTPClient.h +0 -641
  252. data/vendor/Pods/Headers/AFNetworking/AFHTTPRequestOperation.h +0 -133
  253. data/vendor/Pods/Headers/AFNetworking/AFImageRequestOperation.h +0 -113
  254. data/vendor/Pods/Headers/AFNetworking/AFJSONRequestOperation.h +0 -71
  255. data/vendor/Pods/Headers/AFNetworking/AFNetworkActivityIndicatorManager.h +0 -75
  256. data/vendor/Pods/Headers/AFNetworking/AFNetworking.h +0 -43
  257. data/vendor/Pods/Headers/AFNetworking/AFPropertyListRequestOperation.h +0 -68
  258. data/vendor/Pods/Headers/AFNetworking/AFURLConnectionOperation.h +0 -370
  259. data/vendor/Pods/Headers/AFNetworking/AFXMLRequestOperation.h +0 -89
  260. data/vendor/Pods/Headers/AFNetworking/UIImageView+AFNetworking.h +0 -78
  261. data/vendor/Pods/Headers/Reachability/Reachability.h +0 -109
  262. data/vendor/Pods/Headers/YapDatabase/YapCache.h +0 -90
  263. data/vendor/Pods/Headers/YapDatabase/YapDatabaseConnectionState.h +0 -29
  264. data/vendor/Pods/Headers/YapDatabase/YapDatabaseDefaults.h +0 -37
  265. data/vendor/Pods/Headers/YapDatabase/YapDatabaseExtensionPrivate.h +0 -440
  266. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFilteredViewPrivate.h +0 -19
  267. data/vendor/Pods/Headers/YapDatabase/YapDatabaseFullTextSearchPrivate.h +0 -69
  268. data/vendor/Pods/Headers/YapDatabase/YapDatabaseLogging.h +0 -158
  269. data/vendor/Pods/Headers/YapDatabase/YapDatabaseManager.h +0 -17
  270. data/vendor/Pods/Headers/YapDatabase/YapDatabasePrivate.h +0 -424
  271. data/vendor/Pods/Headers/YapDatabase/YapDatabaseSecondaryIndexPrivate.h +0 -73
  272. data/vendor/Pods/Headers/YapDatabase/YapDatabaseStatement.h +0 -13
  273. data/vendor/Pods/Headers/YapDatabase/YapDatabaseString.h +0 -121
  274. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewChangePrivate.h +0 -94
  275. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewMappingsPrivate.h +0 -72
  276. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPage.h +0 -36
  277. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPageMetadata.h +0 -27
  278. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewPrivate.h +0 -153
  279. data/vendor/Pods/Headers/YapDatabase/YapDatabaseViewRangeOptionsPrivate.h +0 -17
  280. data/vendor/Pods/Headers/YapDatabase/YapMemoryTable.h +0 -74
  281. data/vendor/Pods/Headers/YapDatabase/YapNull.h +0 -17
  282. data/vendor/Pods/Headers/YapDatabase/YapTouch.h +0 -15
  283. data/vendor/Pods/Headers/____Pods-AFNetworking-prefix.h +0 -17
  284. data/vendor/Pods/Headers/____Pods-Reachability-prefix.h +0 -5
  285. data/vendor/Pods/Pods-AFNetworking-Private.xcconfig +0 -5
  286. data/vendor/Pods/Pods-AFNetworking-dummy.m +0 -5
  287. data/vendor/Pods/Pods-AFNetworking-prefix.pch +0 -17
  288. data/vendor/Pods/Pods-AFNetworking.xcconfig +0 -1
  289. data/vendor/Pods/Pods-Reachability-Private.xcconfig +0 -5
  290. data/vendor/Pods/Pods-Reachability-dummy.m +0 -5
  291. data/vendor/Pods/Pods-Reachability-prefix.pch +0 -5
  292. data/vendor/Pods/Pods-Reachability.xcconfig +0 -1
  293. data/vendor/Pods/Reachability/LICENCE.txt +0 -24
  294. data/vendor/Pods/Reachability/README.md +0 -65
  295. data/vendor/Pods/Reachability/Reachability.h +0 -109
  296. 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/robbiehanson/CocoaLumberjack
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/robbiehanson/CocoaLumberjack/wiki/GettingStarted
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-<uuid>.txt",
112
- * where uuid is a 6 character hexadecimal consisting of the set [0123456789ABCDEF].
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
- NSUInteger maximumNumberOfLogFiles;
119
- NSString *_logsDirectory;
118
+ NSUInteger maximumNumberOfLogFiles;
119
+ NSString *_logsDirectory;
120
120
  }
121
121
 
122
122
  - (id)init;
123
- - (id)initWithLogsDirectory:(NSString *)logsDirectory;
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
- NSDateFormatter *dateFormatter;
187
+ NSDateFormatter *dateFormatter;
160
188
  }
161
189
 
162
190
  - (id)init;
163
- - (id)initWithDateFormatter:(NSDateFormatter *)dateFormatter;
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
- __strong id <DDLogFileManager> logFileManager;
174
-
175
- DDLogFileInfo *currentLogFileInfo;
176
- NSFileHandle *currentLogFileHandle;
177
-
178
- dispatch_source_t rollingTimer;
179
-
180
- unsigned long long maximumFileSize;
181
- NSTimeInterval rollingFrequency;
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
- - (id)initWithLogFileManager:(id <DDLogFileManager>)logFileManager;
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
- __strong NSString *filePath;
262
- __strong NSString *fileName;
263
-
264
- __strong NSDictionary *fileAttributes;
265
-
266
- __strong NSDate *creationDate;
267
- __strong NSDate *modificationDate;
268
-
269
- unsigned long long fileSize;
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
- + (id)logFileWithPath:(NSString *)filePath;
320
+ + (instancetype)logFileWithPath:(NSString *)filePath;
287
321
 
288
- - (id)initWithFilePath:(NSString *)filePath;
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
- // log-ABC123.txt -> log-ABC123.archived.txt
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/robbiehanson/CocoaLumberjack
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/robbiehanson/CocoaLumberjack/wiki/GettingStarted
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 NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
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
- return [self initWithLogsDirectory:nil];
66
+ return [self initWithLogsDirectory:nil];
62
67
  }
63
68
 
64
- - (id)initWithLogsDirectory:(NSString *)aLogsDirectory
69
+ - (instancetype)initWithLogsDirectory:(NSString *)aLogsDirectory
65
70
  {
66
- if ((self = [super init]))
67
- {
68
- maximumNumberOfLogFiles = DEFAULT_LOG_MAX_NUM_LOG_FILES;
69
-
70
- if (aLogsDirectory)
71
- _logsDirectory = [aLogsDirectory copy];
72
- else
73
- _logsDirectory = [[self defaultLogsDirectory] copy];
74
-
75
- NSKeyValueObservingOptions kvoOptions = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
76
-
77
- [self addObserver:self forKeyPath:@"maximumNumberOfLogFiles" options:kvoOptions context:nil];
78
-
79
- NSLogVerbose(@"DDFileLogManagerDefault: logsDirectory:\n%@", [self logsDirectory]);
80
- NSLogVerbose(@"DDFileLogManagerDefault: sortedLogFileNames:\n%@", [self sortedLogFileNames]);
81
- }
82
- return self;
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
- [self removeObserver:self forKeyPath:@"maximumNumberOfLogFiles"];
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
- NSNumber *old = [change objectForKey:NSKeyValueChangeOldKey];
100
- NSNumber *new = [change objectForKey:NSKeyValueChangeNewKey];
101
-
102
- if ([old isEqual:new])
103
- {
104
- // No change in value - don't bother with any processing.
105
- return;
106
- }
107
-
108
- if ([keyPath isEqualToString:@"maximumNumberOfLogFiles"])
109
- {
110
- NSLogInfo(@"DDFileLogManagerDefault: Responding to configuration change: maximumNumberOfLogFiles");
111
-
112
- dispatch_async([DDLog loggingQueue], ^{ @autoreleasepool {
113
-
114
- [self deleteOldLogFiles];
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
- NSLogVerbose(@"DDLogFileManagerDefault: deleteOldLogFiles");
129
-
130
- NSUInteger maxNumLogFiles = self.maximumNumberOfLogFiles;
131
- if (maxNumLogFiles == 0)
132
- {
133
- // Unlimited - don't delete any log files
134
- return;
135
- }
136
-
137
- NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
138
-
139
- // Do we consider the first file?
140
- // We are only supposed to be deleting archived files.
141
- // In most cases, the first file is likely the log file that is currently being written to.
142
- // So in most cases, we do not want to consider this file for deletion.
143
-
144
- NSUInteger count = [sortedLogFileInfos count];
145
- BOOL excludeFirstFile = NO;
146
-
147
- if (count > 0)
148
- {
149
- DDLogFileInfo *logFileInfo = [sortedLogFileInfos objectAtIndex:0];
150
-
151
- if (!logFileInfo.isArchived)
152
- {
153
- excludeFirstFile = YES;
154
- }
155
- }
156
-
157
- NSArray *sortedArchivedLogFileInfos;
158
- if (excludeFirstFile)
159
- {
160
- count--;
161
- sortedArchivedLogFileInfos = [sortedLogFileInfos subarrayWithRange:NSMakeRange(1, count)];
162
- }
163
- else
164
- {
165
- sortedArchivedLogFileInfos = sortedLogFileInfos;
166
- }
167
-
168
- NSUInteger i;
169
- for (i = maxNumLogFiles; i < count; i++)
170
- {
171
- DDLogFileInfo *logFileInfo = [sortedArchivedLogFileInfos objectAtIndex:i];
172
-
173
- NSLogInfo(@"DDLogFileManagerDefault: Deleting file: %@", logFileInfo.fileName);
174
-
175
- [[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:nil];
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
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
191
- NSString *baseDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
192
- NSString *logsDirectory = [baseDir stringByAppendingPathComponent:@"Logs"];
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
- NSString *appName = [[NSProcessInfo processInfo] processName];
196
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
197
- NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
198
- NSString *logsDirectory = [[basePath stringByAppendingPathComponent:@"Logs"] stringByAppendingPathComponent:appName];
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
- return logsDirectory;
213
+ return logsDirectory;
203
214
  }
204
215
 
205
216
  - (NSString *)logsDirectory
206
217
  {
207
- // We could do this check once, during initalization, and not bother again.
208
- // But this way the code continues to work if the directory gets deleted while the code is running.
209
-
210
- if (![[NSFileManager defaultManager] fileExistsAtPath:_logsDirectory])
211
- {
212
- NSError *err = nil;
213
- if (![[NSFileManager defaultManager] createDirectoryAtPath:_logsDirectory
214
- withIntermediateDirectories:YES attributes:nil error:&err])
215
- {
216
- NSLogError(@"DDFileLogManagerDefault: Error creating logsDirectory: %@", err);
217
- }
218
- }
219
-
220
- return _logsDirectory;
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
- // A log file has a name like "log-<uuid>.txt", where <uuid> is a HEX-string of 6 characters.
226
- //
227
- // For example: log-DFFE99.txt
228
-
229
- BOOL hasProperPrefix = [fileName hasPrefix:@"log-"];
230
-
231
- BOOL hasProperLength = [fileName length] >= 10;
232
-
233
-
234
- if (hasProperPrefix && hasProperLength)
235
- {
236
- NSCharacterSet *hexSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"];
237
-
238
- NSString *hex = [fileName substringWithRange:NSMakeRange(4, 6)];
239
- NSString *nohex = [hex stringByTrimmingCharactersInSet:hexSet];
240
-
241
- if ([nohex length] == 0)
242
- {
243
- return YES;
244
- }
245
- }
246
-
247
- return NO;
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
- NSString *logsDirectory = [self logsDirectory];
257
- NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logsDirectory error:nil];
258
-
259
- NSMutableArray *unsortedLogFilePaths = [NSMutableArray arrayWithCapacity:[fileNames count]];
260
-
261
- for (NSString *fileName in fileNames)
262
- {
263
- // Filter out any files that aren't log files. (Just for extra safety)
264
-
265
- if ([self isLogFile:fileName])
266
- {
267
- NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName];
268
-
269
- [unsortedLogFilePaths addObject:filePath];
270
- }
271
- }
272
-
273
- return unsortedLogFilePaths;
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
- NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
283
-
284
- NSMutableArray *unsortedLogFileNames = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
285
-
286
- for (NSString *filePath in unsortedLogFilePaths)
287
- {
288
- [unsortedLogFileNames addObject:[filePath lastPathComponent]];
289
- }
290
-
291
- return unsortedLogFileNames;
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
- NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths];
302
-
303
- NSMutableArray *unsortedLogFileInfos = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]];
304
-
305
- for (NSString *filePath in unsortedLogFilePaths)
306
- {
307
- DDLogFileInfo *logFileInfo = [[DDLogFileInfo alloc] initWithFilePath:filePath];
308
-
309
- [unsortedLogFileInfos addObject:logFileInfo];
310
- }
311
-
312
- return unsortedLogFileInfos;
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 modification date.
318
- * The first item in the array will be the most recently modified log file.
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
- NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
323
-
324
- NSMutableArray *sortedLogFilePaths = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
325
-
326
- for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
327
- {
328
- [sortedLogFilePaths addObject:[logFileInfo filePath]];
329
- }
330
-
331
- return sortedLogFilePaths;
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 modification date.
337
- * The first item in the array will be the most recently modified log file.
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
- NSArray *sortedLogFileInfos = [self sortedLogFileInfos];
342
-
343
- NSMutableArray *sortedLogFileNames = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]];
344
-
345
- for (DDLogFileInfo *logFileInfo in sortedLogFileInfos)
346
- {
347
- [sortedLogFileNames addObject:[logFileInfo fileName]];
348
- }
349
-
350
- return sortedLogFileNames;
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 modification date.
356
- * The first item in the array will be the most recently modified log file.
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
- return [[self unsortedLogFileInfos] sortedArrayUsingSelector:@selector(reverseCompareByCreationDate:)];
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 a short UUID suitable for use in the log file's name.
369
- * The result will have six characters, all in the hexadecimal set [0123456789ABCDEF].
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 *)generateShortUUID
428
+ - (NSString *)newLogFileName
372
429
  {
373
- CFUUIDRef uuid = CFUUIDCreate(NULL);
374
-
375
- CFStringRef fullStr = CFUUIDCreateString(NULL, uuid);
376
- NSString *result = (__bridge_transfer NSString *)CFStringCreateWithSubstring(NULL, fullStr, CFRangeMake(0, 6));
377
-
378
- CFRelease(fullStr);
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
- // Generate a random log file name, and create the file (if there isn't a collision)
390
-
391
- NSString *logsDirectory = [self logsDirectory];
392
- do
393
- {
394
- NSString *fileName = [NSString stringWithFormat:@"log-%@.txt", [self generateShortUUID]];
395
-
396
- NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName];
397
-
398
- if (![[NSFileManager defaultManager] fileExistsAtPath:filePath])
399
- {
400
- NSLogVerbose(@"DDLogFileManagerDefault: Creating new log file: %@", fileName);
401
-
402
- [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
403
-
404
- // Since we just created a new log file, we may need to delete some old log files
405
- [self deleteOldLogFiles];
406
-
407
- return filePath;
408
- }
409
-
410
- } while(YES);
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
- return [self initWithDateFormatter:nil];
531
+ return [self initWithDateFormatter:nil];
424
532
  }
425
533
 
426
- - (id)initWithDateFormatter:(NSDateFormatter *)aDateFormatter
534
+ - (instancetype)initWithDateFormatter:(NSDateFormatter *)aDateFormatter
427
535
  {
428
- if ((self = [super init]))
429
- {
430
- if (aDateFormatter)
431
- {
432
- dateFormatter = aDateFormatter;
433
- }
434
- else
435
- {
436
- dateFormatter = [[NSDateFormatter alloc] init];
437
- [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style
438
- [dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"];
439
- }
440
- }
441
- return self;
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
- NSString *dateAndTime = [dateFormatter stringFromDate:(logMessage->timestamp)];
447
-
448
- return [NSString stringWithFormat:@"%@ %@", dateAndTime, logMessage->logMsg];
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
- DDLogFileManagerDefault *defaultLogFileManager = [[DDLogFileManagerDefault alloc] init];
462
-
463
- return [self initWithLogFileManager:defaultLogFileManager];
569
+ DDLogFileManagerDefault *defaultLogFileManager = [[DDLogFileManagerDefault alloc] init];
570
+
571
+ return [self initWithLogFileManager:defaultLogFileManager];
464
572
  }
465
573
 
466
- - (id)initWithLogFileManager:(id <DDLogFileManager>)aLogFileManager
574
+ - (instancetype)initWithLogFileManager:(id <DDLogFileManager>)aLogFileManager
467
575
  {
468
- if ((self = [super init]))
469
- {
470
- maximumFileSize = DEFAULT_LOG_MAX_FILE_SIZE;
471
- rollingFrequency = DEFAULT_LOG_ROLLING_FREQUENCY;
472
-
473
- logFileManager = aLogFileManager;
474
-
475
- formatter = [[DDLogFileFormatterDefault alloc] init];
476
- }
477
- return self;
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
- [currentLogFileHandle synchronizeFile];
483
- [currentLogFileHandle closeFile];
484
-
485
- if (rollingTimer)
486
- {
487
- dispatch_source_cancel(rollingTimer);
488
- rollingTimer = NULL;
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
- __block unsigned long long result;
501
-
502
- dispatch_block_t block = ^{
503
- result = maximumFileSize;
504
- };
505
-
506
- // The design of this method is taken from the DDAbstractLogger implementation.
507
- // For extensive documentation please refer to the DDAbstractLogger implementation.
508
-
509
- // Note: The internal implementation MUST access the maximumFileSize variable directly,
510
- // This method is designed explicitly for external access.
511
- //
512
- // Using "self." syntax to go through this method will cause immediate deadlock.
513
- // This is the intended result. Fix it by accessing the ivar directly.
514
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
515
-
516
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
517
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
518
-
519
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
520
-
521
- dispatch_sync(globalLoggingQueue, ^{
522
- dispatch_sync(loggerQueue, block);
523
- });
524
-
525
- return result;
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
- dispatch_block_t block = ^{ @autoreleasepool {
531
-
532
- maximumFileSize = newMaximumFileSize;
533
- [self maybeRollLogFileDueToSize];
534
-
535
- }};
536
-
537
- // The design of this method is taken from the DDAbstractLogger implementation.
538
- // For extensive documentation please refer to the DDAbstractLogger implementation.
539
-
540
- // Note: The internal implementation MUST access the maximumFileSize variable directly,
541
- // This method is designed explicitly for external access.
542
- //
543
- // Using "self." syntax to go through this method will cause immediate deadlock.
544
- // This is the intended result. Fix it by accessing the ivar directly.
545
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
546
-
547
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
548
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
549
-
550
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
551
-
552
- dispatch_async(globalLoggingQueue, ^{
553
- dispatch_async(loggerQueue, block);
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
- __block NSTimeInterval result;
560
-
561
- dispatch_block_t block = ^{
562
- result = rollingFrequency;
563
- };
564
-
565
- // The design of this method is taken from the DDAbstractLogger implementation.
566
- // For extensive documentation please refer to the DDAbstractLogger implementation.
567
-
568
- // Note: The internal implementation should access the rollingFrequency variable directly,
569
- // This method is designed explicitly for external access.
570
- //
571
- // Using "self." syntax to go through this method will cause immediate deadlock.
572
- // This is the intended result. Fix it by accessing the ivar directly.
573
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
574
-
575
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
576
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
577
-
578
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
579
-
580
- dispatch_sync(globalLoggingQueue, ^{
581
- dispatch_sync(loggerQueue, block);
582
- });
583
-
584
- return result;
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
- dispatch_block_t block = ^{ @autoreleasepool {
590
-
591
- rollingFrequency = newRollingFrequency;
592
- [self maybeRollLogFileDueToAge];
593
- }};
594
-
595
- // The design of this method is taken from the DDAbstractLogger implementation.
596
- // For extensive documentation please refer to the DDAbstractLogger implementation.
597
-
598
- // Note: The internal implementation should access the rollingFrequency variable directly,
599
- // This method is designed explicitly for external access.
600
- //
601
- // Using "self." syntax to go through this method will cause immediate deadlock.
602
- // This is the intended result. Fix it by accessing the ivar directly.
603
- // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
604
-
605
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
606
- NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
607
-
608
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
609
-
610
- dispatch_async(globalLoggingQueue, ^{
611
- dispatch_async(loggerQueue, block);
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
- if (rollingTimer)
622
- {
623
- dispatch_source_cancel(rollingTimer);
624
- rollingTimer = NULL;
625
- }
626
-
627
- if (currentLogFileInfo == nil || rollingFrequency <= 0.0)
628
- {
629
- return;
630
- }
631
-
632
- NSDate *logFileCreationDate = [currentLogFileInfo creationDate];
633
-
634
- NSTimeInterval ti = [logFileCreationDate timeIntervalSinceReferenceDate];
635
- ti += rollingFrequency;
636
-
637
- NSDate *logFileRollingDate = [NSDate dateWithTimeIntervalSinceReferenceDate:ti];
638
-
639
- NSLogVerbose(@"DDFileLogger: scheduleTimerToRollLogFileDueToAge");
640
-
641
- NSLogVerbose(@"DDFileLogger: logFileCreationDate: %@", logFileCreationDate);
642
- NSLogVerbose(@"DDFileLogger: logFileRollingDate : %@", logFileRollingDate);
643
-
644
- rollingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, loggerQueue);
645
-
646
- dispatch_source_set_event_handler(rollingTimer, ^{ @autoreleasepool {
647
-
648
- [self maybeRollLogFileDueToAge];
649
-
650
- }});
651
-
652
- #if !OS_OBJECT_USE_OBJC
653
- dispatch_source_t theRollingTimer = rollingTimer;
654
- dispatch_source_set_cancel_handler(rollingTimer, ^{
655
- dispatch_release(theRollingTimer);
656
- });
657
- #endif
658
-
659
- uint64_t delay = (uint64_t)([logFileRollingDate timeIntervalSinceNow] * NSEC_PER_SEC);
660
- dispatch_time_t fireTime = dispatch_time(DISPATCH_TIME_NOW, delay);
661
-
662
- dispatch_source_set_timer(rollingTimer, fireTime, DISPATCH_TIME_FOREVER, 1.0);
663
- dispatch_resume(rollingTimer);
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
- // This method is public.
669
- // We need to execute the rolling on our logging thread/queue.
670
-
671
- dispatch_block_t block = ^{ @autoreleasepool {
672
-
673
- [self rollLogFileNow];
674
- }};
675
-
676
- // The design of this method is taken from the DDAbstractLogger implementation.
677
- // For extensive documentation please refer to the DDAbstractLogger implementation.
678
-
679
- if ([self isOnInternalLoggerQueue])
680
- {
681
- block();
682
- }
683
- else
684
- {
685
- dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
686
- NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
687
-
688
- dispatch_async(globalLoggingQueue, ^{
689
- dispatch_async(loggerQueue, block);
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
- NSLogVerbose(@"DDFileLogger: rollLogFileNow");
697
-
698
-
699
- if (currentLogFileHandle == nil) return;
700
-
701
- [currentLogFileHandle synchronizeFile];
702
- [currentLogFileHandle closeFile];
703
- currentLogFileHandle = nil;
704
-
705
- currentLogFileInfo.isArchived = YES;
706
-
707
- if ([logFileManager respondsToSelector:@selector(didRollAndArchiveLogFile:)])
708
- {
709
- [logFileManager didRollAndArchiveLogFile:(currentLogFileInfo.filePath)];
710
- }
711
-
712
- currentLogFileInfo = nil;
713
-
714
- if (rollingTimer)
715
- {
716
- dispatch_source_cancel(rollingTimer);
717
- rollingTimer = NULL;
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
- if (rollingFrequency > 0.0 && currentLogFileInfo.age >= rollingFrequency)
724
- {
725
- NSLogVerbose(@"DDFileLogger: Rolling log file due to age...");
726
-
727
- [self rollLogFileNow];
728
- }
729
- else
730
- {
731
- [self scheduleTimerToRollLogFileDueToAge];
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
- // This method is called from logMessage.
738
- // Keep it FAST.
739
-
740
- // Note: Use direct access to maximumFileSize variable.
741
- // We specifically wrote our own getter/setter method to allow us to do this (for performance reasons).
742
-
743
- if (maximumFileSize > 0)
744
- {
745
- unsigned long long fileSize = [currentLogFileHandle offsetInFile];
746
-
747
- if (fileSize >= maximumFileSize)
748
- {
749
- NSLogVerbose(@"DDFileLogger: Rolling log file due to size (%qu)...", fileSize);
750
-
751
- [self rollLogFileNow];
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
- if (currentLogFileInfo == nil)
770
- {
771
- NSArray *sortedLogFileInfos = [logFileManager sortedLogFileInfos];
772
-
773
- if ([sortedLogFileInfos count] > 0)
774
- {
775
- DDLogFileInfo *mostRecentLogFileInfo = [sortedLogFileInfos objectAtIndex:0];
776
-
777
- BOOL useExistingLogFile = YES;
778
- BOOL shouldArchiveMostRecent = NO;
779
-
780
- if (mostRecentLogFileInfo.isArchived)
781
- {
782
- useExistingLogFile = NO;
783
- shouldArchiveMostRecent = NO;
784
- }
785
- else if (maximumFileSize > 0 && mostRecentLogFileInfo.fileSize >= maximumFileSize)
786
- {
787
- useExistingLogFile = NO;
788
- shouldArchiveMostRecent = YES;
789
- }
790
- else if (rollingFrequency > 0.0 && mostRecentLogFileInfo.age >= rollingFrequency)
791
- {
792
- useExistingLogFile = NO;
793
- shouldArchiveMostRecent = YES;
794
- }
795
-
796
- if (useExistingLogFile)
797
- {
798
- NSLogVerbose(@"DDFileLogger: Resuming logging with file %@", mostRecentLogFileInfo.fileName);
799
-
800
- currentLogFileInfo = mostRecentLogFileInfo;
801
- }
802
- else
803
- {
804
- if (shouldArchiveMostRecent)
805
- {
806
- mostRecentLogFileInfo.isArchived = YES;
807
-
808
- if ([logFileManager respondsToSelector:@selector(didArchiveLogFile:)])
809
- {
810
- [logFileManager didArchiveLogFile:(mostRecentLogFileInfo.filePath)];
811
- }
812
- }
813
- }
814
- }
815
-
816
- if (currentLogFileInfo == nil)
817
- {
818
- NSString *currentLogFilePath = [logFileManager createNewLogFile];
819
-
820
- currentLogFileInfo = [[DDLogFileInfo alloc] initWithFilePath:currentLogFilePath];
821
- }
822
- }
823
-
824
- return currentLogFileInfo;
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
- if (currentLogFileHandle == nil)
830
- {
831
- NSString *logFilePath = [[self currentLogFileInfo] filePath];
832
-
833
- currentLogFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
834
- [currentLogFileHandle seekToEndOfFile];
835
-
836
- if (currentLogFileHandle)
837
- {
838
- [self scheduleTimerToRollLogFileDueToAge];
839
- }
840
- }
841
-
842
- return currentLogFileHandle;
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
- NSString *logMsg = logMessage->logMsg;
852
-
853
- if (formatter)
854
- {
855
- logMsg = [formatter formatLogMessage:logMessage];
856
- }
857
-
858
- if (logMsg)
859
- {
860
- if (![logMsg hasSuffix:@"\n"])
861
- {
862
- logMsg = [logMsg stringByAppendingString:@"\n"];
863
- }
864
-
865
- NSData *logData = [logMsg dataUsingEncoding:NSUTF8StringEncoding];
866
-
867
- [[self currentLogFileHandle] writeData:logData];
868
-
869
- [self maybeRollLogFileDueToSize];
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
- // If you override me be sure to invoke [super willRemoveLogger];
876
-
877
- [self rollLogFileNow];
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
- return @"cocoa.lumberjack.fileLogger";
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
- + (id)logFileWithPath:(NSString *)aFilePath
1099
+ + (instancetype)logFileWithPath:(NSString *)aFilePath
914
1100
  {
915
- return [[DDLogFileInfo alloc] initWithFilePath:aFilePath];
1101
+ return [[self alloc] initWithFilePath:aFilePath];
916
1102
  }
917
1103
 
918
- - (id)initWithFilePath:(NSString *)aFilePath
1104
+ - (instancetype)initWithFilePath:(NSString *)aFilePath
919
1105
  {
920
- if ((self = [super init]))
921
- {
922
- filePath = [aFilePath copy];
923
- }
924
- return self;
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
- if (fileAttributes == nil)
934
- {
935
- fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
936
- }
937
- return fileAttributes;
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
- if (fileName == nil)
943
- {
944
- fileName = [filePath lastPathComponent];
945
- }
946
- return fileName;
1128
+ if (fileName == nil)
1129
+ {
1130
+ fileName = [filePath lastPathComponent];
1131
+ }
1132
+ return fileName;
947
1133
  }
948
1134
 
949
1135
  - (NSDate *)modificationDate
950
1136
  {
951
- if (modificationDate == nil)
952
- {
953
- modificationDate = [[self fileAttributes] objectForKey:NSFileModificationDate];
954
- }
955
-
956
- return modificationDate;
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
- if (creationDate == nil)
962
- {
963
-
964
- #if TARGET_OS_IPHONE
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
- if (fileSize == 0)
1006
- {
1007
- fileSize = [[[self fileAttributes] objectForKey:NSFileSize] unsignedLongLongValue];
1008
- }
1009
-
1010
- return fileSize;
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
- return [[self creationDate] timeIntervalSinceNow] * -1.0;
1166
+ return [[self creationDate] timeIntervalSinceNow] * -1.0;
1016
1167
  }
1017
1168
 
1018
1169
  - (NSString *)description
1019
1170
  {
1020
- return [@{@"filePath": self.filePath,
1021
- @"fileName": self.fileName,
1022
- @"fileAttributes": self.fileAttributes,
1023
- @"creationDate": self.creationDate,
1024
- @"modificationDate": self.modificationDate,
1025
- @"fileSize": @(self.fileSize),
1026
- @"age": @(self.age),
1027
- @"isArchived": @(self.isArchived)} description];
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
- // Extended attributes don't work properly on the simulator.
1040
- // So we have to use a less attractive alternative.
1041
- // See full explanation in the header file.
1042
-
1043
- return [self hasExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
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
- return [self hasExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
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
- // Extended attributes don't work properly on the simulator.
1058
- // So we have to use a less attractive alternative.
1059
- // See full explanation in the header file.
1060
-
1061
- if (flag)
1062
- [self addExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
1063
- else
1064
- [self removeExtensionAttributeWithName:XATTR_ARCHIVED_NAME];
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
- if (flag)
1069
- [self addExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
1070
- else
1071
- [self removeExtendedAttributeWithName:XATTR_ARCHIVED_NAME];
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
- fileName = nil;
1083
- fileAttributes = nil;
1084
- creationDate = nil;
1085
- modificationDate = nil;
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
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1091
- // See full explanation in the header file.
1092
-
1093
- if (![newFileName isEqualToString:[self fileName]])
1094
- {
1095
- NSString *fileDir = [filePath stringByDeletingLastPathComponent];
1096
-
1097
- NSString *newFilePath = [fileDir stringByAppendingPathComponent:newFileName];
1098
-
1099
- NSLogVerbose(@"DDLogFileInfo: Renaming file: '%@' -> '%@'", self.fileName, newFileName);
1100
-
1101
- NSError *error = nil;
1102
- if (![[NSFileManager defaultManager] moveItemAtPath:filePath toPath:newFilePath error:&error])
1103
- {
1104
- NSLogError(@"DDLogFileInfo: Error renaming file (%@): %@", self.fileName, error);
1105
- }
1106
-
1107
- filePath = newFilePath;
1108
- [self reset];
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
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1125
- // See full explanation in the header file.
1126
-
1127
- // Split the file name into components.
1128
- //
1129
- // log-ABC123.archived.uploaded.txt
1130
- //
1131
- // 0. log-ABC123
1132
- // 1. archived
1133
- // 2. uploaded
1134
- // 3. txt
1135
- //
1136
- // So we want to search for the attrName in the components (ignoring the first and last array indexes).
1137
-
1138
- NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1139
-
1140
- // Watch out for file names without an extension
1141
-
1142
- NSUInteger count = [components count];
1143
- NSUInteger max = (count >= 2) ? count-1 : count;
1144
-
1145
- NSUInteger i;
1146
- for (i = 1; i < max; i++)
1147
- {
1148
- NSString *attr = [components objectAtIndex:i];
1149
-
1150
- if ([attrName isEqualToString:attr])
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
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1162
- // See full explanation in the header file.
1163
-
1164
- if ([attrName length] == 0) return;
1165
-
1166
- // Example:
1167
- // attrName = "archived"
1168
- //
1169
- // "log-ABC123.txt" -> "log-ABC123.archived.txt"
1170
-
1171
- NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1172
-
1173
- NSUInteger count = [components count];
1174
-
1175
- NSUInteger estimatedNewLength = [[self fileName] length] + [attrName length] + 1;
1176
- NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
1177
-
1178
- if (count > 0)
1179
- {
1180
- [newFileName appendString:[components objectAtIndex:0]];
1181
- }
1182
-
1183
- NSString *lastExt = @"";
1184
-
1185
- NSUInteger i;
1186
- for (i = 1; i < count; i++)
1187
- {
1188
- NSString *attr = [components objectAtIndex:i];
1189
- if ([attr length] == 0)
1190
- {
1191
- continue;
1192
- }
1193
-
1194
- if ([attrName isEqualToString:attr])
1195
- {
1196
- // Extension attribute already exists in file name
1197
- return;
1198
- }
1199
-
1200
- if ([lastExt length] > 0)
1201
- {
1202
- [newFileName appendFormat:@".%@", lastExt];
1203
- }
1204
-
1205
- lastExt = attr;
1206
- }
1207
-
1208
- [newFileName appendFormat:@".%@", attrName];
1209
-
1210
- if ([lastExt length] > 0)
1211
- {
1212
- [newFileName appendFormat:@".%@", lastExt];
1213
- }
1214
-
1215
- [self renameFile:newFileName];
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
- // This method is only used on the iPhone simulator, where normal extended attributes are broken.
1221
- // See full explanation in the header file.
1222
-
1223
- if ([attrName length] == 0) return;
1224
-
1225
- // Example:
1226
- // attrName = "archived"
1227
- //
1228
- // "log-ABC123.txt" -> "log-ABC123.archived.txt"
1229
-
1230
- NSArray *components = [[self fileName] componentsSeparatedByString:@"."];
1231
-
1232
- NSUInteger count = [components count];
1233
-
1234
- NSUInteger estimatedNewLength = [[self fileName] length];
1235
- NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength];
1236
-
1237
- if (count > 0)
1238
- {
1239
- [newFileName appendString:[components objectAtIndex:0]];
1240
- }
1241
-
1242
- BOOL found = NO;
1243
-
1244
- NSUInteger i;
1245
- for (i = 1; i < count; i++)
1246
- {
1247
- NSString *attr = [components objectAtIndex:i];
1248
-
1249
- if ([attrName isEqualToString:attr])
1250
- {
1251
- found = YES;
1252
- }
1253
- else
1254
- {
1255
- [newFileName appendFormat:@".%@", attr];
1256
- }
1257
- }
1258
-
1259
- if (found)
1260
- {
1261
- [self renameFile:newFileName];
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
- const char *path = [filePath UTF8String];
1270
- const char *name = [attrName UTF8String];
1271
-
1272
- ssize_t result = getxattr(path, name, NULL, 0, 0, 0);
1273
-
1274
- return (result >= 0);
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
- const char *path = [filePath UTF8String];
1280
- const char *name = [attrName UTF8String];
1281
-
1282
- int result = setxattr(path, name, NULL, 0, 0, 0);
1283
-
1284
- if (result < 0)
1285
- {
1286
- NSLogError(@"DDLogFileInfo: setxattr(%@, %@): error = %i", attrName, self.fileName, result);
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
- const char *path = [filePath UTF8String];
1293
- const char *name = [attrName UTF8String];
1294
-
1295
- int result = removexattr(path, name, 0);
1296
-
1297
- if (result < 0 && errno != ENOATTR)
1298
- {
1299
- NSLogError(@"DDLogFileInfo: removexattr(%@, %@): error = %i", attrName, self.fileName, result);
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
- if ([object isKindOfClass:[self class]])
1312
- {
1313
- DDLogFileInfo *another = (DDLogFileInfo *)object;
1314
-
1315
- return [filePath isEqualToString:[another filePath]];
1316
- }
1317
-
1318
- return NO;
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
- NSDate *us = [self creationDate];
1324
- NSDate *them = [another creationDate];
1325
-
1326
- NSComparisonResult result = [us compare:them];
1327
-
1328
- if (result == NSOrderedAscending)
1329
- return NSOrderedDescending;
1330
-
1331
- if (result == NSOrderedDescending)
1332
- return NSOrderedAscending;
1333
-
1334
- return NSOrderedSame;
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
- NSDate *us = [self modificationDate];
1340
- NSDate *them = [another modificationDate];
1341
-
1342
- NSComparisonResult result = [us compare:them];
1343
-
1344
- if (result == NSOrderedAscending)
1345
- return NSOrderedDescending;
1346
-
1347
- if (result == NSOrderedDescending)
1348
- return NSOrderedAscending;
1349
-
1350
- return NSOrderedSame;
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
+