From 8d4b45c50cec669ceb90c963da2f5b2f7bd2e613 Mon Sep 17 00:00:00 2001 From: slarson Date: Mon, 30 Jun 2025 15:53:07 -0700 Subject: [PATCH 01/32] First attempt to update to iOS16 --- AGENTS.md | 4 + OpenWorm.xcodeproj/project.pbxproj | 86 +- Podfile | 15 +- Podfile.lock | 48 +- .../ContextFilterLogFormatter.h | 1 - .../CocoaLumberjack/DDASLLogger.h | 1 - .../DDAbstractDatabaseLogger.h | 1 - .../CocoaLumberjack/DDFileLogger.h | 1 - Pods/BuildHeaders/CocoaLumberjack/DDLog.h | 1 - .../CocoaLumberjack/DDTTYLogger.h | 1 - .../DispatchQueueLogFormatter.h | 1 - .../DCRoundSwitch/DCRoundSwitch.h | 1 - .../DCRoundSwitch/DCRoundSwitchKnobLayer.h | 1 - .../DCRoundSwitch/DCRoundSwitchOutlineLayer.h | 1 - .../DCRoundSwitch/DCRoundSwitchToggleLayer.h | 1 - Pods/BuildHeaders/Reachability/Reachability.h | 1 - Pods/BuildHeaders/RegexKitLite/RegexKitLite.h | 1 - Pods/BuildHeaders/TestFlightSDK/TestFlight.h | 1 - Pods/BuildHeaders/iRate/iRate.h | 1 - Pods/CocoaLumberjack/CHANGELOG.md | 638 + Pods/CocoaLumberjack/CocoaLumberjack.podspec | 18 - Pods/CocoaLumberjack/LICENSE | 14 + Pods/CocoaLumberjack/LICENSE.txt | 18 - Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h | 41 - Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m | 99 - .../Lumberjack/DDAbstractDatabaseLogger.m | 654 - .../CocoaLumberjack/Lumberjack/DDFileLogger.h | 334 - .../CocoaLumberjack/Lumberjack/DDFileLogger.m | 1380 - Pods/CocoaLumberjack/Lumberjack/DDLog.h | 597 - Pods/CocoaLumberjack/Lumberjack/DDLog.m | 1067 - Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h | 167 - Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m | 1480 - .../Extensions/ContextFilterLogFormatter.h | 65 - .../Extensions/ContextFilterLogFormatter.m | 191 - .../Extensions/DispatchQueueLogFormatter.h | 122 - .../Extensions/DispatchQueueLogFormatter.m | 241 - Pods/CocoaLumberjack/README.markdown | 37 - Pods/CocoaLumberjack/README.md | 301 + .../Sources/CocoaLumberjack/CLI/CLIColor.m | 57 + .../Sources/CocoaLumberjack/DDASLLogCapture.m | 205 + .../Sources/CocoaLumberjack/DDASLLogger.m | 133 + .../DDAbstractDatabaseLogger.m | 636 + .../CocoaLumberjack/DDFileLogger+Internal.h | 31 + .../Sources/CocoaLumberjack/DDFileLogger.m | 1865 + .../Sources/CocoaLumberjack/DDLog.m | 1321 + .../Sources/CocoaLumberjack/DDLoggerNames.m | 21 + .../Sources/CocoaLumberjack/DDOSLogger.m | 158 + .../Sources/CocoaLumberjack/DDTTYLogger.m | 1446 + .../DDContextFilterLogFormatter+Deprecated.m | 57 + .../Extensions/DDContextFilterLogFormatter.m | 185 + .../Extensions/DDDispatchQueueLogFormatter.m | 240 + .../Extensions/DDFileLogger+Buffering.m | 202 + .../Extensions/DDMultiFormatter.m | 110 + .../CocoaLumberjack/PrivacyInfo.xcprivacy | 30 + .../Supporting Files/CocoaLumberjack.h | 104 + .../Supporting Files/DDLegacyMacros.h | 75 + .../include/CocoaLumberjack/CLIColor.h | 54 + .../include/CocoaLumberjack/DDASLLogCapture.h | 46 + .../include/CocoaLumberjack/DDASLLogger.h | 63 + .../DDAbstractDatabaseLogger.h | 113 +- .../include/CocoaLumberjack/DDAssertMacros.h | 30 + .../DDContextFilterLogFormatter+Deprecated.h | 119 + .../DDContextFilterLogFormatter.h | 117 + .../DDDispatchQueueLogFormatter.h | 223 + .../CocoaLumberjack/DDFileLogger+Buffering.h | 27 + .../include/CocoaLumberjack/DDFileLogger.h | 571 + .../include/CocoaLumberjack/DDLog+LOGV.h | 82 + .../include/CocoaLumberjack/DDLog.h | 1024 + .../include/CocoaLumberjack/DDLogMacros.h | 101 + .../include/CocoaLumberjack/DDLoggerNames.h | 30 + .../CocoaLumberjack/DDMultiFormatter.h | 60 + .../include/CocoaLumberjack/DDOSLogger.h | 106 + .../include/CocoaLumberjack/DDTTYLogger.h | 186 + .../DCRoundSwitch/docset-installed.txt | 4 - .../DCRoundSwitch/docset/Contents/Info.plist | 35 - .../Documents/Classes/DCRoundSwitch.html | 470 - .../Classes/DCRoundSwitchKnobLayer.html | 268 - .../Classes/DCRoundSwitchOutlineLayer.html | 213 - .../Classes/DCRoundSwitchToggleLayer.html | 413 - .../Resources/Documents/css/styles.css | 584 - .../Resources/Documents/css/stylesPrint.css | 22 - .../Resources/Documents/hierarchy.html | 82 - .../Documents/img/button_bar_background.png | Bin 114 -> 0 bytes .../Resources/Documents/img/disclosure.png | Bin 206 -> 0 bytes .../Documents/img/disclosure_open.png | Bin 203 -> 0 bytes .../Documents/img/library_background.png | Bin 160 -> 0 bytes .../Documents/img/title_background.png | Bin 109 -> 0 bytes .../Contents/Resources/Documents/index.html | 116 - .../docset/Contents/Resources/Nodes.xml | 49 - .../docset/Contents/Resources/Tokens1.xml | 158 - .../docset/Contents/Resources/Tokens2.xml | 37 - .../docset/Contents/Resources/Tokens3.xml | 15 - .../docset/Contents/Resources/Tokens4.xml | 158 - .../docset/Contents/Resources/docSet.dsidx | Bin 237568 -> 0 bytes .../docset/Contents/Resources/docSet.mom | Bin 13990 -> 0 bytes .../docset/Contents/Resources/docSet.skidx | Bin 16384 -> 0 bytes .../docset/Contents/Resources/docSet.toc | Bin 426 -> 0 bytes .../html/Classes/DCRoundSwitch.html | 470 - .../html/Classes/DCRoundSwitchKnobLayer.html | 268 - .../Classes/DCRoundSwitchOutlineLayer.html | 213 - .../Classes/DCRoundSwitchToggleLayer.html | 413 - .../DCRoundSwitch/html/css/styles.css | 584 - .../DCRoundSwitch/html/css/stylesPrint.css | 22 - .../DCRoundSwitch/html/hierarchy.html | 82 - .../html/img/button_bar_background.png | Bin 114 -> 0 bytes .../DCRoundSwitch/html/img/disclosure.png | Bin 206 -> 0 bytes .../html/img/disclosure_open.png | Bin 203 -> 0 bytes .../html/img/library_background.png | Bin 160 -> 0 bytes .../html/img/title_background.png | Bin 109 -> 0 bytes .../DCRoundSwitch/html/index.html | 116 - Pods/Documentation/iRate/docset-installed.txt | 4 - .../iRate/docset/Contents/Info.plist | 35 - .../Resources/Documents/Classes/iRate.html | 1196 - .../Documents/Protocols/iRateDelegate.html | 444 - .../Resources/Documents/css/styles.css | 584 - .../Resources/Documents/css/stylesPrint.css | 22 - .../Resources/Documents/hierarchy.html | 82 - .../Documents/img/button_bar_background.png | Bin 114 -> 0 bytes .../Resources/Documents/img/disclosure.png | Bin 206 -> 0 bytes .../Documents/img/disclosure_open.png | Bin 203 -> 0 bytes .../Documents/img/library_background.png | Bin 160 -> 0 bytes .../Documents/img/title_background.png | Bin 109 -> 0 bytes .../Contents/Resources/Documents/index.html | 429 - .../iRate/docset/Contents/Resources/Nodes.xml | 47 - .../docset/Contents/Resources/Tokens1.xml | 873 - .../docset/Contents/Resources/Tokens2.xml | 114 - .../docset/Contents/Resources/docSet.dsidx | Bin 249856 -> 0 bytes .../docset/Contents/Resources/docSet.mom | Bin 13990 -> 0 bytes .../docset/Contents/Resources/docSet.skidx | Bin 32768 -> 0 bytes .../docset/Contents/Resources/docSet.toc | Bin 300 -> 0 bytes .../iRate/html/Classes/iRate.html | 1196 - .../iRate/html/Protocols/iRateDelegate.html | 444 - Pods/Documentation/iRate/html/css/styles.css | 584 - .../iRate/html/css/stylesPrint.css | 22 - Pods/Documentation/iRate/html/hierarchy.html | 82 - .../iRate/html/img/button_bar_background.png | Bin 114 -> 0 bytes .../iRate/html/img/disclosure.png | Bin 206 -> 0 bytes .../iRate/html/img/disclosure_open.png | Bin 203 -> 0 bytes .../iRate/html/img/library_background.png | Bin 160 -> 0 bytes .../iRate/html/img/title_background.png | Bin 109 -> 0 bytes Pods/Documentation/iRate/html/index.html | 429 - .../ContextFilterLogFormatter.h | 1 - Pods/Headers/CocoaLumberjack/DDASLLogger.h | 1 - .../DDAbstractDatabaseLogger.h | 1 - Pods/Headers/CocoaLumberjack/DDFileLogger.h | 1 - Pods/Headers/CocoaLumberjack/DDLog.h | 1 - Pods/Headers/CocoaLumberjack/DDTTYLogger.h | 1 - .../DispatchQueueLogFormatter.h | 1 - Pods/Headers/DCRoundSwitch/DCRoundSwitch.h | 1 - .../DCRoundSwitch/DCRoundSwitchKnobLayer.h | 1 - .../DCRoundSwitch/DCRoundSwitchOutlineLayer.h | 1 - .../DCRoundSwitch/DCRoundSwitchToggleLayer.h | 1 - .../Private/CocoaLumberjack/CLIColor.h | 1 + .../Private/CocoaLumberjack/CocoaLumberjack.h | 1 + .../Private/CocoaLumberjack/DDASLLogCapture.h | 1 + .../Private/CocoaLumberjack/DDASLLogger.h | 1 + .../DDAbstractDatabaseLogger.h | 1 + .../Private/CocoaLumberjack/DDAssertMacros.h | 1 + .../DDContextFilterLogFormatter+Deprecated.h | 1 + .../DDContextFilterLogFormatter.h | 1 + .../DDDispatchQueueLogFormatter.h | 1 + .../CocoaLumberjack/DDFileLogger+Buffering.h | 1 + .../CocoaLumberjack/DDFileLogger+Internal.h | 1 + .../Private/CocoaLumberjack/DDFileLogger.h | 1 + .../Private/CocoaLumberjack/DDLegacyMacros.h | 1 + .../Private/CocoaLumberjack/DDLog+LOGV.h | 1 + Pods/Headers/Private/CocoaLumberjack/DDLog.h | 1 + .../Private/CocoaLumberjack/DDLogMacros.h | 1 + .../Private/CocoaLumberjack/DDLoggerNames.h | 1 + .../CocoaLumberjack/DDMultiFormatter.h | 1 + .../Private/CocoaLumberjack/DDOSLogger.h | 1 + .../Private/CocoaLumberjack/DDTTYLogger.h | 1 + .../Private/DCRoundSwitch/DCRoundSwitch.h | 1 + .../DCRoundSwitch/DCRoundSwitchKnobLayer.h | 1 + .../DCRoundSwitch/DCRoundSwitchOutlineLayer.h | 1 + .../DCRoundSwitch/DCRoundSwitchToggleLayer.h | 1 + .../Private/Reachability/Reachability.h | 1 + Pods/Headers/Private/iRate/iRate.h | 1 + .../Headers/Public/CocoaLumberjack/CLIColor.h | 1 + .../Public/CocoaLumberjack/CocoaLumberjack.h | 1 + .../Public/CocoaLumberjack/DDASLLogCapture.h | 1 + .../Public/CocoaLumberjack/DDASLLogger.h | 1 + .../DDAbstractDatabaseLogger.h | 1 + .../Public/CocoaLumberjack/DDAssertMacros.h | 1 + .../DDContextFilterLogFormatter+Deprecated.h | 1 + .../DDContextFilterLogFormatter.h | 1 + .../DDDispatchQueueLogFormatter.h | 1 + .../CocoaLumberjack/DDFileLogger+Buffering.h | 1 + .../Public/CocoaLumberjack/DDFileLogger.h | 1 + .../Public/CocoaLumberjack/DDLegacyMacros.h | 1 + .../Public/CocoaLumberjack/DDLog+LOGV.h | 1 + Pods/Headers/Public/CocoaLumberjack/DDLog.h | 1 + .../Public/CocoaLumberjack/DDLogMacros.h | 1 + .../Public/CocoaLumberjack/DDLoggerNames.h | 1 + .../Public/CocoaLumberjack/DDMultiFormatter.h | 1 + .../Public/CocoaLumberjack/DDOSLogger.h | 1 + .../Public/CocoaLumberjack/DDTTYLogger.h | 1 + .../Public/DCRoundSwitch/DCRoundSwitch.h | 1 + .../DCRoundSwitch/DCRoundSwitchKnobLayer.h | 1 + .../DCRoundSwitch/DCRoundSwitchOutlineLayer.h | 1 + .../DCRoundSwitch/DCRoundSwitchToggleLayer.h | 1 + .../Public/Reachability/Reachability.h | 1 + Pods/Headers/Public/iRate/iRate.h | 1 + Pods/Headers/Reachability/Reachability.h | 1 - Pods/Headers/RegexKitLite/RegexKitLite.h | 1 - Pods/Headers/TestFlightSDK/TestFlight.h | 1 - Pods/Headers/iRate/iRate.h | 1 - Pods/Manifest.lock | 30 + Pods/Pods-Acknowledgements.markdown | 132 - Pods/Pods-prefix.pch | 3 - Pods/Pods-resources.sh | 24 - Pods/Pods.xcconfig | 8 - Pods/Pods.xcodeproj/project.pbxproj | 2666 +- Pods/PodsDummy_Pods.m | 4 - .../Framework/PrivacyInfo.xcprivacy | 14 + Pods/Reachability/LICENCE.txt | 24 + Pods/Reachability/README.md | 181 +- Pods/Reachability/Reachability.h | 73 +- Pods/Reachability/Reachability.m | 268 +- Pods/Reachability/Reachability.podspec | 12 - Pods/RegexKitLite/License.html | 33 - Pods/RegexKitLite/RegexKitLite.h | 295 - Pods/RegexKitLite/RegexKitLite.html | 6990 -- Pods/RegexKitLite/RegexKitLite.m | 2636 - .../CocoaLumberjack/CocoaLumberjack-dummy.m | 5 + .../CocoaLumberjack-prefix.pch | 12 + .../CocoaLumberjack.debug.xcconfig | 12 + .../CocoaLumberjack.release.xcconfig | 12 + ...mberjackPrivacy-CocoaLumberjack-Info.plist | 24 + .../DCRoundSwitch/DCRoundSwitch-dummy.m | 5 + .../DCRoundSwitch/DCRoundSwitch-prefix.pch | 12 + .../DCRoundSwitch.debug.xcconfig | 12 + .../DCRoundSwitch.release.xcconfig | 12 + .../Pods-OpenWorm-acknowledgements.markdown | 81 + .../Pods-OpenWorm-acknowledgements.plist} | 89 +- .../Pods-OpenWorm/Pods-OpenWorm-dummy.m | 5 + .../Pods-OpenWorm/Pods-OpenWorm-resources.sh | 133 + .../Pods-OpenWorm.debug.xcconfig | 11 + .../Pods-OpenWorm.release.xcconfig | 11 + .../Reachability/Reachability-dummy.m | 5 + .../Reachability/Reachability-prefix.pch | 12 + .../Reachability/Reachability.debug.xcconfig | 12 + .../Reachability.release.xcconfig | 12 + ...achability_Privacy-Reachability-Info.plist | 24 + Pods/Target Support Files/iRate/iRate-dummy.m | 5 + .../iRate/iRate-prefix.pch | 12 + .../iRate/iRate.debug.xcconfig | 12 + .../iRate/iRate.release.xcconfig | 12 + Pods/TestFlightSDK/README.md | 225 - Pods/TestFlightSDK/TestFlight.h | 101 - Pods/TestFlightSDK/libTestFlight.a | Bin 3947248 -> 0 bytes Pods/iRate/LICENCE.md | 2 - Pods/iRate/README.md | 465 +- .../iRate.bundle/ar.lproj/Localizable.strings | Bin 0 -> 650 bytes .../iRate.bundle/bn.lproj/Localizable.strings | Bin 0 -> 986 bytes .../iRate.bundle/bs.lproj/Localizable.strings | 6 + .../iRate.bundle/ca.lproj/Localizable.strings | Bin 0 -> 872 bytes .../iRate.bundle/cs.lproj/Localizable.strings | 6 + .../iRate.bundle/da.lproj/Localizable.strings | 6 +- .../de-AT.lproj/Localizable.strings | 6 + .../iRate.bundle/el.lproj/Localizable.strings | Bin 0 -> 940 bytes .../iRate.bundle/fa.lproj/Localizable.strings | 6 + .../iRate.bundle/fi.lproj/Localizable.strings | Bin 0 -> 810 bytes .../iRate.bundle/fr.lproj/Localizable.strings | Bin 934 -> 501 bytes .../iRate.bundle/hi.lproj/Localizable.strings | Bin 0 -> 852 bytes .../iRate.bundle/hr.lproj/Localizable.strings | 6 + .../iRate.bundle/hu.lproj/Localizable.strings | Bin 0 -> 924 bytes .../iRate.bundle/id.lproj/Localizable.strings | Bin 0 -> 902 bytes .../iRate.bundle/it.lproj/Localizable.strings | Bin 862 -> 812 bytes .../iRate.bundle/ja.lproj/Localizable.strings | Bin 620 -> 628 bytes .../iRate.bundle/mk.lproj/Localizable.strings | Bin 0 -> 940 bytes .../iRate.bundle/no.lproj/Localizable.strings | Bin 0 -> 856 bytes .../iRate.bundle/pa.lproj/Localizable.strings | Bin 0 -> 1030 bytes .../iRate.bundle/pt.lproj/Localizable.strings | Bin 972 -> 884 bytes .../iRate.bundle/sk.lproj/Localizable.strings | 6 + .../iRate.bundle/sl.lproj/Localizable.strings | Bin 0 -> 888 bytes .../iRate.bundle/th.lproj/Localizable.strings | Bin 0 -> 896 bytes .../iRate.bundle/tr.lproj/Localizable.strings | Bin 898 -> 928 bytes .../ur-IN.lproj/Localizable.strings | 7 + .../ur-PK.lproj/Localizable.strings | 7 + .../iRate.bundle/ur.lproj/Localizable.strings | 7 + .../iRate.bundle/vi.lproj/Localizable.strings | 6 + .../zh-TW.lproj/Localizable.strings | Bin 0 -> 510 bytes Pods/iRate/iRate/iRate.h | 78 +- Pods/iRate/iRate/iRate.m | 1219 +- WormBrowser/OWAppDelegate.m | 1 - WormBrowser/OWDefines.h | 1 - WormBrowser/OWMetaDataViewController.m | 43 +- WormBrowser/OWSearchViewController.m | 1 - WormBrowser/OpenWorm-Prefix.pch | 1 - fix.patch | 90965 ++++++++++++++++ 291 files changed, 105292 insertions(+), 30719 deletions(-) create mode 100644 AGENTS.md delete mode 120000 Pods/BuildHeaders/CocoaLumberjack/ContextFilterLogFormatter.h delete mode 120000 Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h delete mode 120000 Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h delete mode 120000 Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h delete mode 120000 Pods/BuildHeaders/CocoaLumberjack/DDLog.h delete mode 120000 Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h delete mode 120000 Pods/BuildHeaders/CocoaLumberjack/DispatchQueueLogFormatter.h delete mode 120000 Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitch.h delete mode 120000 Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchKnobLayer.h delete mode 120000 Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchOutlineLayer.h delete mode 120000 Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchToggleLayer.h delete mode 120000 Pods/BuildHeaders/Reachability/Reachability.h delete mode 120000 Pods/BuildHeaders/RegexKitLite/RegexKitLite.h delete mode 120000 Pods/BuildHeaders/TestFlightSDK/TestFlight.h delete mode 120000 Pods/BuildHeaders/iRate/iRate.h create mode 100644 Pods/CocoaLumberjack/CHANGELOG.md delete mode 100644 Pods/CocoaLumberjack/CocoaLumberjack.podspec create mode 100644 Pods/CocoaLumberjack/LICENSE delete mode 100644 Pods/CocoaLumberjack/LICENSE.txt delete mode 100755 Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h delete mode 100755 Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m delete mode 100644 Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m delete mode 100644 Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h delete mode 100644 Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m delete mode 100755 Pods/CocoaLumberjack/Lumberjack/DDLog.h delete mode 100755 Pods/CocoaLumberjack/Lumberjack/DDLog.m delete mode 100755 Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h delete mode 100755 Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m delete mode 100644 Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.h delete mode 100644 Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.m delete mode 100644 Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.h delete mode 100644 Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.m delete mode 100644 Pods/CocoaLumberjack/README.markdown create mode 100644 Pods/CocoaLumberjack/README.md create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/CLI/CLIColor.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDASLLogCapture.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDASLLogger.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDAbstractDatabaseLogger.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDFileLogger+Internal.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDFileLogger.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDLog.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDLoggerNames.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDOSLogger.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDTTYLogger.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDContextFilterLogFormatter+Deprecated.m create mode 100755 Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDContextFilterLogFormatter.m create mode 100755 Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDDispatchQueueLogFormatter.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDFileLogger+Buffering.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDMultiFormatter.m create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/PrivacyInfo.xcprivacy create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/Supporting Files/CocoaLumberjack.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/Supporting Files/DDLegacyMacros.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/CLIColor.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDASLLogCapture.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDASLLogger.h rename Pods/CocoaLumberjack/{Lumberjack => Sources/CocoaLumberjack/include/CocoaLumberjack}/DDAbstractDatabaseLogger.h (67%) create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDAssertMacros.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDContextFilterLogFormatter+Deprecated.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDContextFilterLogFormatter.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDDispatchQueueLogFormatter.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDFileLogger+Buffering.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDFileLogger.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDLog+LOGV.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDLog.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDLogMacros.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDLoggerNames.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDMultiFormatter.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDOSLogger.h create mode 100644 Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDTTYLogger.h delete mode 100644 Pods/Documentation/DCRoundSwitch/docset-installed.txt delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Info.plist delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/Classes/DCRoundSwitch.html delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/Classes/DCRoundSwitchKnobLayer.html delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/Classes/DCRoundSwitchOutlineLayer.html delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/Classes/DCRoundSwitchToggleLayer.html delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/css/styles.css delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/css/stylesPrint.css delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/hierarchy.html delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/img/button_bar_background.png delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/img/disclosure.png delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/img/disclosure_open.png delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/img/library_background.png delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/img/title_background.png delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Documents/index.html delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Nodes.xml delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Tokens1.xml delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Tokens2.xml delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Tokens3.xml delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/Tokens4.xml delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/docSet.dsidx delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/docSet.mom delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/docSet.skidx delete mode 100644 Pods/Documentation/DCRoundSwitch/docset/Contents/Resources/docSet.toc delete mode 100644 Pods/Documentation/DCRoundSwitch/html/Classes/DCRoundSwitch.html delete mode 100644 Pods/Documentation/DCRoundSwitch/html/Classes/DCRoundSwitchKnobLayer.html delete mode 100644 Pods/Documentation/DCRoundSwitch/html/Classes/DCRoundSwitchOutlineLayer.html delete mode 100644 Pods/Documentation/DCRoundSwitch/html/Classes/DCRoundSwitchToggleLayer.html delete mode 100644 Pods/Documentation/DCRoundSwitch/html/css/styles.css delete mode 100644 Pods/Documentation/DCRoundSwitch/html/css/stylesPrint.css delete mode 100644 Pods/Documentation/DCRoundSwitch/html/hierarchy.html delete mode 100644 Pods/Documentation/DCRoundSwitch/html/img/button_bar_background.png delete mode 100644 Pods/Documentation/DCRoundSwitch/html/img/disclosure.png delete mode 100644 Pods/Documentation/DCRoundSwitch/html/img/disclosure_open.png delete mode 100644 Pods/Documentation/DCRoundSwitch/html/img/library_background.png delete mode 100644 Pods/Documentation/DCRoundSwitch/html/img/title_background.png delete mode 100644 Pods/Documentation/DCRoundSwitch/html/index.html delete mode 100644 Pods/Documentation/iRate/docset-installed.txt delete mode 100644 Pods/Documentation/iRate/docset/Contents/Info.plist delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/Classes/iRate.html delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/Protocols/iRateDelegate.html delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/css/styles.css delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/css/stylesPrint.css delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/hierarchy.html delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/img/button_bar_background.png delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/img/disclosure.png delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/img/disclosure_open.png delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/img/library_background.png delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/img/title_background.png delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Documents/index.html delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Nodes.xml delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Tokens1.xml delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/Tokens2.xml delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/docSet.dsidx delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/docSet.mom delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/docSet.skidx delete mode 100644 Pods/Documentation/iRate/docset/Contents/Resources/docSet.toc delete mode 100644 Pods/Documentation/iRate/html/Classes/iRate.html delete mode 100644 Pods/Documentation/iRate/html/Protocols/iRateDelegate.html delete mode 100644 Pods/Documentation/iRate/html/css/styles.css delete mode 100644 Pods/Documentation/iRate/html/css/stylesPrint.css delete mode 100644 Pods/Documentation/iRate/html/hierarchy.html delete mode 100644 Pods/Documentation/iRate/html/img/button_bar_background.png delete mode 100644 Pods/Documentation/iRate/html/img/disclosure.png delete mode 100644 Pods/Documentation/iRate/html/img/disclosure_open.png delete mode 100644 Pods/Documentation/iRate/html/img/library_background.png delete mode 100644 Pods/Documentation/iRate/html/img/title_background.png delete mode 100644 Pods/Documentation/iRate/html/index.html delete mode 120000 Pods/Headers/CocoaLumberjack/ContextFilterLogFormatter.h delete mode 120000 Pods/Headers/CocoaLumberjack/DDASLLogger.h delete mode 120000 Pods/Headers/CocoaLumberjack/DDAbstractDatabaseLogger.h delete mode 120000 Pods/Headers/CocoaLumberjack/DDFileLogger.h delete mode 120000 Pods/Headers/CocoaLumberjack/DDLog.h delete mode 120000 Pods/Headers/CocoaLumberjack/DDTTYLogger.h delete mode 120000 Pods/Headers/CocoaLumberjack/DispatchQueueLogFormatter.h delete mode 120000 Pods/Headers/DCRoundSwitch/DCRoundSwitch.h delete mode 120000 Pods/Headers/DCRoundSwitch/DCRoundSwitchKnobLayer.h delete mode 120000 Pods/Headers/DCRoundSwitch/DCRoundSwitchOutlineLayer.h delete mode 120000 Pods/Headers/DCRoundSwitch/DCRoundSwitchToggleLayer.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/CLIColor.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/CocoaLumberjack.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDASLLogCapture.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDASLLogger.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDAbstractDatabaseLogger.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDAssertMacros.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDContextFilterLogFormatter+Deprecated.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDContextFilterLogFormatter.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDDispatchQueueLogFormatter.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDFileLogger+Buffering.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDFileLogger+Internal.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDFileLogger.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDLegacyMacros.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDLog+LOGV.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDLog.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDLogMacros.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDLoggerNames.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDMultiFormatter.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDOSLogger.h create mode 120000 Pods/Headers/Private/CocoaLumberjack/DDTTYLogger.h create mode 120000 Pods/Headers/Private/DCRoundSwitch/DCRoundSwitch.h create mode 120000 Pods/Headers/Private/DCRoundSwitch/DCRoundSwitchKnobLayer.h create mode 120000 Pods/Headers/Private/DCRoundSwitch/DCRoundSwitchOutlineLayer.h create mode 120000 Pods/Headers/Private/DCRoundSwitch/DCRoundSwitchToggleLayer.h create mode 120000 Pods/Headers/Private/Reachability/Reachability.h create mode 120000 Pods/Headers/Private/iRate/iRate.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/CLIColor.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/CocoaLumberjack.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDASLLogCapture.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDASLLogger.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDAbstractDatabaseLogger.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDAssertMacros.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDContextFilterLogFormatter+Deprecated.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDContextFilterLogFormatter.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDDispatchQueueLogFormatter.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDFileLogger+Buffering.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDFileLogger.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDLegacyMacros.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDLog+LOGV.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDLog.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDLogMacros.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDLoggerNames.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDMultiFormatter.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDOSLogger.h create mode 120000 Pods/Headers/Public/CocoaLumberjack/DDTTYLogger.h create mode 120000 Pods/Headers/Public/DCRoundSwitch/DCRoundSwitch.h create mode 120000 Pods/Headers/Public/DCRoundSwitch/DCRoundSwitchKnobLayer.h create mode 120000 Pods/Headers/Public/DCRoundSwitch/DCRoundSwitchOutlineLayer.h create mode 120000 Pods/Headers/Public/DCRoundSwitch/DCRoundSwitchToggleLayer.h create mode 120000 Pods/Headers/Public/Reachability/Reachability.h create mode 120000 Pods/Headers/Public/iRate/iRate.h delete mode 120000 Pods/Headers/Reachability/Reachability.h delete mode 120000 Pods/Headers/RegexKitLite/RegexKitLite.h delete mode 120000 Pods/Headers/TestFlightSDK/TestFlight.h delete mode 120000 Pods/Headers/iRate/iRate.h create mode 100644 Pods/Manifest.lock delete mode 100644 Pods/Pods-Acknowledgements.markdown delete mode 100644 Pods/Pods-prefix.pch delete mode 100755 Pods/Pods-resources.sh delete mode 100644 Pods/Pods.xcconfig delete mode 100644 Pods/PodsDummy_Pods.m create mode 100644 Pods/Reachability/Framework/PrivacyInfo.xcprivacy create mode 100644 Pods/Reachability/LICENCE.txt delete mode 100644 Pods/Reachability/Reachability.podspec delete mode 100644 Pods/RegexKitLite/License.html delete mode 100644 Pods/RegexKitLite/RegexKitLite.h delete mode 100644 Pods/RegexKitLite/RegexKitLite.html delete mode 100644 Pods/RegexKitLite/RegexKitLite.m create mode 100644 Pods/Target Support Files/CocoaLumberjack/CocoaLumberjack-dummy.m create mode 100644 Pods/Target Support Files/CocoaLumberjack/CocoaLumberjack-prefix.pch create mode 100644 Pods/Target Support Files/CocoaLumberjack/CocoaLumberjack.debug.xcconfig create mode 100644 Pods/Target Support Files/CocoaLumberjack/CocoaLumberjack.release.xcconfig create mode 100644 Pods/Target Support Files/CocoaLumberjack/ResourceBundle-CocoaLumberjackPrivacy-CocoaLumberjack-Info.plist create mode 100644 Pods/Target Support Files/DCRoundSwitch/DCRoundSwitch-dummy.m create mode 100644 Pods/Target Support Files/DCRoundSwitch/DCRoundSwitch-prefix.pch create mode 100644 Pods/Target Support Files/DCRoundSwitch/DCRoundSwitch.debug.xcconfig create mode 100644 Pods/Target Support Files/DCRoundSwitch/DCRoundSwitch.release.xcconfig create mode 100644 Pods/Target Support Files/Pods-OpenWorm/Pods-OpenWorm-acknowledgements.markdown rename Pods/{Pods-Acknowledgements.plist => Target Support Files/Pods-OpenWorm/Pods-OpenWorm-acknowledgements.plist} (52%) create mode 100644 Pods/Target Support Files/Pods-OpenWorm/Pods-OpenWorm-dummy.m create mode 100755 Pods/Target Support Files/Pods-OpenWorm/Pods-OpenWorm-resources.sh create mode 100644 Pods/Target Support Files/Pods-OpenWorm/Pods-OpenWorm.debug.xcconfig create mode 100644 Pods/Target Support Files/Pods-OpenWorm/Pods-OpenWorm.release.xcconfig create mode 100644 Pods/Target Support Files/Reachability/Reachability-dummy.m create mode 100644 Pods/Target Support Files/Reachability/Reachability-prefix.pch create mode 100644 Pods/Target Support Files/Reachability/Reachability.debug.xcconfig create mode 100644 Pods/Target Support Files/Reachability/Reachability.release.xcconfig create mode 100644 Pods/Target Support Files/Reachability/ResourceBundle-Reachability_Privacy-Reachability-Info.plist create mode 100644 Pods/Target Support Files/iRate/iRate-dummy.m create mode 100644 Pods/Target Support Files/iRate/iRate-prefix.pch create mode 100644 Pods/Target Support Files/iRate/iRate.debug.xcconfig create mode 100644 Pods/Target Support Files/iRate/iRate.release.xcconfig delete mode 100644 Pods/TestFlightSDK/README.md delete mode 100644 Pods/TestFlightSDK/TestFlight.h delete mode 100644 Pods/TestFlightSDK/libTestFlight.a create mode 100644 Pods/iRate/iRate/iRate.bundle/ar.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/bn.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/bs.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/ca.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/cs.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/de-AT.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/el.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/fa.lproj/Localizable.strings create mode 100755 Pods/iRate/iRate/iRate.bundle/fi.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/hi.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/hr.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/hu.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/id.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/mk.lproj/Localizable.strings create mode 100755 Pods/iRate/iRate/iRate.bundle/no.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/pa.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/sk.lproj/Localizable.strings create mode 100755 Pods/iRate/iRate/iRate.bundle/sl.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/th.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/ur-IN.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/ur-PK.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/ur.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/vi.lproj/Localizable.strings create mode 100644 Pods/iRate/iRate/iRate.bundle/zh-TW.lproj/Localizable.strings create mode 100644 fix.patch diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7630747 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,4 @@ +# AGENT Instructions + +- After modifying `Podfile` or any pod dependency, run `pod install --allow-root` to regenerate the workspace. +- Ensure project build settings in `OpenWorm.xcodeproj/project.pbxproj` are updated accordingly when bumping deployment target or architectures. diff --git a/OpenWorm.xcodeproj/project.pbxproj b/OpenWorm.xcodeproj/project.pbxproj index c16d938..2d1b505 100644 --- a/OpenWorm.xcodeproj/project.pbxproj +++ b/OpenWorm.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 52F3D240624B4916A96B0A0D /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88B158F30C54BD7BD50DE53 /* libPods.a */; }; A805275B168913FB0037CA87 /* bootstrap in Resources */ = {isa = PBXBuildFile; fileRef = A805275A168913FB0037CA87 /* bootstrap */; }; A807F437169A5A2900FA84D7 /* reduced.json in Resources */ = {isa = PBXBuildFile; fileRef = A807F436169A5A2900FA84D7 /* reduced.json */; }; A83D379816ACF64E00A72AA3 /* OpenWormLogoNew.png in Resources */ = {isa = PBXBuildFile; fileRef = A83D379716ACF64E00A72AA3 /* OpenWormLogoNew.png */; }; @@ -158,10 +157,13 @@ A8F42B5A166ED6D1005503A4 /* OWCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F42B59166ED6D0005503A4 /* OWCamera.m */; }; A8F838E01682FE430052531F /* OWMetaDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F838DF1682FE430052531F /* OWMetaDataViewController.m */; }; A8FC9F7B1676ADED000883F3 /* data.json in Resources */ = {isa = PBXBuildFile; fileRef = A8FC9F7A1676ADED000883F3 /* data.json */; }; + FFA41A257D9AAA264C3867C2 /* libPods-OpenWorm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6849F52DCA6B27D968C0ECCD /* libPods-OpenWorm.a */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 76D74B3BCB6B468F977418CA /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = SOURCE_ROOT; }; + 674C096515004CCE671FEA3D /* Pods-OpenWorm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenWorm.release.xcconfig"; path = "Target Support Files/Pods-OpenWorm/Pods-OpenWorm.release.xcconfig"; sourceTree = ""; }; + 6849F52DCA6B27D968C0ECCD /* libPods-OpenWorm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-OpenWorm.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8C21A8EDBC495042D3400A13 /* Pods-OpenWorm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenWorm.debug.xcconfig"; path = "Target Support Files/Pods-OpenWorm/Pods-OpenWorm.debug.xcconfig"; sourceTree = ""; }; A805275A168913FB0037CA87 /* bootstrap */ = {isa = PBXFileReference; lastKnownFileType = folder; path = bootstrap; sourceTree = ""; }; A807F436169A5A2900FA84D7 /* reduced.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = reduced.json; path = ../Metadata/reduced.json; sourceTree = ""; }; A83D379716ACF64E00A72AA3 /* OpenWormLogoNew.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = OpenWormLogoNew.png; path = ImageAssets/OpenWormLogoNew.png; sourceTree = SOURCE_ROOT; }; @@ -332,7 +334,6 @@ A8F838DE1682FE430052531F /* OWMetaDataViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWMetaDataViewController.h; sourceTree = ""; }; A8F838DF1682FE430052531F /* OWMetaDataViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWMetaDataViewController.m; sourceTree = ""; }; A8FC9F7A1676ADED000883F3 /* data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = data.json; path = ../Metadata/data.json; sourceTree = ""; }; - B88B158F30C54BD7BD50DE53 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -346,13 +347,23 @@ A8C710DF166C329D0067DCAC /* UIKit.framework in Frameworks */, A8C710E1166C329D0067DCAC /* Foundation.framework in Frameworks */, A8C710E3166C329D0067DCAC /* CoreGraphics.framework in Frameworks */, - 52F3D240624B4916A96B0A0D /* libPods.a in Frameworks */, + FFA41A257D9AAA264C3867C2 /* libPods-OpenWorm.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 735558FA2BC1BA7E9E395FB5 /* Pods */ = { + isa = PBXGroup; + children = ( + 8C21A8EDBC495042D3400A13 /* Pods-OpenWorm.debug.xcconfig */, + 674C096515004CCE671FEA3D /* Pods-OpenWorm.release.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; A807F3ED169A599700FA84D7 /* WormData75PolyCount */ = { isa = PBXGroup; children = ( @@ -507,7 +518,7 @@ A8C710E4166C329D0067DCAC /* WormBrowser */, A8C710DD166C329D0067DCAC /* Frameworks */, A8C710DB166C329D0067DCAC /* Products */, - 76D74B3BCB6B468F977418CA /* Pods.xcconfig */, + 735558FA2BC1BA7E9E395FB5 /* Pods */, ); sourceTree = ""; }; @@ -529,7 +540,7 @@ A8C710DE166C329D0067DCAC /* UIKit.framework */, A8C710E0166C329D0067DCAC /* Foundation.framework */, A8C710E2166C329D0067DCAC /* CoreGraphics.framework */, - B88B158F30C54BD7BD50DE53 /* libPods.a */, + 6849F52DCA6B27D968C0ECCD /* libPods-OpenWorm.a */, ); name = Frameworks; sourceTree = ""; @@ -650,10 +661,11 @@ isa = PBXNativeTarget; buildConfigurationList = A8C71101166C329D0067DCAC /* Build configuration list for PBXNativeTarget "OpenWorm" */; buildPhases = ( + CEC0E2168D3516332AA0D283 /* [CP] Check Pods Manifest.lock */, A8C710D6166C329D0067DCAC /* Sources */, A8C710D7166C329D0067DCAC /* Frameworks */, A8C710D8166C329D0067DCAC /* Resources */, - E8206EDB2B304A59AE9560BF /* Copy Pods Resources */, + 686D5D542BDB505786A2C837 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -846,6 +858,28 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 686D5D542BDB505786A2C837 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-OpenWorm/Pods-OpenWorm-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack/CocoaLumberjackPrivacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Reachability/Reachability_Privacy.bundle", + "${PODS_ROOT}/iRate/iRate/iRate.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/CocoaLumberjackPrivacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Reachability_Privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/iRate.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-OpenWorm/Pods-OpenWorm-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; A8CC4A5916E1BE6B00A94962 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -859,19 +893,27 @@ shellPath = /bin/sh; shellScript = "/usr/local/bin/appledoc --create-html --no-create-docset --project-name openwormbrowser --project-company \"WholeSlide, Inc.\" --company-id us.metacell --output /Users/stonerri/Documents/OpenWorm/openwormbrowser-ios/doc --no-repeat-first-par /Users/stonerri/Documents/OpenWorm/openwormbrowser-ios/WormBrowser"; }; - E8206EDB2B304A59AE9560BF /* Copy Pods Resources */ = { + CEC0E2168D3516332AA0D283 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "Copy Pods Resources"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-OpenWorm-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Pods-resources.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -933,6 +975,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; @@ -951,7 +994,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -962,6 +1005,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; @@ -973,7 +1017,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -983,14 +1027,15 @@ }; A8C71102166C329D0067DCAC /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 76D74B3BCB6B468F977418CA /* Pods.xcconfig */; + baseConfigurationReference = 8C21A8EDBC495042D3400A13 /* Pods-OpenWorm.debug.xcconfig */; buildSettings = { + ARCHS = "$(ARCHS_STANDARD)"; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "WormBrowser/OpenWorm-Prefix.pch"; INFOPLIST_FILE = "WormBrowser/OpenWorm-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; @@ -1000,14 +1045,15 @@ }; A8C71103166C329D0067DCAC /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 76D74B3BCB6B468F977418CA /* Pods.xcconfig */; + baseConfigurationReference = 674C096515004CCE671FEA3D /* Pods-OpenWorm.release.xcconfig */; buildSettings = { + ARCHS = "$(ARCHS_STANDARD)"; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "WormBrowser/OpenWorm-Prefix.pch"; INFOPLIST_FILE = "WormBrowser/OpenWorm-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; @@ -1017,14 +1063,14 @@ }; A8CC4A5516E1BE5F00A94962 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 76D74B3BCB6B468F977418CA /* Pods.xcconfig */; buildSettings = { + ARCHS = "$(ARCHS_STANDARD)"; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "WormBrowser/OpenWorm-Prefix.pch"; INFOPLIST_FILE = "$(SRCROOT)/WormBrowser/OpenWorm-Docs.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; PRODUCT_NAME = "OpenWorm copy"; PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; @@ -1034,14 +1080,14 @@ }; A8CC4A5616E1BE5F00A94962 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 76D74B3BCB6B468F977418CA /* Pods.xcconfig */; buildSettings = { + ARCHS = "$(ARCHS_STANDARD)"; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "WormBrowser/OpenWorm-Prefix.pch"; INFOPLIST_FILE = "$(SRCROOT)/WormBrowser/OpenWorm-Docs.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; PRODUCT_NAME = "OpenWorm copy"; PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; diff --git a/Podfile b/Podfile index 85af1cc..71cc72c 100644 --- a/Podfile +++ b/Podfile @@ -1,7 +1,8 @@ -platform :ios, 5.1 -pod 'Reachability' -pod 'TestFlightSDK', '1.1' -pod 'CocoaLumberjack' -pod 'RegexKitLite' -pod 'iRate' -pod 'DCRoundSwitch', '~> 0.0.1' +platform :ios, '14.0' + +target 'OpenWorm' do + pod 'Reachability' + pod 'CocoaLumberjack' + pod 'iRate' + pod 'DCRoundSwitch' +end diff --git a/Podfile.lock b/Podfile.lock index cdfa3ba..cca1f3e 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,26 +1,30 @@ +PODS: + - CocoaLumberjack (3.8.5): + - CocoaLumberjack/Core (= 3.8.5) + - CocoaLumberjack/Core (3.8.5) + - DCRoundSwitch (0.0.1) + - iRate (1.12.2) + - Reachability (3.7.6) -COCOAPODS: 0.16.2 +DEPENDENCIES: + - CocoaLumberjack + - DCRoundSwitch + - iRate + - Reachability -SPEC CHECKSUMS: - Reachability: 1c8584c5f26fa776695efef95caaa50402c94cfb - RegexKitLite: 293ff6f3cf8f34277989a37802162c6961a2b35a - DCRoundSwitch: c08f58330d242f182450b5e4ad32e5238f53d6d4 - CocoaLumberjack: 0f2fa7090a23f13261072d882e017c688300efbe - iRate: eb1d02ff0a2bfee220f5fe028583b4ce5f3ef3bd - TestFlightSDK: 2a2cdb82967c7f05655683c61854c92d36e9104d +SPEC REPOS: + trunk: + - CocoaLumberjack + - DCRoundSwitch + - iRate + - Reachability -PODS: -- CocoaLumberjack (1.6) -- DCRoundSwitch (0.0.1) -- Reachability (3.1.0) -- RegexKitLite (4.0) -- TestFlightSDK (1.1) -- iRate (1.7.2) +SPEC CHECKSUMS: + CocoaLumberjack: 6a459bc897d6d80bd1b8c78482ec7ad05dffc3f0 + DCRoundSwitch: 86d348f35be4d6ef18dbc9331c682aab6f85e980 + iRate: 4fc69958788624545e5d050c8ffd20884013c3f1 + Reachability: fd0ecd23705e2599e4cceeb943222ae02296cbc6 -DEPENDENCIES: -- CocoaLumberjack -- DCRoundSwitch (~> 0.0.1) -- Reachability -- RegexKitLite -- TestFlightSDK (= 1.1) -- iRate +PODFILE CHECKSUM: 788602d9180a601397ae0fd6952aace6891276fe + +COCOAPODS: 1.11.3 diff --git a/Pods/BuildHeaders/CocoaLumberjack/ContextFilterLogFormatter.h b/Pods/BuildHeaders/CocoaLumberjack/ContextFilterLogFormatter.h deleted file mode 120000 index de4836b..0000000 --- a/Pods/BuildHeaders/CocoaLumberjack/ContextFilterLogFormatter.h +++ /dev/null @@ -1 +0,0 @@ -../../CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.h \ No newline at end of file diff --git a/Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h b/Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h deleted file mode 120000 index 663f808..0000000 --- a/Pods/BuildHeaders/CocoaLumberjack/DDASLLogger.h +++ /dev/null @@ -1 +0,0 @@ -../../CocoaLumberjack/Lumberjack/DDASLLogger.h \ No newline at end of file diff --git a/Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h b/Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h deleted file mode 120000 index 950a053..0000000 --- a/Pods/BuildHeaders/CocoaLumberjack/DDAbstractDatabaseLogger.h +++ /dev/null @@ -1 +0,0 @@ -../../CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h \ No newline at end of file diff --git a/Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h b/Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h deleted file mode 120000 index 18c2149..0000000 --- a/Pods/BuildHeaders/CocoaLumberjack/DDFileLogger.h +++ /dev/null @@ -1 +0,0 @@ -../../CocoaLumberjack/Lumberjack/DDFileLogger.h \ No newline at end of file diff --git a/Pods/BuildHeaders/CocoaLumberjack/DDLog.h b/Pods/BuildHeaders/CocoaLumberjack/DDLog.h deleted file mode 120000 index 8af615d..0000000 --- a/Pods/BuildHeaders/CocoaLumberjack/DDLog.h +++ /dev/null @@ -1 +0,0 @@ -../../CocoaLumberjack/Lumberjack/DDLog.h \ No newline at end of file diff --git a/Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h b/Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h deleted file mode 120000 index 6c7bb54..0000000 --- a/Pods/BuildHeaders/CocoaLumberjack/DDTTYLogger.h +++ /dev/null @@ -1 +0,0 @@ -../../CocoaLumberjack/Lumberjack/DDTTYLogger.h \ No newline at end of file diff --git a/Pods/BuildHeaders/CocoaLumberjack/DispatchQueueLogFormatter.h b/Pods/BuildHeaders/CocoaLumberjack/DispatchQueueLogFormatter.h deleted file mode 120000 index 76d4c51..0000000 --- a/Pods/BuildHeaders/CocoaLumberjack/DispatchQueueLogFormatter.h +++ /dev/null @@ -1 +0,0 @@ -../../CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.h \ No newline at end of file diff --git a/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitch.h b/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitch.h deleted file mode 120000 index 3370016..0000000 --- a/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitch.h +++ /dev/null @@ -1 +0,0 @@ -../../DCRoundSwitch/DCRoundSwitch/DCRoundSwitch.h \ No newline at end of file diff --git a/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchKnobLayer.h b/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchKnobLayer.h deleted file mode 120000 index 263e759..0000000 --- a/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchKnobLayer.h +++ /dev/null @@ -1 +0,0 @@ -../../DCRoundSwitch/DCRoundSwitch/DCRoundSwitchKnobLayer.h \ No newline at end of file diff --git a/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchOutlineLayer.h b/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchOutlineLayer.h deleted file mode 120000 index f861b85..0000000 --- a/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchOutlineLayer.h +++ /dev/null @@ -1 +0,0 @@ -../../DCRoundSwitch/DCRoundSwitch/DCRoundSwitchOutlineLayer.h \ No newline at end of file diff --git a/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchToggleLayer.h b/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchToggleLayer.h deleted file mode 120000 index e2df5c3..0000000 --- a/Pods/BuildHeaders/DCRoundSwitch/DCRoundSwitchToggleLayer.h +++ /dev/null @@ -1 +0,0 @@ -../../DCRoundSwitch/DCRoundSwitch/DCRoundSwitchToggleLayer.h \ No newline at end of file diff --git a/Pods/BuildHeaders/Reachability/Reachability.h b/Pods/BuildHeaders/Reachability/Reachability.h deleted file mode 120000 index d374abf..0000000 --- a/Pods/BuildHeaders/Reachability/Reachability.h +++ /dev/null @@ -1 +0,0 @@ -../../Reachability/Reachability.h \ No newline at end of file diff --git a/Pods/BuildHeaders/RegexKitLite/RegexKitLite.h b/Pods/BuildHeaders/RegexKitLite/RegexKitLite.h deleted file mode 120000 index eed57e3..0000000 --- a/Pods/BuildHeaders/RegexKitLite/RegexKitLite.h +++ /dev/null @@ -1 +0,0 @@ -../../RegexKitLite/RegexKitLite.h \ No newline at end of file diff --git a/Pods/BuildHeaders/TestFlightSDK/TestFlight.h b/Pods/BuildHeaders/TestFlightSDK/TestFlight.h deleted file mode 120000 index 07e55a6..0000000 --- a/Pods/BuildHeaders/TestFlightSDK/TestFlight.h +++ /dev/null @@ -1 +0,0 @@ -../../TestFlightSDK/TestFlight.h \ No newline at end of file diff --git a/Pods/BuildHeaders/iRate/iRate.h b/Pods/BuildHeaders/iRate/iRate.h deleted file mode 120000 index 0d14090..0000000 --- a/Pods/BuildHeaders/iRate/iRate.h +++ /dev/null @@ -1 +0,0 @@ -../../iRate/iRate/iRate.h \ No newline at end of file diff --git a/Pods/CocoaLumberjack/CHANGELOG.md b/Pods/CocoaLumberjack/CHANGELOG.md new file mode 100644 index 0000000..7a519a3 --- /dev/null +++ b/Pods/CocoaLumberjack/CHANGELOG.md @@ -0,0 +1,638 @@ +# [3.8.5 - Xcode 15.3 on Mar 8th, 2024](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tags/3.8.5) + +### Public + +- Fix build failure due to privacy manifest when using static linking with CocoaPods (#1408) +- Allow custom mapping of `DDLogFlag` to `os_log_type_t`, fix default mapping for `DDLogFlagWarn` (#1410) + + +# [3.8.4 - Xcode 15.2 on Feb 8th, 2024](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tags/3.8.4) + +### Public + +- Extend privacy manifest to fulfill validation criteria (#1403) +- Fix crash when fetching registered classes (#1406) + + +# [3.8.3 - Xcode 15.2 on Feb 5th, 2024](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tags/3.8.3) + +### Public + +- Add privacy manifest (#1403) +- Update doc from DDLogLevelWarn to DDLogLevelWarning to match library (#1383) +- Only cleanup files on configuration change if the manager is used by a file logger (#1398) +- Fix #1386 again by adding a missing return and adjusting the preprocessor conditionals +- Fix some C++ warnings + +### Internal + +- Update copyright for 2024 (#1400) +- Improve asserts (#1385) + + +# [3.8.2 - Xcode 15.0 on Oct 31st, 2023](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.8.2) + +### Public + +- App background-mode not correctly detected in app extensions (#1359) +- Fix DDFileLogger rollingFrequency and maximumFileSize not being honored (#1361) +- Fix potential crashes when using the new `DDLogMessageFormat` with messages that contain '%' +- Fix simulator issues when using dynamic registered logging on iOS 17 (#1386) +- Allow `DDFileLogger` to write in different file formats (#1380) + +### Internal + +- Generate Podspec (#1360) + + +# [3.8.1 - Xcode 14.3 on Aug 21st, 2023](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.8.1) + +### Public + +- Silence double conversion warnings for 32-bit watchOS (#1320) +- Enable ALLOW_TARGET_PLATFORM_SPECIALIZATION (#1321) +- Update to swift-log 1.5.2, implement metadata providers (#1329) +- Preserve `messageFormat` in `DDLogMessage` (#1347) + +### Internal + +- Update copyright for 2023 + + +## [3.8.0 - Xcode 14.1 on Nov 2nd, 2022](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.8.0) + +### Public + +- Add support for Xcode 14 / Swift 5.7 - drop support for Swift < 5.5, iOS/tvOS < 11, macOS < 10.13, watchOS < 4 (#1316) +- Update README about swift-log usage (#1275) +- Use dispatch_walltime for scheduling log file rolling timer (#1309) + +### Internal + +- Add consistent newline to file endings (#1272) +- Fix error checking in DDFileLogger (#1274) +- Avoid using NSString format (#1280) +- Prevent logging to symlink files (#1314) + + +## [3.7.4 - Xcode 13.2 on Dec 16, 2021](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.7.4) + +### Public + +- Fix swift-tools-version in Package@swift-5.3.swift + + +## [3.7.3 - Xcode 13.2 on Dec 16, 2021](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.7.3) + +### Public + +- Fix "DDFileLogger: Failed to get offset" when setting maximumFileSize (#1234) +- Follow-up to add annotations to DDOSLogger (#1248) +- Fixed nullability conflict in DDDispatchQueueLogFormatter.h (#1252) +- Add Swift 5.5 support, fix archive build on Xcode 13 (#1253) +- Fix file access issue in Catalyst apps (#1257) +- Fix excluded archs in debug build when not mac catalyst (#1260) +- Bump Xcode last upgraded version to 13.2 (#1265) +- Don't log warnings for CLI apps in DDTTYLogger (#1269) + + +## [3.7.2 - Xcode 12.4 on Apr 9th, 2021](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.7.2) + +### Public + +- Re-introduce (and deprecate) `_tag` field to fix breakage in 3.7.1 (#1224) + + +## [3.7.1 - Xcode 12.4 on Apr 7th, 2021](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.7.1) + +### Public + +- Deprecate `tag` property of `DDLogMessage`, use `representedObject` instead. (#1177, #532) +- Add per-message synchronous logging control for messages logged via SwiftLog using `DDLogHandler` (#1209) +- Add TargetConditionals import for Xcode 12.5 (#1210) +- Prevent logging an error when archiving an already deleted file (#1212) +- Use inclusive words - denylist / allowlist (#1218) +- Add `DDAssertionFailure` macro for Objective-C (#1220) + +### Internal + +- Use setter to replace kvo for `NSFileLogger` (#1180) +- Use new API for `NSFileHandle` on supported platforms (#1181) +- Remove unnecessary checks in `DDFileLogger` (#1182) +- Add an assertion to avoid potential deadlock issues for `flushLog` (#1183) + + +## [3.7.0 - Xcode 12 on Oct 2nd, 2020](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.7.0) + +### Public + +- **Breaking change**: Dropped support for iOS 8 (#1153) +- Update SPM tools-version to 5.3 to enable Swift 5.3 support (#1148) +- Add backend for swift-log (#1164) +- Specify CocoaPods version to ensure `swift_version` attribute works (#1167) +- Simplify `DDLogFileManager` callbacks for archived log files (#1166) + + +## [3.6.2 - Xcode 11.6 on July 31st, 2020](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.6.2) + +### Public +- Fix warnings when building with SPM bundled with Swift 5.2 / Xcode 11.4 (#1132) +- Added Swift name for DDQualityOfServiceName constants. +- Don't localize timestamps in `DDefaultFileLogFormatter` (#1151) +- Allow logging arbitrary objects via Swift log functions (#1146) + +### Repository +- Switch from Travis to GitHub Actions (#1135, #1140, #1150, #1152) + + +## [3.6.1 - Xcode 11.3.1 on Jan 25th, 2020](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.6.1) + +### Public +- Improve error handling during log file creation in DDFileLogger & DDLogFileManager (#1103 / #1111) +- Improve nullability annotations in public headers (#1111 / #1112 / #1119) +- Added support for thread QOS in DDLogMessage class (#1124) + +### Internal +- Fix rolling timer being rescheduled rapidly due to leeway (#1106 / #1107) +- Fix -didArchiveLogFile: returning the file name instead of the file path (#1078) +- Fix setxattr() function usage (#1118) +- Fix NSDateFormatter thread safety (#1121) +- Fix -lt_dataForMessage: duplicated code (#1122) + + +## [3.6.0 - Xcode 11 on October 2nd, 2019](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.6.0) + +### Public +- Swift Package Manager Support (#1083) +- New `willLogMessage:` and `didLogMessage:` methods on `DDFileLogger` which provide access to the current log file info. + +### Internal +- Fix issue with log archiving in the simulator (#1098) +- Limit assertion to non-simulator build (#1100) + + +## [3.5.3 - Xcode 10.2 on Apr 24th, 2019](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.5.3) + +### Public +- Additional compatibility with Swift 5 (backwards compatible with Swift 4) (#1043) +- Fix warning building with Xcode 10.2 (#1059) +- Set Xcode 10.2 and Swift 5.0 as a default (#1064) +- Fix format string crash (#1066) + +### Internal +- Fix warning about syntax (#1054) (#1065) +- Remove banned APIs (#1056) (#1057) +- Add CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER & fix warnings (#1059) +- Use LLONG_MAX instead of LONG_LONG_MAX (#1062) + + +## [3.5.2 - Xcode 10.1 on Mar 15th, 2019](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.5.2) + +### Public +- Fix reusing of log files after rolling (#1042) +- Fix creation of too many log files (#1049) +- Preliminary compatibility with Swift 5 (backwards compatible with Swift 4) (#1044) +- core: loggers os logger variations have been added (#1039) + +### Internal +- Sync internal queues to prevent cleaning up log files too soon in tests (#1053) +- DDLog checks for NULL values and for global queue dispatching has been added (#1045) + + +## [3.5.1 - Xcode 10 on Feb 4th, 2019](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.5.1) + +### Public +- Fix high CPU usage because of empty fileAttributes and / or too high rollingFrequceny (#1028) + + +## [3.5.0 - Xcode 10 on Jan 25th, 2019](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.5.0) + +### Public +- Added `logFileHeader` property to `DDLogFileManagerDefault`. Override to set header for each created file. #998 +- `DDFileLogger` now accepts a `dispatch_queue_t` which it uses to run callbacks. If not provided, the default global queue is used. #1003 +- Added opt-in buffering to `DDFileLogger`. Call `wrapWithBuffer` to create a file logger which buffers. #1001, #1012 +- Add `DDAssert` and `DDAssertionFailure` functions for Swift #934 +- Add `DD_LOG_LEVEL` define (which can be set in `GCC_PREPROCESSOR_DEFINITIONS`) for Swift to set default log level (enables stripping for strings that are not logged). #952 +- Add `asyncLoggingEnabled` global variable to control asynchronous logging. #1019 + +### Internal +- Prevent memory access errors caused by a failed fetch #944 +- Fix common warnings emitted by `-Wall`, `-Wconversion`, `-Wextra`, etc #943, #931 +- Fixes issue that could cause log messages to become interleaved when there are multiple `DDFileLogger`s #985 +- `DispatchQueueFormatter` knows about `com.apple.root.default-qos.overcommit` now #932 +- Fix thread safety issues in `DDFileLogger`. Makes it a little harder to deadlock in some cases. #986, #1003, #946 +- Fix availability checks and memory leak #996 + +### Repository +- Reduce podspec to two subspecs and remove customized modulemap #976 +- Add danger support for PR checks #962 - fixes #956 +- Merged framework targets + using `xcconfig` + deployment target `iOS 8` and `Mac OS 10.10` #959 e97da34 +- Documentation update #955 e7414ae 0239196 #933 +- Full links to Docs and other resources so they are resolved on external pages (i.e. https://cocoapods.org/pods/CocoaLumberjack) e9d6971 +- Replace `OSAtomic` with `stdatomic` in `DDDispatchQueueLogFormatter` #957 #958 +- Add Stale Bot + configuration #953 +- Update to Xcode 10 and Swift 4.2 compiler #950 +- Xcode 10 scheme changes #949 +- Update incomplete BSD 3-Clause License #942 +- Updated to CocoaPods 1.5.3 2d0590f +- Use Xcode 9.4 image for tests #939 +- Xcode (schemes) version bumps #938 +- Update demo and documentation about CustomLogLevels #1023 + + +## [3.4.2 - Xcode 9.3 on Apr 17th, 2018](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.4.2) +- Update README.md #912 +- Fixed typo in pull request template #913 +- Fix `-Wimplicit-retain-self` warnings #915 +- Update memory management in dynamic logging #916 +- Xcode 9.3 support #921 #923 #926 #927 +- Add extern "C" for Objective-C++ #922 +- Add `flush` method to the `DDFileLogger` #928 + + +## [3.4.1 - Xcode 9.1 on Jan 26th, 2018](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.4.1) +- Fix `DDLogFileManagerDefault` `-isLogFile` #909 +- Fix locking the main thread #911 + + +## [3.4.0 - Xcode 9.1 on Jan 3rd, 2018](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.4.0) +- Fix Travis CI #895 +- Fix typos #896 +- Fix schemes and link errors #897 #899 #903 #907 + + +## [3.3.0 - Xcode 9 on Oct 3rd, 2017](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.3.0) +- Xcode 9 support and Swift 4 support #890 #893 +- Replace `OSSpinLock` with `pthread_mutex` #889 + + +## [3.2.1 - Xcode 9 beta on Aug 21st, 2017](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.2.1) +- Xcode 9 beta support #874 #873 #884 #883 #882 +- Fixed some issues around deleting log files #868 #879 +- update 'Use Log Level per Logger' doc #888 +- Remove empty asset catalogs so that they don't show up in Open Quickly #877 +- Fixed typo in pull request template #880 + + +## [3.2.0 - Swift 3.0.0, Xcode 8.3 on May 3rd, 2017](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.2.0) +- Xcode 8.3 support #860 #853 +- added a very basic `os_log` (unified logging) logger #850 #856 +- Use `NSFileProtectionType` instead of `NSString` #866 +- Optimized timestamp calculation in `DDTTYLogger` #851 +- Updated docs #864 +- Fix Travis #863 +- Fixed nullability of `DDLogMessage.function` #849 `DDExtractFileNameWithoutExtension` #845 +- Ignore `Carthage/Build` directory #862 +- Updated schemes #859 #857 + + +## [3.1.0 - Swift 3.0.1, Xcode 8.1 on Feb 22nd, 2017](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.1.0) +- Swift 3.0.1 and Xcode 8.1 support via #816 +- Fix Carthage build and updated the podspec structure #819 #818 #784 #790 #782 #778 #815 +- Fix CLIColor.h not included in umbrella header #781 #796 #813 #783 +- Fix crash in `[DDLog log:level:flag:context:file:function:line:tag:format:]` #831 #830 +- Code improvements: + - using class properties #779 + - nullability #803 #809 #776 + - fix static analyzer issues #822 #828 + - optimized `USE_DISPATCH_CURRENT_QUEUE_LABEL` and `USE_DISPATCH_GET_CURRENT_QUEUE` macros #829 + - fixed dispatch_source_set_timer() usage #834 + - fixed misuse of non null parameter in `DDFileLogger fileAttributes` #835 + - store calendar in logger queue specifics for multi-thread safety #837 + - reenable default `init` method for `DDLogMessage` class #838 +- Added option to not copy messages #832 +- Added new hooks when adding loggers and formatters #836 +- Ability to create new log files every day #736 +- Skip messages in ASL logger which are filtered out by the formatter #786 #742 +- Fixed #823 by adding a `hash` implementation for `DDFileLogger` - same as `isEqual`, it only considers the `filePath` 7ceed08 +- Fix Travis CI build #807 +- Updated docs #798 #808 #811 #810 #820 + + +## [3.0.0 - Swift 3.0, Xcode 8 on Sep 21st, 2016](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.0.0) +- Swift 3.0 and Xcode 8 support via #769, fixes #771 and #772. Many thanks to @ffried @max-potapov @chrisdoc @BarakRL @devxoul and the others who contributed + + +## [2.4.0 - Swift 2.3 on Sep 19th, 2016](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.4.0) +- Swift 2.3 explicit so that the project compiles on Xcode 8 - #747 #773 fix #762 #763 #766 +- CocoaPods 1.0.0 fully adopted - 0f5a793 637dfc1 70439fe #729 +- Fix CLIColor.h not found for non-AppKit binaries w/o clang modules #745 +- Retrieve the `DDLogLevel` of each logger associated to `DDLog` #753 +- updated doc: #727 a9f54c9 #741, diagrams in 8bd128d +- Added CONTRIBUTING, ISSUE and PULL_REQUEST TEMPLATE and added a small Communication section to the Readme +- Fixed an issue with one demo #760 + + +## [2.3.0 - Swift 2.2, Xcode7.3 on May 2nd, 2016](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.3.0) +- Updated to Swift 2.2 - #704 +- replaced deprecated `__FUNCTION__`, `__FILE__`, `__LINE__` with newly added to Swift 2.2: `#function`, `#file`, `#line` +- Xcode 7.3 update - #692 #662 +- simplify usage and integration of the static library target - #657 +- DDLog usable via instances - #679 +- Swift cleanup - #649 +- Enable Application extension API only for tvOS - #701 +- Added `appletvos` and `appletvsimulator` to `SUPPORTED_PLATFORMS` and set `TVOS_DEPLOYMENT_TARGET` - #707 +- fixed `OSSpinLock` init issue - #653 +- Added check to prevent duplicate loggers - #682 +- fixed typo in import - #693 +- updated the docs - #646 #650 #656 #655 #661 #664 #667 #684 #724 + + +## [2.2.0 - TVOS, Xcode7.1 on Oct 28th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.2.0) +- added `tvOS` support (thanks [@sinoru](https://github.com/sinoru)) - [#634](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/634) [#640](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/640) [#630](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/630) [#628](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/628) [#618](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/618) [#611](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/611) +- Remove `(escaping)` from the Swift `@autoclosure` parameters - [#642](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/642) + + +## [2.1.0 - Swift 2.0, WatchOS, Xcode7 on Oct 23rd, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.1.0) +- Fixed the version for the Carthage builds - see [#633](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/633) +- Improved documentation + + +## [2.1.0 RC - Swift 2.0, WatchOS, Xcode7 on Oct 22nd, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.1.0-rc) +- Refactored the `NSDateFormatter` related code to fix a bunch of issues: [#621](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/621) +- Fix Issue [#488](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/488): Support `DDLog` without `AppKit Dependency` (`#define DD_CLI`): [#627](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/627) +- Re-add `NS_DESIGNATED_INITIALIZER` [#619](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/619) + + +## [2.1.0 Beta - Swift 2.0, WatchOS, Xcode7 on Oct 12th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.1.0-beta) +- Updated the library to use Swift 2.0 and Xcode 7 [#617](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/617) [#545](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/545) [#534](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/534) +- WatchOS support (2.0) [#583](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/583) [#581](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/581) [#579](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/579) + + +## [2.0.3 Patch for 2.0.0 on Oct 13th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.3) + +- Compatibility with Xcode 6 that was broken by the 2.0.2 patch - [f042fd3](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/f042fd3) + + +## [2.0.2 Patch for 2.0.0 on Oct 12th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.2) + +- Swift 1.2 fixes [#546](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/546) [#578](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/578) plus and update to Swift 2.0 [5627dff](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/5627dff) imported from our swift_2.0 branch +- Make build work on `tvOS` [#597](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/597) +- Make `CocoaLumberjackSwift-iOS` target depends on `CocoaLumberjack-iOS` [#575](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/575) +- `APPLICATION_EXTENSION_API_ONLY` to `YES` for Extensions [#576](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/576) +- Remove unnecessary `NS_DESIGNATED_INITIALIZER`s [#593](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/593) fixes [#592](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/592) +- Add ignore warning mark for `DDMakeColor` [#553](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/553) +- Kill unused function warnings from `DDTTYLogger.h` [#613](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/613) +- Flag unused parameters as being unused to silence strict warnings [#566](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/566) +- Extend ignore unused warning pragma to cover all platforms [#559](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/559) +- Removed images.xcassets from Mobile project [#580](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/580) +- Silence the Xcode 7 upgrade check - [#595](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/595) +- Fix import for when CL framework files are manually imported into project [#560](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/560) +- Don't override defines in case they're already set at project level [#551](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/551) +- log full filepath when failing to set attribute [#550](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/550) +- Fix issue in standalone build with `DDLegacyMacros.h` [#552](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/552) +- Update `CustomFormatters.md` with proper thread-safe blurb [#555](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/555) +- typo in parameter's variable name fixed [#568](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/568) +- Typo: minor fix [#571](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/571) +- Surely we should be adding 1, not 0 for `OSAtomicAdd32` ? [#587](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/587) +- `rollLogFileWithCompletionBlock` calls back on background queue instead of main queue [#589](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/589) +- Removing extraneous `\` on line 55 [#600](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/600) +- Updated `GettingStarted.md` to include `ddLogLevel` [#602](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/602) +- Remove redundant check for `processorCount` availability [#604](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/604) + + +## [2.0.1 Patch for 2.0.0 on Jun 25th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.1) + +- **Carthage support** [#521](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/521) [#526](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/526) +- fixed crash on `DDASLLogCapture` when `TIME` or `TIME_NSEC` is `NULL` [#484](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/484) +- **Swift** fixes and improvements: [#483](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/483) [#509](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/509) [#518](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/518) [#522](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/522) [5eafceb](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/5eafceb) +- Unit tests: [#500](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/500) [#498](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/498) [#499](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/499) +- Fix [#478](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/478) by reverting [#473](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/473) +- Add `armv7s` to static library [#538](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/538) +- Fix `NSLog` `threadid` mismatch with iOS 8+/OSX 10.10+ [#514](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/514) +- Fixed the `LogV` macros so that avalist is no longer undefined [#511](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/511) +- Using type safe `DDColor` alias instead of #define directive [#506](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/506) +- Several fixes/tweaks to `DDASLLogCapture` [#512](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/512) +- Prevent duplicate log entries when both `DDASLLogCapture` and `DDASLLogger` are used [#515](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/515) +- Fix memory leaks in `DDTTYLogger`, add self annotations to blocks [#536](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/536) +- Update older syntax to modern subscripting for array access [#482](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/482) +- Remove execute permission on non-executable files [#517](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/517) +- Change code samples to use `DDLogFlagWarning` [#520](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/520) +- Fix seemingly obvious typo in the `toLogLevel` function [#508](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/508) + + +## [CocoaLumberjack 2.0.0 on Mar 13th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0) + +The library was strongly refactored, with a few goals in mind: +- Swift support - that we will release in a separate milestone, since CocoaPods 0.36.0 just got out +- Unit tests support +- reorganised things (on disk) +- better coding style + +See [Migration from 1.x to 2.x](https://github.com/CocoaLumberjack/CocoaLumberjack#migrating-to-2x) + + +## [2.0.0-rc2 on Feb 20th, 2015](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-rc2) + +- Bucket of Swift improvements - [#434](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/434) [#437](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/437) [#449](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/449) [#440](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/440) +- Fixed [#433](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/433) (build issue due to dispatch_queue properties) - [#455](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/455) +- Enable codesign for iOS device framework builds - [#444](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/444) +- Declare `automaticallyAppendNewlineForCustomFormatters` properties as `nonatomic` - [#443](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/443) +- Warning fixes & type standardization - [#419](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/419) +- Legacy checks updated - [#424](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/424) +- Documentation updates + + +## [2.0.0-rc on Dec 11th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-rc) + +- Fix `dispatch_queue_t` properties. +- Fix `registeredClasses` crashes at launch. + + +## [2.0.0-beta4 on Nov 7th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-beta4) + +- Major refactoring and clean up. +- Remove superfluous `log` from property names and use underscore for direct variable access. +- Preliminary Swift support through `CocoaLumberjack.swift`. +- Automatic 1.9.x legacy support when `DDLog.h` is imported instead of the new `CocoaLumberjack.h`. + + +## [2.0.0-beta3 on Oct 21st, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-beta3) + +- Modernize flag variables to be `NS_OPTIONS`/`NS_ENUM`. +- Change the log flags and levels to `NSUInteger`. +- Fix warning when compiled with assertions blocked. +- Crash fixes. + + +## [2.0.0-beta2 on Sep 30th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-beta2) + +- Cleanup code. +- Match `NSLog` read UID functionality in `DDASLLogger`. +- Update framework and static libraries. + + +## [2.0.0 Beta on Aug 12th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/2.0.0-beta) + +See [Migrate from 1.x to 2.x](https://github.com/CocoaLumberjack/CocoaLumberjack#migrating-to-2x) + + +## [1.9.2 Updated patch release for 1.9.0 on Aug 11th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.9.2) + +- Fixed `NSCalendar components:fromDate:` crash - [#140](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/140) [#307](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/307) [#216](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/216) +- New `DDAssert` macros - [#306](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/306) +- Limit log growth by disk space only, not the number of files - [#195](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/195) [#303](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/303) +- Change the mechanism for adding new line character (i.e. '\n\) to log messages in some logger - [#308](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/308) [#310](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/310) +- Fixed deprecations - [#320](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/320) [#312](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/312) [#317](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/317) +- `aslmsg` not freed and causing memory leak - [#314](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/314) +- Fixed `CompressingLogFileManager` compression bug - [#315](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/315) +- Remove unnecessary `NULL` check before `free()` - [#316](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/316) + + +## [1.9.1 Patch release for 1.9.0 on Jun 30th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.9.1) + +- Fixed issues in rolling frequency - [#243](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/243) [#295](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/295) [@georgekola](https://github.com/georgekola) +- Fixed critical issue, `addLogger` method should use a full bit mask instead of `LOG_LEVEL_VERBOSE`, otherwise extended logs or extra flags are ignored [fe6824c](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/fe6824c) [@robbiehanson](https://github.com/robbiehanson) +- Performance optimisation: use compiler macros to skip iOS version checks - [4656d3b](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/4656d3b) [#298](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/298) [#291](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/291) [@robbiehanson](https://github.com/robbiehanson) [@liviur](https://github.com/liviur) +- Changed the `Build Active Architecture Only` to `NO` [#294](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/294) [#293](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/293) +- Optimisation by reusing `NSDateFormatter` instances [#296](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/296) [#301](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/301) + + +## [1.9.0 New ASL capture module, several File logger fixes on May 23rd, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.9.0) + +- New ASL capture module [#242](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/242) [#263](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/263) +- Override default `NSFileProtection` handling [#285](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/285) +- Replaced warnings when ARC was not enabled with errors [#284](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/284) +- Fix for issue [#278](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/278) where really large log files can keep growing [#280](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/280) +- Fixed Xcode warnings [#279](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/279) +- Update `calendarUnitFlags` with new iOS SDK values [#277](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/277) +- Fix possible crash in `[NSCalendar components:fromDate:]` [#277](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/277) +- Fix [#262](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/262) inverted ifs when renaming log [#264](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/264) +- Proper way of doing singletons (via `dispatch_once`) [#259](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/259) +- Explicitly declare `DDFileLogger` and `DDDispatchQueueLogFormatter ` properties as atomic to avoid Xcode warnings [#258](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/258) +- Set `NSFileProtectionKey` on the temporary file created during compression [#256](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/256) +- Fix a rare crash in `CompressingLogFileManager` caused by an unchecked result from read [#255](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/255) +- Add explicit casts for integer conversion [#253](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/253) +- Replace use of `NSThread.detachNewThreadSelector` [#251](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/251) +- Add a constructor override for `initWithLogsDirectory:` [#252](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/252) +- Check and log the streamError whenever we fail to write during compression and log any failures when removing the original file or cleaning up the temporary file after compression failed [#250](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/250) +- Following Apple's guidelines for iOS Static Libraries [#249](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/249) +- Some extra warnings for the mobile framework xcode project [a2e5666](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/a2e5666) +- Update `FineGrainedLoggingAppDelegate.m` [#244](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/244) +- New `[DDLog log:message:]` primitive [7f8af2e](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/7f8af2e) +- Fixed issue [#181](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/181) when logging messages in iOS7 devices aren't properly retrieved by `asl_search` [#240](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/240) +- Allow prevention of log file reuse [#238](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/238) +- `DDTTYLogger`: Favour XcodeColors environment variable [#237](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/237) +- `DDLog`: calling `atexit_b` in CLI applications, that use Foundation framework [#234](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/234) + + +## [1.8.1 AllLoggers and bugfixes on Feb 14th, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.8.1) + +- read access to all loggers - [#217](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/217) [#219](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/219) +- fixed bug with archived logs not being handled correctly on iOS simulator - [#218](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/218) +- log the `strerror(errno)` value when `setxattr()` fails - [#211](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/211) +- Add a check for an archived log before overwriting - [#214](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/214) +- improved safety by using assertions instead of comments (`DDLog` in the core) - [#221](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/221) +- added Lumberjack logo :) + + +## [1.8.0 Better CL support, custom logfile name format, bugfixes on Jan 21st, 2014](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.8.0) + +- `DDFileLogger` custom logfile (name) format - [#208](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/208) +- Security static analysis fix - [#202](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/202) +- `DDFileLogger`: using `CFBundleIdentifier` as a log filename prefix on OSX and iOS - [#206](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/206) +- Allow disabling of specific levels per-logger - [#204](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/204) +- Improve support for OS X command line tools - [#194](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/194) +- `DDFileLogger`: fixed crash that occurred in case if application name == nil - [#198](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/198) +- `DDFileLogger`: fixed comment - [#199](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/199) +- Fix Travis - [#205](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/205) + + +## [1.7.0 New log file naming convention and CocoaLumberjack organisation on Dec 10th, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.7.0) + +- new log file naming convention - [#191](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/191) +- completed transition to **CocoaLumberjack** organisation - [#188](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/188) + + +## [1.6.5.1 Patch release for Xcode 4.4+ compatibility on Dec 4th, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.5.1) + +- fixed compatibility with Xcode 4.4+ [#187](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/187) + + +## [1.6.5 File Logger refactoring, Multi Formatter, preffixed extension classes on Dec 3rd, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.5) + +`DDFileLogger` refactoring and fixes (thanks [@dvor](https://github.com/dvor) and [@an0](https://github.com/an0)): +- Fixed [#63](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/63) Loggers don't flush in Command Line Tool [#184](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/184) +- Fixed [#52](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/52) Force log rotation [#183](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/183) +- Fixed [#55](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/55) After deleting log file or log dir they aren't created again without relaunching the app [#183](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/183) +- Fixed [#129](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/129) [iOS] `DDFileLogger` causes crash when logging from background app [#183](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/183) +- Fixed [#153](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/153) Log file on iPhone only contains a single line [#177](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/177) +- Fixed [#155](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/155) How do I combine all my log levels into one file? [#177](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/177) +- Fixed [#175](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/175) `DFileLogger` `creationDate` bug on 64-bit iOS system [#177](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/177) +- Allow customizing the naming convention for log files to use timestamps [#174](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/174) + +Other: +- Implemented multiple formatter (`DDMultiFormatter` - alows chaining of formatters) [#178](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/178) +- Added DD prefix to extension classes (`ContextFilterLogFormatter` and `DispatchQueueLogFormatter`) [#178](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/178) +- Updated code indentation: Tabs changed to spaces [#180](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/180) +- Included `DDLog+LOGV.h` in Cocoapods sources [d253bd7](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/d253bd7) +- other fixes/improvements + + +## [1.6.4 Fix compatibility with 3rd party frameworks on Nov 21st, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.4) + +* "Fix" conflicts with 3rd party libraries using `CocoaLumberjack` [#172](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/172) +* Ignore deprecated warning for `dispatch_get_current_queue` [#167](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/167) +* Add new `DEBUG` log level support to included loggers [#166](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/166) +* Method declarations that make it easier to extend/modify `DispatchQueueLogFormatter` [#164](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/164) + + +## [1.6.3 New macros, updated podspec and bug fixes on Apr 2nd, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.3) + +* Add `LOGV`-style macros [#161](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/161) +* Fix getting queue's label [#159](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/159) +* New log level `DEBUG` [#145](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/145) +* Use `DISPATCH_CURRENT_QUEUE_LABEL` if available [#159](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/159) +* Different `logLevel` per each logger [#151](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/151) +* Created 2 subspecs, `Core` and `Extensions` [#152](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/152) +* Updated observer for keypath using `NSStringFromSelector` + `@selector` [38e5da3](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/38e5da3) +* Replaced `id` return type with `instancetype` [ebee454](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/ebee454) +* Remove implicit conversion warnings [#149](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/149) +* `DDTTYLogger`: Allow to set default color profiles for all contexts at once [#146](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/146) [#158](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/158) +* `DDTTYLogger`: By default apply `setForegroundColor:backgroundColor:forFlag:` to `LOG_CONTEXT_ALL` [#154](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/154) +* `DispatchQueueLogFormatter`: Use modern Objective-C [#142](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/142) +* `DispatchQueueLogFormatter`: Make sure to always use a `NSGregorianCalendar` for date formatter [#142](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/142) +* Replaced explicit reference to class name in `logFileWithPath` factory method [#131](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/131) +* Catch exceptions in `logMessage:` [#130](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/130) +* Fix enum type conversion warnings [#124](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/124) +* Add deployment target condition for workaround [#121](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/121) +* Fix static analyzer warnings about `nil` values in dictionary [#122](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/122) +* Fix `dispatch_get_current_queue` crash [#121](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/121) +* Fixing colors in greyscale color-space not working [d019cfd](https://github.com/CocoaLumberjack/CocoaLumberjack/commit/d019cfd) +* Guard around `dispatch_resume()` being called with null pointer [#107](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/107) +* `NULL` safety checks [#107](https://github.com/CocoaLumberjack/CocoaLumberjack/pull/107) + + +## [1.6.2 on Apr 2nd, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.2) + +## [1.6.1 on Apr 2nd, 2013](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6.1) + +## [1.6 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.6) + +## [1.5.1 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.5.1) + +## [1.5 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.5) + +## [1.4.1 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.4.1) + +## [1.4 on Jul 3rd, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.4) + +## [1.3.3 on Mar 30th, 2012](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.3.3) + +## [1.3.2 on Dec 23rd, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.3.2) + +## [1.3.1 on Dec 9th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.3.1) + +## [1.3 on Dec 9th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.3) + +## [1.2.3 on Dec 9th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.2.3) + +## [1.2.2 on Dec 9th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.2.2) + +## [1.2.1 on Oct 13th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.2.1) + +## [1.2 on Oct 13th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.2) + +## [1.1 on Oct 13th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.1) + +## [1.0 on Oct 13th, 2011](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/1.0) diff --git a/Pods/CocoaLumberjack/CocoaLumberjack.podspec b/Pods/CocoaLumberjack/CocoaLumberjack.podspec deleted file mode 100644 index a62a597..0000000 --- a/Pods/CocoaLumberjack/CocoaLumberjack.podspec +++ /dev/null @@ -1,18 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'CocoaLumberjack' - s.version = '1.3.3' - s.license = 'BSD' - s.summary = 'A fast & simple, yet powerful & flexible logging framework for Mac and iOS.' - s.homepage = 'https://github.com/robbiehanson/CocoaLumberjack' - s.author = { 'Robbie Hanson' => 'robbiehanson@deusty.com' } - s.source = { :git => 'https://github.com/robbiehanson/CocoaLumberjack.git', - :tag => '1.3.3' } - - s.description = 'It is similar in concept to other popular logging frameworks such as log4j, ' \ - 'yet is designed specifically for objective-c, and takes advantage of features ' \ - 'such as multi-threading, grand central dispatch (if available), lockless ' \ - 'atomic operations, and the dynamic nature of the objective-c runtime.' - - s.source_files = 'Lumberjack' - s.clean_paths = 'Benchmarking', 'Xcode' -end diff --git a/Pods/CocoaLumberjack/LICENSE b/Pods/CocoaLumberjack/LICENSE new file mode 100644 index 0000000..27f20f7 --- /dev/null +++ b/Pods/CocoaLumberjack/LICENSE @@ -0,0 +1,14 @@ +BSD 3-Clause License + +Copyright (c) 2010-2024, Deusty, LLC +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of Deusty nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of Deusty, LLC. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Pods/CocoaLumberjack/LICENSE.txt b/Pods/CocoaLumberjack/LICENSE.txt deleted file mode 100644 index 66a942c..0000000 --- a/Pods/CocoaLumberjack/LICENSE.txt +++ /dev/null @@ -1,18 +0,0 @@ -Software License Agreement (BSD License) - -Copyright (c) 2010, Deusty, LLC -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Neither the name of Deusty nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of Deusty, LLC. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h b/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h deleted file mode 100755 index 0f2e963..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.h +++ /dev/null @@ -1,41 +0,0 @@ -#import -#import - -#import "DDLog.h" - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted - * - * - * This class provides a logger for the Apple System Log facility. - * - * As described in the "Getting Started" page, - * the traditional NSLog() function directs it's output to two places: - * - * - Apple System Log - * - StdErr (if stderr is a TTY) so log statements show up in Xcode console - * - * To duplicate NSLog() functionality you can simply add this logger and a tty logger. - * However, if you instead choose to use file logging (for faster performance), - * you may choose to use a file logger and a tty logger. -**/ - -@interface DDASLLogger : DDAbstractLogger -{ - aslclient client; -} - -+ (DDASLLogger *)sharedInstance; - -// Inherited from DDAbstractLogger - -// - (id )logFormatter; -// - (void)setLogFormatter:(id )formatter; - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m b/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m deleted file mode 100755 index 4ec1e7c..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/DDASLLogger.m +++ /dev/null @@ -1,99 +0,0 @@ -#import "DDASLLogger.h" - -#import - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted -**/ - -#if ! __has_feature(objc_arc) -#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). -#endif - - -@implementation DDASLLogger - -static DDASLLogger *sharedInstance; - -/** - * The runtime sends initialize to each class in a program exactly one time just before the class, - * or any class that inherits from it, is sent its first message from within the program. (Thus the - * method may never be invoked if the class is not used.) The runtime sends the initialize message to - * classes in a thread-safe manner. Superclasses receive this message before their subclasses. - * - * This method may also be called directly (assumably by accident), hence the safety mechanism. -**/ -+ (void)initialize -{ - static BOOL initialized = NO; - if (!initialized) - { - initialized = YES; - - sharedInstance = [[DDASLLogger alloc] init]; - } -} - -+ (DDASLLogger *)sharedInstance -{ - return sharedInstance; -} - -- (id)init -{ - if (sharedInstance != nil) - { - return nil; - } - - if ((self = [super init])) - { - // A default asl client is provided for the main thread, - // but background threads need to create their own client. - - client = asl_open(NULL, "com.apple.console", 0); - } - return self; -} - -- (void)logMessage:(DDLogMessage *)logMessage -{ - NSString *logMsg = logMessage->logMsg; - - if (formatter) - { - logMsg = [formatter formatLogMessage:logMessage]; - } - - if (logMsg) - { - const char *msg = [logMsg UTF8String]; - - int aslLogLevel; - switch (logMessage->logLevel) - { - // Note: By default ASL will filter anything above level 5 (Notice). - // So our mappings shouldn't go above that level. - - case 1 : aslLogLevel = ASL_LEVEL_CRIT; break; - case 2 : aslLogLevel = ASL_LEVEL_ERR; break; - case 3 : aslLogLevel = ASL_LEVEL_WARNING; break; - default : aslLogLevel = ASL_LEVEL_NOTICE; break; - } - - asl_log(client, NULL, aslLogLevel, "%s", msg); - } -} - -- (NSString *)loggerName -{ - return @"cocoa.lumberjack.aslLogger"; -} - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m b/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m deleted file mode 100644 index 1a2b7cb..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.m +++ /dev/null @@ -1,654 +0,0 @@ -#import "DDAbstractDatabaseLogger.h" -#import - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted -**/ - -#if ! __has_feature(objc_arc) -#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). -#endif - -/** - * Does ARC support support GCD objects? - * It does if the minimum deployment target is iOS 6+ or Mac OS X 8+ -**/ -#if TARGET_OS_IPHONE - - // Compiling for iOS - - #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 // iOS 6.0 or later - #define NEEDS_DISPATCH_RETAIN_RELEASE 0 - #else // iOS 5.X or earlier - #define NEEDS_DISPATCH_RETAIN_RELEASE 1 - #endif - -#else - - // Compiling for Mac OS X - - #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 // Mac OS X 10.8 or later - #define NEEDS_DISPATCH_RETAIN_RELEASE 0 - #else - #define NEEDS_DISPATCH_RETAIN_RELEASE 1 // Mac OS X 10.7 or earlier - #endif - -#endif - -@interface DDAbstractDatabaseLogger () -- (void)destroySaveTimer; -- (void)destroyDeleteTimer; -@end - -#pragma mark - - -@implementation DDAbstractDatabaseLogger - -- (id)init -{ - if ((self = [super init])) - { - saveThreshold = 500; - saveInterval = 60; // 60 seconds - maxAge = (60 * 60 * 24 * 7); // 7 days - deleteInterval = (60 * 5); // 5 minutes - } - return self; -} - -- (void)dealloc -{ - [self destroySaveTimer]; - [self destroyDeleteTimer]; - -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Override Me -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (BOOL)db_log:(DDLogMessage *)logMessage -{ - // Override me and add your implementation. - // - // Return YES if an item was added to the buffer. - // Return NO if the logMessage was ignored. - - return NO; -} - -- (void)db_save -{ - // Override me and add your implementation. -} - -- (void)db_delete -{ - // Override me and add your implementation. -} - -- (void)db_saveAndDelete -{ - // Override me and add your implementation. -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Private API -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)performSaveAndSuspendSaveTimer -{ - if (unsavedCount > 0) - { - if (deleteOnEverySave) - [self db_saveAndDelete]; - else - [self db_save]; - } - - unsavedCount = 0; - unsavedTime = 0; - - if (saveTimer && !saveTimerSuspended) - { - dispatch_suspend(saveTimer); - saveTimerSuspended = YES; - } -} - -- (void)performDelete -{ - if (maxAge > 0.0) - { - [self db_delete]; - - lastDeleteTime = dispatch_time(DISPATCH_TIME_NOW, 0); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Timers -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)destroySaveTimer -{ - if (saveTimer) - { - dispatch_source_cancel(saveTimer); - if (saveTimerSuspended) - { - // Must resume a timer before releasing it (or it will crash) - dispatch_resume(saveTimer); - saveTimerSuspended = NO; - } - #if NEEDS_DISPATCH_RETAIN_RELEASE - dispatch_release(saveTimer); - #endif - saveTimer = NULL; - } -} - -- (void)updateAndResumeSaveTimer -{ - if ((saveTimer != NULL) && (saveInterval > 0.0) && (unsavedTime > 0.0)) - { - uint64_t interval = saveInterval * NSEC_PER_SEC; - dispatch_time_t startTime = dispatch_time(unsavedTime, interval); - - dispatch_source_set_timer(saveTimer, startTime, interval, 1.0); - - if (saveTimerSuspended) - { - dispatch_resume(saveTimer); - saveTimerSuspended = NO; - } - } -} - -- (void)createSuspendedSaveTimer -{ - if ((saveTimer == NULL) && (saveInterval > 0.0)) - { - saveTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, loggerQueue); - - dispatch_source_set_event_handler(saveTimer, ^{ @autoreleasepool { - - [self performSaveAndSuspendSaveTimer]; - - }}); - - saveTimerSuspended = YES; - } -} - -- (void)destroyDeleteTimer -{ - if (deleteTimer) - { - dispatch_source_cancel(deleteTimer); - #if NEEDS_DISPATCH_RETAIN_RELEASE - dispatch_release(deleteTimer); - #endif - deleteTimer = NULL; - } -} - -- (void)updateDeleteTimer -{ - if ((deleteTimer != NULL) && (deleteInterval > 0.0) && (maxAge > 0.0)) - { - uint64_t interval = deleteInterval * NSEC_PER_SEC; - dispatch_time_t startTime; - - if (lastDeleteTime > 0) - startTime = dispatch_time(lastDeleteTime, interval); - else - startTime = dispatch_time(DISPATCH_TIME_NOW, interval); - - dispatch_source_set_timer(deleteTimer, startTime, interval, 1.0); - } -} - -- (void)createAndStartDeleteTimer -{ - if ((deleteTimer == NULL) && (deleteInterval > 0.0) && (maxAge > 0.0)) - { - deleteTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, loggerQueue); - - dispatch_source_set_event_handler(deleteTimer, ^{ @autoreleasepool { - - [self performDelete]; - - }}); - - [self updateDeleteTimer]; - - dispatch_resume(deleteTimer); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Configuration -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (NSUInteger)saveThreshold -{ - if (dispatch_get_current_queue() == loggerQueue) - { - return saveThreshold; - } - else - { - __block NSUInteger result; - - dispatch_sync(loggerQueue, ^{ - result = saveThreshold; - }); - - return result; - } -} - -- (void)setSaveThreshold:(NSUInteger)threshold -{ - dispatch_block_t block = ^{ - - if (saveThreshold != threshold) - { - saveThreshold = threshold; - - // Since the saveThreshold has changed, - // we check to see if the current unsavedCount has surpassed the new threshold. - // - // If it has, we immediately save the log. - - if ((unsavedCount >= saveThreshold) && (saveThreshold > 0)) - { - @autoreleasepool { - - [self performSaveAndSuspendSaveTimer]; - - } - } - } - }; - - if (dispatch_get_current_queue() == loggerQueue) - block(); - else - dispatch_async(loggerQueue, block); -} - -- (NSTimeInterval)saveInterval -{ - if (dispatch_get_current_queue() == loggerQueue) - { - return saveInterval; - } - else - { - __block NSTimeInterval result; - - dispatch_sync(loggerQueue, ^{ - result = saveInterval; - }); - - return result; - } -} - -- (void)setSaveInterval:(NSTimeInterval)interval -{ - dispatch_block_t block = ^{ - - // C99 recommended floating point comparison macro - // Read: isLessThanOrGreaterThan(floatA, floatB) - - if (/* saveInterval != interval */ islessgreater(saveInterval, interval)) - { - saveInterval = interval; - - // There are several cases we need to handle here. - // - // 1. If the saveInterval was previously enabled and it just got disabled, - // then we need to stop the saveTimer. (And we might as well release it.) - // - // 2. If the saveInterval was previously disabled and it just got enabled, - // then we need to setup the saveTimer. (Plus we might need to do an immediate save.) - // - // 3. If the saveInterval increased, then we need to reset the timer so that it fires at the later date. - // - // 4. If the saveInterval decreased, then we need to reset the timer so that it fires at an earlier date. - // (Plus we might need to do an immediate save.) - - if (saveInterval > 0.0) - { - @autoreleasepool - { - if (saveTimer == NULL) - { - // Handles #2 - // - // Since the saveTimer uses the unsavedTime to calculate it's first fireDate, - // if a save is needed the timer will fire immediately. - - [self createSuspendedSaveTimer]; - [self updateAndResumeSaveTimer]; - } - else - { - // Handles #3 - // Handles #4 - // - // Since the saveTimer uses the unsavedTime to calculate it's first fireDate, - // if a save is needed the timer will fire immediately. - - [self updateAndResumeSaveTimer]; - } - } - } - else if (saveTimer) - { - // Handles #1 - - [self destroySaveTimer]; - } - } - }; - - if (dispatch_get_current_queue() == loggerQueue) - block(); - else - dispatch_async(loggerQueue, block); -} - -- (NSTimeInterval)maxAge -{ - if (dispatch_get_current_queue() == loggerQueue) - { - return maxAge; - } - else - { - __block NSTimeInterval result; - - dispatch_sync(loggerQueue, ^{ - result = maxAge; - }); - - return result; - } -} - -- (void)setMaxAge:(NSTimeInterval)interval -{ - dispatch_block_t block = ^{ - - // C99 recommended floating point comparison macro - // Read: isLessThanOrGreaterThan(floatA, floatB) - - if (/* maxAge != interval */ islessgreater(maxAge, interval)) - { - NSTimeInterval oldMaxAge = maxAge; - NSTimeInterval newMaxAge = interval; - - maxAge = interval; - - // There are several cases we need to handle here. - // - // 1. If the maxAge was previously enabled and it just got disabled, - // then we need to stop the deleteTimer. (And we might as well release it.) - // - // 2. If the maxAge was previously disabled and it just got enabled, - // then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.) - // - // 3. If the maxAge was increased, - // then we don't need to do anything. - // - // 4. If the maxAge was decreased, - // then we should do an immediate delete. - - BOOL shouldDeleteNow = NO; - - if (oldMaxAge > 0.0) - { - if (newMaxAge <= 0.0) - { - // Handles #1 - - [self destroyDeleteTimer]; - } - else if (oldMaxAge > newMaxAge) - { - // Handles #4 - shouldDeleteNow = YES; - } - } - else if (newMaxAge > 0.0) - { - // Handles #2 - shouldDeleteNow = YES; - } - - if (shouldDeleteNow) - { - @autoreleasepool - { - [self performDelete]; - - if (deleteTimer) - [self updateDeleteTimer]; - else - [self createAndStartDeleteTimer]; - } - } - } - }; - - if (dispatch_get_current_queue() == loggerQueue) - block(); - else - dispatch_async(loggerQueue, block); -} - -- (NSTimeInterval)deleteInterval -{ - if (dispatch_get_current_queue() == loggerQueue) - { - return deleteInterval; - } - else - { - __block NSTimeInterval result; - - dispatch_sync(loggerQueue, ^{ - result = deleteInterval; - }); - - return result; - } -} - -- (void)setDeleteInterval:(NSTimeInterval)interval -{ - dispatch_block_t block = ^{ - - // C99 recommended floating point comparison macro - // Read: isLessThanOrGreaterThan(floatA, floatB) - - if (/* deleteInterval != interval */ islessgreater(deleteInterval, interval)) - { - deleteInterval = interval; - - // There are several cases we need to handle here. - // - // 1. If the deleteInterval was previously enabled and it just got disabled, - // then we need to stop the deleteTimer. (And we might as well release it.) - // - // 2. If the deleteInterval was previously disabled and it just got enabled, - // then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.) - // - // 3. If the deleteInterval increased, then we need to reset the timer so that it fires at the later date. - // - // 4. If the deleteInterval decreased, then we need to reset the timer so that it fires at an earlier date. - // (Plus we might need to do an immediate delete.) - - if (deleteInterval > 0.0) - { - @autoreleasepool - { - if (deleteTimer == NULL) - { - // Handles #2 - // - // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate, - // if a delete is needed the timer will fire immediately. - - [self createAndStartDeleteTimer]; - } - else - { - // Handles #3 - // Handles #4 - // - // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate, - // if a save is needed the timer will fire immediately. - - [self updateDeleteTimer]; - } - } - } - else if (deleteTimer) - { - // Handles #1 - - [self destroyDeleteTimer]; - } - } - }; - - if (dispatch_get_current_queue() == loggerQueue) - block(); - else - dispatch_async(loggerQueue, block); -} - -- (BOOL)deleteOnEverySave -{ - if (dispatch_get_current_queue() == loggerQueue) - { - return deleteOnEverySave; - } - else - { - __block BOOL result; - - dispatch_sync(loggerQueue, ^{ - result = deleteOnEverySave; - }); - - return result; - } -} - -- (void)setDeleteOnEverySave:(BOOL)flag -{ - dispatch_block_t block = ^{ - - deleteOnEverySave = flag; - }; - - if (dispatch_get_current_queue() == loggerQueue) - block(); - else - dispatch_async(loggerQueue, block); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Public API -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)savePendingLogEntries -{ - dispatch_block_t block = ^{ @autoreleasepool { - - [self performSaveAndSuspendSaveTimer]; - }}; - - if (dispatch_get_current_queue() == loggerQueue) - block(); - else - dispatch_async(loggerQueue, block); -} - -- (void)deleteOldLogEntries -{ - dispatch_block_t block = ^{ @autoreleasepool { - - [self performDelete]; - }}; - - if (dispatch_get_current_queue() == loggerQueue) - block(); - else - dispatch_async(loggerQueue, block); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark DDLogger -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)didAddLogger -{ - // If you override me be sure to invoke [super didAddLogger]; - - [self createSuspendedSaveTimer]; - - [self createAndStartDeleteTimer]; -} - -- (void)willRemoveLogger -{ - // If you override me be sure to invoke [super willRemoveLogger]; - - [self performSaveAndSuspendSaveTimer]; - - [self destroySaveTimer]; - [self destroyDeleteTimer]; -} - -- (void)logMessage:(DDLogMessage *)logMessage -{ - if ([self db_log:logMessage]) - { - BOOL firstUnsavedEntry = (++unsavedCount == 1); - - if ((unsavedCount >= saveThreshold) && (saveThreshold > 0)) - { - [self performSaveAndSuspendSaveTimer]; - } - else if (firstUnsavedEntry) - { - unsavedTime = dispatch_time(DISPATCH_TIME_NOW, 0); - [self updateAndResumeSaveTimer]; - } - } -} - -- (void)flush -{ - // This method is invoked by DDLog's flushLog method. - // - // It is called automatically when the application quits, - // or if the developer invokes DDLog's flushLog method prior to crashing or something. - - [self performSaveAndSuspendSaveTimer]; -} - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h b/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h deleted file mode 100644 index 5af6376..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.h +++ /dev/null @@ -1,334 +0,0 @@ -#import -#import "DDLog.h" - -@class DDLogFileInfo; - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted - * - * - * This class provides a logger to write log statements to a file. -**/ - - -// Default configuration and safety/sanity values. -// -// maximumFileSize -> DEFAULT_LOG_MAX_FILE_SIZE -// rollingFrequency -> DEFAULT_LOG_ROLLING_FREQUENCY -// maximumNumberOfLogFiles -> DEFAULT_LOG_MAX_NUM_LOG_FILES -// -// You should carefully consider the proper configuration values for your application. - -#define DEFAULT_LOG_MAX_FILE_SIZE (1024 * 1024) // 1 MB -#define DEFAULT_LOG_ROLLING_FREQUENCY (60 * 60 * 24) // 24 Hours -#define DEFAULT_LOG_MAX_NUM_LOG_FILES (5) // 5 Files - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// The LogFileManager protocol is designed to allow you to control all aspects of your log files. -// -// The primary purpose of this is to allow you to do something with the log files after they have been rolled. -// Perhaps you want to compress them to save disk space. -// Perhaps you want to upload them to an FTP server. -// Perhaps you want to run some analytics on the file. -// -// A default LogFileManager is, of course, provided. -// The default LogFileManager simply deletes old log files according to the maximumNumberOfLogFiles property. -// -// This protocol provides various methods to fetch the list of log files. -// -// There are two variants: sorted and unsorted. -// If sorting is not necessary, the unsorted variant is obviously faster. -// The sorted variant will return an array sorted by when the log files were created, -// with the most recently created log file at index 0, and the oldest log file at the end of the array. -// -// You can fetch only the log file paths (full path including name), log file names (name only), -// or an array of DDLogFileInfo objects. -// The DDLogFileInfo class is documented below, and provides a handy wrapper that -// gives you easy access to various file attributes such as the creation date or the file size. - -@protocol DDLogFileManager -@required - -// Public properties - -/** - * The maximum number of archived log files to keep on disk. - * For example, if this property is set to 3, - * then the LogFileManager will only keep 3 archived log files (plus the current active log file) on disk. - * Once the active log file is rolled/archived, then the oldest of the existing 3 rolled/archived log files is deleted. - * - * You may optionally disable deleting old/rolled/archived log files by setting this property to zero. -**/ -@property (readwrite, assign) NSUInteger maximumNumberOfLogFiles; - -// Public methods - -- (NSString *)logsDirectory; - -- (NSArray *)unsortedLogFilePaths; -- (NSArray *)unsortedLogFileNames; -- (NSArray *)unsortedLogFileInfos; - -- (NSArray *)sortedLogFilePaths; -- (NSArray *)sortedLogFileNames; -- (NSArray *)sortedLogFileInfos; - -// Private methods (only to be used by DDFileLogger) - -- (NSString *)createNewLogFile; - -@optional - -// Notifications from DDFileLogger - -- (void)didArchiveLogFile:(NSString *)logFilePath; -- (void)didRollAndArchiveLogFile:(NSString *)logFilePath; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Default log file manager. - * - * All log files are placed inside the logsDirectory. - * If a specific logsDirectory isn't specified, the default directory is used. - * On Mac, this is in ~/Library/Logs/. - * On iPhone, this is in ~/Library/Caches/Logs. - * - * Log files are named "log-.txt", - * where uuid is a 6 character hexadecimal consisting of the set [0123456789ABCDEF]. - * - * Archived log files are automatically deleted according to the maximumNumberOfLogFiles property. -**/ -@interface DDLogFileManagerDefault : NSObject -{ - NSUInteger maximumNumberOfLogFiles; - NSString *_logsDirectory; -} - -- (id)init; -- (id)initWithLogsDirectory:(NSString *)logsDirectory; - -/* Inherited from DDLogFileManager protocol: - -@property (readwrite, assign) NSUInteger maximumNumberOfLogFiles; - -- (NSString *)logsDirectory; - -- (NSArray *)unsortedLogFilePaths; -- (NSArray *)unsortedLogFileNames; -- (NSArray *)unsortedLogFileInfos; - -- (NSArray *)sortedLogFilePaths; -- (NSArray *)sortedLogFileNames; -- (NSArray *)sortedLogFileInfos; - -*/ - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Most users will want file log messages to be prepended with the date and time. - * Rather than forcing the majority of users to write their own formatter, - * we will supply a logical default formatter. - * Users can easily replace this formatter with their own by invoking the setLogFormatter method. - * It can also be removed by calling setLogFormatter, and passing a nil parameter. - * - * In addition to the convenience of having a logical default formatter, - * it will also provide a template that makes it easy for developers to copy and change. -**/ -@interface DDLogFileFormatterDefault : NSObject -{ - NSDateFormatter *dateFormatter; -} - -- (id)init; -- (id)initWithDateFormatter:(NSDateFormatter *)dateFormatter; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@interface DDFileLogger : DDAbstractLogger -{ - __strong id logFileManager; - - DDLogFileInfo *currentLogFileInfo; - NSFileHandle *currentLogFileHandle; - - dispatch_source_t rollingTimer; - - unsigned long long maximumFileSize; - NSTimeInterval rollingFrequency; -} - -- (id)init; -- (id)initWithLogFileManager:(id )logFileManager; - -/** - * Log File Rolling: - * - * maximumFileSize: - * The approximate maximum size to allow log files to grow. - * If a log file is larger than this value after a log statement is appended, - * then the log file is rolled. - * - * rollingFrequency - * How often to roll the log file. - * The frequency is given as an NSTimeInterval, which is a double that specifies the interval in seconds. - * Once the log file gets to be this old, it is rolled. - * - * Both the maximumFileSize and the rollingFrequency are used to manage rolling. - * Whichever occurs first will cause the log file to be rolled. - * - * For example: - * The rollingFrequency is 24 hours, - * but the log file surpasses the maximumFileSize after only 20 hours. - * The log file will be rolled at that 20 hour mark. - * A new log file will be created, and the 24 hour timer will be restarted. - * - * You may optionally disable rolling due to filesize by setting maximumFileSize to zero. - * If you do so, rolling is based solely on rollingFrequency. - * - * You may optionally disable rolling due to time by setting rollingFrequency to zero (or any non-positive number). - * If you do so, rolling is based solely on maximumFileSize. - * - * If you disable both maximumFileSize and rollingFrequency, then the log file won't ever be rolled. - * This is strongly discouraged. -**/ -@property (readwrite, assign) unsigned long long maximumFileSize; -@property (readwrite, assign) NSTimeInterval rollingFrequency; - -/** - * The DDLogFileManager instance can be used to retrieve the list of log files, - * and configure the maximum number of archived log files to keep. - * - * @see DDLogFileManager.maximumNumberOfLogFiles -**/ -@property (strong, nonatomic, readonly) id logFileManager; - - -// You can optionally force the current log file to be rolled with this method. - -- (void)rollLogFile; - -// Inherited from DDAbstractLogger - -// - (id )logFormatter; -// - (void)setLogFormatter:(id )formatter; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * DDLogFileInfo is a simple class that provides access to various file attributes. - * It provides good performance as it only fetches the information if requested, - * and it caches the information to prevent duplicate fetches. - * - * It was designed to provide quick snapshots of the current state of log files, - * and to help sort log files in an array. - * - * This class does not monitor the files, or update it's cached attribute values if the file changes on disk. - * This is not what the class was designed for. - * - * If you absolutely must get updated values, - * you can invoke the reset method which will clear the cache. -**/ -@interface DDLogFileInfo : NSObject -{ - __strong NSString *filePath; - __strong NSString *fileName; - - __strong NSDictionary *fileAttributes; - - __strong NSDate *creationDate; - __strong NSDate *modificationDate; - - unsigned long long fileSize; -} - -@property (strong, nonatomic, readonly) NSString *filePath; -@property (strong, nonatomic, readonly) NSString *fileName; - -@property (strong, nonatomic, readonly) NSDictionary *fileAttributes; - -@property (strong, nonatomic, readonly) NSDate *creationDate; -@property (strong, nonatomic, readonly) NSDate *modificationDate; - -@property (nonatomic, readonly) unsigned long long fileSize; - -@property (nonatomic, readonly) NSTimeInterval age; - -@property (nonatomic, readwrite) BOOL isArchived; - -+ (id)logFileWithPath:(NSString *)filePath; - -- (id)initWithFilePath:(NSString *)filePath; - -- (void)reset; -- (void)renameFile:(NSString *)newFileName; - -#if TARGET_IPHONE_SIMULATOR - -// So here's the situation. -// Extended attributes are perfect for what we're trying to do here (marking files as archived). -// This is exactly what extended attributes were designed for. -// -// But Apple screws us over on the simulator. -// Everytime you build-and-go, they copy the application into a new folder on the hard drive, -// and as part of the process they strip extended attributes from our log files. -// Normally, a copy of a file preserves extended attributes. -// So obviously Apple has gone to great lengths to piss us off. -// -// Thus we use a slightly different tactic for marking log files as archived in the simulator. -// That way it "just works" and there's no confusion when testing. -// -// The difference in method names is indicative of the difference in functionality. -// On the simulator we add an attribute by appending a filename extension. -// -// For example: -// log-ABC123.txt -> log-ABC123.archived.txt - -- (BOOL)hasExtensionAttributeWithName:(NSString *)attrName; - -- (void)addExtensionAttributeWithName:(NSString *)attrName; -- (void)removeExtensionAttributeWithName:(NSString *)attrName; - -#else - -// Normal use of extended attributes used everywhere else, -// such as on Macs and on iPhone devices. - -- (BOOL)hasExtendedAttributeWithName:(NSString *)attrName; - -- (void)addExtendedAttributeWithName:(NSString *)attrName; -- (void)removeExtendedAttributeWithName:(NSString *)attrName; - -#endif - -- (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another; -- (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another; - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m b/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m deleted file mode 100644 index ea9cc80..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/DDFileLogger.m +++ /dev/null @@ -1,1380 +0,0 @@ -#import "DDFileLogger.h" - -#import -#import -#import -#import - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted -**/ - -#if ! __has_feature(objc_arc) -#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). -#endif - -// Does ARC support support GCD objects? -// It does if the minimum deployment target is iOS 6+ or Mac OS X 8+ - -#if TARGET_OS_IPHONE - - // Compiling for iOS - - #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 // iOS 6.0 or later - #define NEEDS_DISPATCH_RETAIN_RELEASE 0 - #else // iOS 5.X or earlier - #define NEEDS_DISPATCH_RETAIN_RELEASE 1 - #endif - -#else - - // Compiling for Mac OS X - - #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 // Mac OS X 10.8 or later - #define NEEDS_DISPATCH_RETAIN_RELEASE 0 - #else - #define NEEDS_DISPATCH_RETAIN_RELEASE 1 // Mac OS X 10.7 or earlier - #endif - -#endif - -// We probably shouldn't be using DDLog() statements within the DDLog implementation. -// But we still want to leave our log statements for any future debugging, -// and to allow other developers to trace the implementation (which is a great learning tool). -// -// So we use primitive logging macros around NSLog. -// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog. - -#define LOG_LEVEL 2 - -#define NSLogError(frmt, ...) do{ if(LOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0) -#define NSLogWarn(frmt, ...) do{ if(LOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0) -#define NSLogInfo(frmt, ...) do{ if(LOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0) -#define NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0) - -@interface DDLogFileManagerDefault (PrivateAPI) - -- (void)deleteOldLogFiles; -- (NSString *)defaultLogsDirectory; - -@end - -@interface DDFileLogger (PrivateAPI) - -- (void)rollLogFileNow; -- (void)maybeRollLogFileDueToAge; -- (void)maybeRollLogFileDueToSize; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation DDLogFileManagerDefault - -@synthesize maximumNumberOfLogFiles; - -- (id)init -{ - return [self initWithLogsDirectory:nil]; -} - -- (id)initWithLogsDirectory:(NSString *)aLogsDirectory -{ - if ((self = [super init])) - { - maximumNumberOfLogFiles = DEFAULT_LOG_MAX_NUM_LOG_FILES; - - if (aLogsDirectory) - _logsDirectory = [aLogsDirectory copy]; - else - _logsDirectory = [[self defaultLogsDirectory] copy]; - - NSKeyValueObservingOptions kvoOptions = NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew; - - [self addObserver:self forKeyPath:@"maximumNumberOfLogFiles" options:kvoOptions context:nil]; - - NSLogVerbose(@"DDFileLogManagerDefault: logsDirectory:\n%@", [self logsDirectory]); - NSLogVerbose(@"DDFileLogManagerDefault: sortedLogFileNames:\n%@", [self sortedLogFileNames]); - } - return self; -} - -- (void)dealloc -{ - [self removeObserver:self forKeyPath:@"maximumNumberOfLogFiles"]; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Configuration -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)observeValueForKeyPath:(NSString *)keyPath - ofObject:(id)object - change:(NSDictionary *)change - context:(void *)context -{ - NSNumber *old = [change objectForKey:NSKeyValueChangeOldKey]; - NSNumber *new = [change objectForKey:NSKeyValueChangeNewKey]; - - if ([old isEqual:new]) - { - // No change in value - don't bother with any processing. - return; - } - - if ([keyPath isEqualToString:@"maximumNumberOfLogFiles"]) - { - NSLogInfo(@"DDFileLogManagerDefault: Responding to configuration change: maximumNumberOfLogFiles"); - - dispatch_async([DDLog loggingQueue], ^{ @autoreleasepool { - - [self deleteOldLogFiles]; - }}); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark File Deleting -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Deletes archived log files that exceed the maximumNumberOfLogFiles configuration value. -**/ -- (void)deleteOldLogFiles -{ - NSLogVerbose(@"DDLogFileManagerDefault: deleteOldLogFiles"); - - NSUInteger maxNumLogFiles = self.maximumNumberOfLogFiles; - if (maxNumLogFiles == 0) - { - // Unlimited - don't delete any log files - return; - } - - NSArray *sortedLogFileInfos = [self sortedLogFileInfos]; - - // Do we consider the first file? - // We are only supposed to be deleting archived files. - // In most cases, the first file is likely the log file that is currently being written to. - // So in most cases, we do not want to consider this file for deletion. - - NSUInteger count = [sortedLogFileInfos count]; - BOOL excludeFirstFile = NO; - - if (count > 0) - { - DDLogFileInfo *logFileInfo = [sortedLogFileInfos objectAtIndex:0]; - - if (!logFileInfo.isArchived) - { - excludeFirstFile = YES; - } - } - - NSArray *sortedArchivedLogFileInfos; - if (excludeFirstFile) - { - count--; - sortedArchivedLogFileInfos = [sortedLogFileInfos subarrayWithRange:NSMakeRange(1, count)]; - } - else - { - sortedArchivedLogFileInfos = sortedLogFileInfos; - } - - NSUInteger i; - for (i = maxNumLogFiles; i < count; i++) - { - DDLogFileInfo *logFileInfo = [sortedArchivedLogFileInfos objectAtIndex:i]; - - NSLogInfo(@"DDLogFileManagerDefault: Deleting file: %@", logFileInfo.fileName); - - [[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:nil]; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Log Files -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Returns the path to the default logs directory. - * If the logs directory doesn't exist, this method automatically creates it. -**/ -- (NSString *)defaultLogsDirectory -{ -#if TARGET_OS_IPHONE - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - NSString *baseDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; - NSString *logsDirectory = [baseDir stringByAppendingPathComponent:@"Logs"]; - -#else - NSString *appName = [[NSProcessInfo processInfo] processName]; - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); - NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory(); - NSString *logsDirectory = [[basePath stringByAppendingPathComponent:@"Logs"] stringByAppendingPathComponent:appName]; - -#endif - - return logsDirectory; -} - -- (NSString *)logsDirectory -{ - // We could do this check once, during initalization, and not bother again. - // But this way the code continues to work if the directory gets deleted while the code is running. - - if (![[NSFileManager defaultManager] fileExistsAtPath:_logsDirectory]) - { - NSError *err = nil; - if (![[NSFileManager defaultManager] createDirectoryAtPath:_logsDirectory - withIntermediateDirectories:YES attributes:nil error:&err]) - { - NSLogError(@"DDFileLogManagerDefault: Error creating logsDirectory: %@", err); - } - } - - return _logsDirectory; -} - -- (BOOL)isLogFile:(NSString *)fileName -{ - // A log file has a name like "log-.txt", where is a HEX-string of 6 characters. - // - // For example: log-DFFE99.txt - - BOOL hasProperPrefix = [fileName hasPrefix:@"log-"]; - - BOOL hasProperLength = [fileName length] >= 10; - - - if (hasProperPrefix && hasProperLength) - { - NSCharacterSet *hexSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"]; - - NSString *hex = [fileName substringWithRange:NSMakeRange(4, 6)]; - NSString *nohex = [hex stringByTrimmingCharactersInSet:hexSet]; - - if ([nohex length] == 0) - { - return YES; - } - } - - return NO; -} - -/** - * Returns an array of NSString objects, - * each of which is the filePath to an existing log file on disk. -**/ -- (NSArray *)unsortedLogFilePaths -{ - NSString *logsDirectory = [self logsDirectory]; - NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logsDirectory error:nil]; - - NSMutableArray *unsortedLogFilePaths = [NSMutableArray arrayWithCapacity:[fileNames count]]; - - for (NSString *fileName in fileNames) - { - // Filter out any files that aren't log files. (Just for extra safety) - - if ([self isLogFile:fileName]) - { - NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName]; - - [unsortedLogFilePaths addObject:filePath]; - } - } - - return unsortedLogFilePaths; -} - -/** - * Returns an array of NSString objects, - * each of which is the fileName of an existing log file on disk. -**/ -- (NSArray *)unsortedLogFileNames -{ - NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths]; - - NSMutableArray *unsortedLogFileNames = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]]; - - for (NSString *filePath in unsortedLogFilePaths) - { - [unsortedLogFileNames addObject:[filePath lastPathComponent]]; - } - - return unsortedLogFileNames; -} - -/** - * Returns an array of DDLogFileInfo objects, - * each representing an existing log file on disk, - * and containing important information about the log file such as it's modification date and size. -**/ -- (NSArray *)unsortedLogFileInfos -{ - NSArray *unsortedLogFilePaths = [self unsortedLogFilePaths]; - - NSMutableArray *unsortedLogFileInfos = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]]; - - for (NSString *filePath in unsortedLogFilePaths) - { - DDLogFileInfo *logFileInfo = [[DDLogFileInfo alloc] initWithFilePath:filePath]; - - [unsortedLogFileInfos addObject:logFileInfo]; - } - - return unsortedLogFileInfos; -} - -/** - * Just like the unsortedLogFilePaths method, but sorts the array. - * The items in the array are sorted by modification date. - * The first item in the array will be the most recently modified log file. -**/ -- (NSArray *)sortedLogFilePaths -{ - NSArray *sortedLogFileInfos = [self sortedLogFileInfos]; - - NSMutableArray *sortedLogFilePaths = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]]; - - for (DDLogFileInfo *logFileInfo in sortedLogFileInfos) - { - [sortedLogFilePaths addObject:[logFileInfo filePath]]; - } - - return sortedLogFilePaths; -} - -/** - * Just like the unsortedLogFileNames method, but sorts the array. - * The items in the array are sorted by modification date. - * The first item in the array will be the most recently modified log file. -**/ -- (NSArray *)sortedLogFileNames -{ - NSArray *sortedLogFileInfos = [self sortedLogFileInfos]; - - NSMutableArray *sortedLogFileNames = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]]; - - for (DDLogFileInfo *logFileInfo in sortedLogFileInfos) - { - [sortedLogFileNames addObject:[logFileInfo fileName]]; - } - - return sortedLogFileNames; -} - -/** - * Just like the unsortedLogFileInfos method, but sorts the array. - * The items in the array are sorted by modification date. - * The first item in the array will be the most recently modified log file. -**/ -- (NSArray *)sortedLogFileInfos -{ - return [[self unsortedLogFileInfos] sortedArrayUsingSelector:@selector(reverseCompareByCreationDate:)]; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Creation -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Generates a short UUID suitable for use in the log file's name. - * The result will have six characters, all in the hexadecimal set [0123456789ABCDEF]. -**/ -- (NSString *)generateShortUUID -{ - CFUUIDRef uuid = CFUUIDCreate(NULL); - - CFStringRef fullStr = CFUUIDCreateString(NULL, uuid); - NSString *result = (__bridge_transfer NSString *)CFStringCreateWithSubstring(NULL, fullStr, CFRangeMake(0, 6)); - - CFRelease(fullStr); - CFRelease(uuid); - - return result; -} - -/** - * Generates a new unique log file path, and creates the corresponding log file. -**/ -- (NSString *)createNewLogFile -{ - // Generate a random log file name, and create the file (if there isn't a collision) - - NSString *logsDirectory = [self logsDirectory]; - do - { - NSString *fileName = [NSString stringWithFormat:@"log-%@.txt", [self generateShortUUID]]; - - NSString *filePath = [logsDirectory stringByAppendingPathComponent:fileName]; - - if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) - { - NSLogVerbose(@"DDLogFileManagerDefault: Creating new log file: %@", fileName); - - [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]; - - // Since we just created a new log file, we may need to delete some old log files - [self deleteOldLogFiles]; - - return filePath; - } - - } while(YES); -} - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation DDLogFileFormatterDefault - -- (id)init -{ - return [self initWithDateFormatter:nil]; -} - -- (id)initWithDateFormatter:(NSDateFormatter *)aDateFormatter -{ - if ((self = [super init])) - { - if (aDateFormatter) - { - dateFormatter = aDateFormatter; - } - else - { - dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style - [dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"]; - } - } - return self; -} - -- (NSString *)formatLogMessage:(DDLogMessage *)logMessage -{ - NSString *dateAndTime = [dateFormatter stringFromDate:(logMessage->timestamp)]; - - return [NSString stringWithFormat:@"%@ %@", dateAndTime, logMessage->logMsg]; -} - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation DDFileLogger - -- (id)init -{ - DDLogFileManagerDefault *defaultLogFileManager = [[DDLogFileManagerDefault alloc] init]; - - return [self initWithLogFileManager:defaultLogFileManager]; -} - -- (id)initWithLogFileManager:(id )aLogFileManager -{ - if ((self = [super init])) - { - maximumFileSize = DEFAULT_LOG_MAX_FILE_SIZE; - rollingFrequency = DEFAULT_LOG_ROLLING_FREQUENCY; - - logFileManager = aLogFileManager; - - formatter = [[DDLogFileFormatterDefault alloc] init]; - } - return self; -} - -- (void)dealloc -{ - [currentLogFileHandle synchronizeFile]; - [currentLogFileHandle closeFile]; - - if (rollingTimer) - { - dispatch_source_cancel(rollingTimer); - rollingTimer = NULL; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Properties -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@synthesize logFileManager; - -- (unsigned long long)maximumFileSize -{ - // The design of this method is taken from the DDAbstractLogger implementation. - // For extensive documentation please refer to the DDAbstractLogger implementation. - - // Note: The internal implementation should access the maximumFileSize variable directly, - // but if we forget to do this, then this method should at least work properly. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - return maximumFileSize; - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - __block unsigned long long result; - - dispatch_sync(globalLoggingQueue, ^{ - dispatch_sync(loggerQueue, ^{ - result = maximumFileSize; - }); - }); - - return result; - } -} - -- (void)setMaximumFileSize:(unsigned long long)newMaximumFileSize -{ - // The design of this method is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_block_t block = ^{ @autoreleasepool { - - maximumFileSize = newMaximumFileSize; - [self maybeRollLogFileDueToSize]; - - }}; - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (NSTimeInterval)rollingFrequency -{ - // The design of this method is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - // Note: The internal implementation should access the rollingFrequency variable directly, - // but if we forget to do this, then this method should at least work properly. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - return rollingFrequency; - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - __block NSTimeInterval result; - - dispatch_sync(globalLoggingQueue, ^{ - dispatch_sync(loggerQueue, ^{ - result = rollingFrequency; - }); - }); - - return result; - } -} - -- (void)setRollingFrequency:(NSTimeInterval)newRollingFrequency -{ - // The design of this method is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_block_t block = ^{ @autoreleasepool { - - rollingFrequency = newRollingFrequency; - [self maybeRollLogFileDueToAge]; - - }}; - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark File Rolling -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)scheduleTimerToRollLogFileDueToAge -{ - if (rollingTimer) - { - dispatch_source_cancel(rollingTimer); - rollingTimer = NULL; - } - - if (currentLogFileInfo == nil || rollingFrequency <= 0.0) - { - return; - } - - NSDate *logFileCreationDate = [currentLogFileInfo creationDate]; - - NSTimeInterval ti = [logFileCreationDate timeIntervalSinceReferenceDate]; - ti += rollingFrequency; - - NSDate *logFileRollingDate = [NSDate dateWithTimeIntervalSinceReferenceDate:ti]; - - NSLogVerbose(@"DDFileLogger: scheduleTimerToRollLogFileDueToAge"); - - NSLogVerbose(@"DDFileLogger: logFileCreationDate: %@", logFileCreationDate); - NSLogVerbose(@"DDFileLogger: logFileRollingDate : %@", logFileRollingDate); - - rollingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, loggerQueue); - - dispatch_source_set_event_handler(rollingTimer, ^{ @autoreleasepool { - - [self maybeRollLogFileDueToAge]; - - }}); - - #if NEEDS_DISPATCH_RETAIN_RELEASE - dispatch_source_t theRollingTimer = rollingTimer; - dispatch_source_set_cancel_handler(rollingTimer, ^{ - dispatch_release(theRollingTimer); - }); - #endif - - uint64_t delay = [logFileRollingDate timeIntervalSinceNow] * NSEC_PER_SEC; - dispatch_time_t fireTime = dispatch_time(DISPATCH_TIME_NOW, delay); - - dispatch_source_set_timer(rollingTimer, fireTime, DISPATCH_TIME_FOREVER, 1.0); - dispatch_resume(rollingTimer); -} - -- (void)rollLogFile -{ - // This method is public. - // We need to execute the rolling on our logging thread/queue. - // - // The design of this method is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_block_t block = ^{ @autoreleasepool { - - [self rollLogFileNow]; - }}; - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (void)rollLogFileNow -{ - NSLogVerbose(@"DDFileLogger: rollLogFileNow"); - - - if (currentLogFileHandle == nil) return; - - [currentLogFileHandle synchronizeFile]; - [currentLogFileHandle closeFile]; - currentLogFileHandle = nil; - - currentLogFileInfo.isArchived = YES; - - if ([logFileManager respondsToSelector:@selector(didRollAndArchiveLogFile:)]) - { - [logFileManager didRollAndArchiveLogFile:(currentLogFileInfo.filePath)]; - } - - currentLogFileInfo = nil; - - if (rollingTimer) - { - dispatch_source_cancel(rollingTimer); - rollingTimer = NULL; - } -} - -- (void)maybeRollLogFileDueToAge -{ - if (rollingFrequency > 0.0 && currentLogFileInfo.age >= rollingFrequency) - { - NSLogVerbose(@"DDFileLogger: Rolling log file due to age..."); - - [self rollLogFileNow]; - } - else - { - [self scheduleTimerToRollLogFileDueToAge]; - } -} - -- (void)maybeRollLogFileDueToSize -{ - // This method is called from logMessage. - // Keep it FAST. - - // Note: Use direct access to maximumFileSize variable. - // We specifically wrote our own getter/setter method to allow us to do this (for performance reasons). - - if (maximumFileSize > 0) - { - unsigned long long fileSize = [currentLogFileHandle offsetInFile]; - - if (fileSize >= maximumFileSize) - { - NSLogVerbose(@"DDFileLogger: Rolling log file due to size (%qu)...", fileSize); - - [self rollLogFileNow]; - } - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark File Logging -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Returns the log file that should be used. - * If there is an existing log file that is suitable, - * within the constraints of maximumFileSize and rollingFrequency, then it is returned. - * - * Otherwise a new file is created and returned. -**/ -- (DDLogFileInfo *)currentLogFileInfo -{ - if (currentLogFileInfo == nil) - { - NSArray *sortedLogFileInfos = [logFileManager sortedLogFileInfos]; - - if ([sortedLogFileInfos count] > 0) - { - DDLogFileInfo *mostRecentLogFileInfo = [sortedLogFileInfos objectAtIndex:0]; - - BOOL useExistingLogFile = YES; - BOOL shouldArchiveMostRecent = NO; - - if (mostRecentLogFileInfo.isArchived) - { - useExistingLogFile = NO; - shouldArchiveMostRecent = NO; - } - else if (maximumFileSize > 0 && mostRecentLogFileInfo.fileSize >= maximumFileSize) - { - useExistingLogFile = NO; - shouldArchiveMostRecent = YES; - } - else if (rollingFrequency > 0.0 && mostRecentLogFileInfo.age >= rollingFrequency) - { - useExistingLogFile = NO; - shouldArchiveMostRecent = YES; - } - - if (useExistingLogFile) - { - NSLogVerbose(@"DDFileLogger: Resuming logging with file %@", mostRecentLogFileInfo.fileName); - - currentLogFileInfo = mostRecentLogFileInfo; - } - else - { - if (shouldArchiveMostRecent) - { - mostRecentLogFileInfo.isArchived = YES; - - if ([logFileManager respondsToSelector:@selector(didArchiveLogFile:)]) - { - [logFileManager didArchiveLogFile:(mostRecentLogFileInfo.filePath)]; - } - } - } - } - - if (currentLogFileInfo == nil) - { - NSString *currentLogFilePath = [logFileManager createNewLogFile]; - - currentLogFileInfo = [[DDLogFileInfo alloc] initWithFilePath:currentLogFilePath]; - } - } - - return currentLogFileInfo; -} - -- (NSFileHandle *)currentLogFileHandle -{ - if (currentLogFileHandle == nil) - { - NSString *logFilePath = [[self currentLogFileInfo] filePath]; - - currentLogFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath]; - [currentLogFileHandle seekToEndOfFile]; - - if (currentLogFileHandle) - { - [self scheduleTimerToRollLogFileDueToAge]; - } - } - - return currentLogFileHandle; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark DDLogger Protocol -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)logMessage:(DDLogMessage *)logMessage -{ - NSString *logMsg = logMessage->logMsg; - - if (formatter) - { - logMsg = [formatter formatLogMessage:logMessage]; - } - - if (logMsg) - { - if (![logMsg hasSuffix:@"\n"]) - { - logMsg = [logMsg stringByAppendingString:@"\n"]; - } - - NSData *logData = [logMsg dataUsingEncoding:NSUTF8StringEncoding]; - - [[self currentLogFileHandle] writeData:logData]; - - [self maybeRollLogFileDueToSize]; - } -} - -- (void)willRemoveLogger -{ - // If you override me be sure to invoke [super willRemoveLogger]; - - [self rollLogFileNow]; -} - -- (NSString *)loggerName -{ - return @"cocoa.lumberjack.fileLogger"; -} - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#if TARGET_IPHONE_SIMULATOR - #define XATTR_ARCHIVED_NAME @"archived" -#else - #define XATTR_ARCHIVED_NAME @"lumberjack.log.archived" -#endif - -@implementation DDLogFileInfo - -@synthesize filePath; - -@dynamic fileName; -@dynamic fileAttributes; -@dynamic creationDate; -@dynamic modificationDate; -@dynamic fileSize; -@dynamic age; - -@dynamic isArchived; - - -#pragma mark Lifecycle - -+ (id)logFileWithPath:(NSString *)aFilePath -{ - return [[DDLogFileInfo alloc] initWithFilePath:aFilePath]; -} - -- (id)initWithFilePath:(NSString *)aFilePath -{ - if ((self = [super init])) - { - filePath = [aFilePath copy]; - } - return self; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Standard Info -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (NSDictionary *)fileAttributes -{ - if (fileAttributes == nil) - { - fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; - } - return fileAttributes; -} - -- (NSString *)fileName -{ - if (fileName == nil) - { - fileName = [filePath lastPathComponent]; - } - return fileName; -} - -- (NSDate *)modificationDate -{ - if (modificationDate == nil) - { - modificationDate = [[self fileAttributes] objectForKey:NSFileModificationDate]; - } - - return modificationDate; -} - -- (NSDate *)creationDate -{ - if (creationDate == nil) - { - - #if TARGET_OS_IPHONE - - const char *path = [filePath UTF8String]; - - struct attrlist attrList; - memset(&attrList, 0, sizeof(attrList)); - attrList.bitmapcount = ATTR_BIT_MAP_COUNT; - attrList.commonattr = ATTR_CMN_CRTIME; - - struct { - u_int32_t attrBufferSizeInBytes; - struct timespec crtime; - } attrBuffer; - - int result = getattrlist(path, &attrList, &attrBuffer, sizeof(attrBuffer), 0); - if (result == 0) - { - double seconds = (double)(attrBuffer.crtime.tv_sec); - double nanos = (double)(attrBuffer.crtime.tv_nsec); - - NSTimeInterval ti = seconds + (nanos / 1000000000.0); - - creationDate = [NSDate dateWithTimeIntervalSince1970:ti]; - } - else - { - NSLogError(@"DDLogFileInfo: creationDate(%@): getattrlist result = %i", self.fileName, result); - } - - #else - - creationDate = [[self fileAttributes] objectForKey:NSFileCreationDate]; - - #endif - - } - return creationDate; -} - -- (unsigned long long)fileSize -{ - if (fileSize == 0) - { - fileSize = [[[self fileAttributes] objectForKey:NSFileSize] unsignedLongLongValue]; - } - - return fileSize; -} - -- (NSTimeInterval)age -{ - return [[self creationDate] timeIntervalSinceNow] * -1.0; -} - -- (NSString *)description -{ - return [[NSDictionary dictionaryWithObjectsAndKeys: - self.filePath, @"filePath", - self.fileName, @"fileName", - self.fileAttributes, @"fileAttributes", - self.creationDate, @"creationDate", - self.modificationDate, @"modificationDate", - [NSNumber numberWithUnsignedLongLong:self.fileSize], @"fileSize", - [NSNumber numberWithDouble:self.age], @"age", - [NSNumber numberWithBool:self.isArchived], @"isArchived", - nil] description]; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Archiving -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (BOOL)isArchived -{ - -#if TARGET_IPHONE_SIMULATOR - - // Extended attributes don't work properly on the simulator. - // So we have to use a less attractive alternative. - // See full explanation in the header file. - - return [self hasExtensionAttributeWithName:XATTR_ARCHIVED_NAME]; - -#else - - return [self hasExtendedAttributeWithName:XATTR_ARCHIVED_NAME]; - -#endif -} - -- (void)setIsArchived:(BOOL)flag -{ - -#if TARGET_IPHONE_SIMULATOR - - // Extended attributes don't work properly on the simulator. - // So we have to use a less attractive alternative. - // See full explanation in the header file. - - if (flag) - [self addExtensionAttributeWithName:XATTR_ARCHIVED_NAME]; - else - [self removeExtensionAttributeWithName:XATTR_ARCHIVED_NAME]; - -#else - - if (flag) - [self addExtendedAttributeWithName:XATTR_ARCHIVED_NAME]; - else - [self removeExtendedAttributeWithName:XATTR_ARCHIVED_NAME]; - -#endif -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Changes -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (void)reset -{ - fileName = nil; - fileAttributes = nil; - creationDate = nil; - modificationDate = nil; -} - -- (void)renameFile:(NSString *)newFileName -{ - // This method is only used on the iPhone simulator, where normal extended attributes are broken. - // See full explanation in the header file. - - if (![newFileName isEqualToString:[self fileName]]) - { - NSString *fileDir = [filePath stringByDeletingLastPathComponent]; - - NSString *newFilePath = [fileDir stringByAppendingPathComponent:newFileName]; - - NSLogVerbose(@"DDLogFileInfo: Renaming file: '%@' -> '%@'", self.fileName, newFileName); - - NSError *error = nil; - if (![[NSFileManager defaultManager] moveItemAtPath:filePath toPath:newFilePath error:&error]) - { - NSLogError(@"DDLogFileInfo: Error renaming file (%@): %@", self.fileName, error); - } - - filePath = newFilePath; - [self reset]; - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Attribute Management -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#if TARGET_IPHONE_SIMULATOR - -// Extended attributes don't work properly on the simulator. -// So we have to use a less attractive alternative. -// See full explanation in the header file. - -- (BOOL)hasExtensionAttributeWithName:(NSString *)attrName -{ - // This method is only used on the iPhone simulator, where normal extended attributes are broken. - // See full explanation in the header file. - - // Split the file name into components. - // - // log-ABC123.archived.uploaded.txt - // - // 0. log-ABC123 - // 1. archived - // 2. uploaded - // 3. txt - // - // So we want to search for the attrName in the components (ignoring the first and last array indexes). - - NSArray *components = [[self fileName] componentsSeparatedByString:@"."]; - - // Watch out for file names without an extension - - NSUInteger count = [components count]; - NSUInteger max = (count >= 2) ? count-1 : count; - - NSUInteger i; - for (i = 1; i < max; i++) - { - NSString *attr = [components objectAtIndex:i]; - - if ([attrName isEqualToString:attr]) - { - return YES; - } - } - - return NO; -} - -- (void)addExtensionAttributeWithName:(NSString *)attrName -{ - // This method is only used on the iPhone simulator, where normal extended attributes are broken. - // See full explanation in the header file. - - if ([attrName length] == 0) return; - - // Example: - // attrName = "archived" - // - // "log-ABC123.txt" -> "log-ABC123.archived.txt" - - NSArray *components = [[self fileName] componentsSeparatedByString:@"."]; - - NSUInteger count = [components count]; - - NSUInteger estimatedNewLength = [[self fileName] length] + [attrName length] + 1; - NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength]; - - if (count > 0) - { - [newFileName appendString:[components objectAtIndex:0]]; - } - - NSString *lastExt = @""; - - NSUInteger i; - for (i = 1; i < count; i++) - { - NSString *attr = [components objectAtIndex:i]; - if ([attr length] == 0) - { - continue; - } - - if ([attrName isEqualToString:attr]) - { - // Extension attribute already exists in file name - return; - } - - if ([lastExt length] > 0) - { - [newFileName appendFormat:@".%@", lastExt]; - } - - lastExt = attr; - } - - [newFileName appendFormat:@".%@", attrName]; - - if ([lastExt length] > 0) - { - [newFileName appendFormat:@".%@", lastExt]; - } - - [self renameFile:newFileName]; -} - -- (void)removeExtensionAttributeWithName:(NSString *)attrName -{ - // This method is only used on the iPhone simulator, where normal extended attributes are broken. - // See full explanation in the header file. - - if ([attrName length] == 0) return; - - // Example: - // attrName = "archived" - // - // "log-ABC123.txt" -> "log-ABC123.archived.txt" - - NSArray *components = [[self fileName] componentsSeparatedByString:@"."]; - - NSUInteger count = [components count]; - - NSUInteger estimatedNewLength = [[self fileName] length]; - NSMutableString *newFileName = [NSMutableString stringWithCapacity:estimatedNewLength]; - - if (count > 0) - { - [newFileName appendString:[components objectAtIndex:0]]; - } - - BOOL found = NO; - - NSUInteger i; - for (i = 1; i < count; i++) - { - NSString *attr = [components objectAtIndex:i]; - - if ([attrName isEqualToString:attr]) - { - found = YES; - } - else - { - [newFileName appendFormat:@".%@", attr]; - } - } - - if (found) - { - [self renameFile:newFileName]; - } -} - -#else - -- (BOOL)hasExtendedAttributeWithName:(NSString *)attrName -{ - const char *path = [filePath UTF8String]; - const char *name = [attrName UTF8String]; - - ssize_t result = getxattr(path, name, NULL, 0, 0, 0); - - return (result >= 0); -} - -- (void)addExtendedAttributeWithName:(NSString *)attrName -{ - const char *path = [filePath UTF8String]; - const char *name = [attrName UTF8String]; - - int result = setxattr(path, name, NULL, 0, 0, 0); - - if (result < 0) - { - NSLogError(@"DDLogFileInfo: setxattr(%@, %@): error = %i", attrName, self.fileName, result); - } -} - -- (void)removeExtendedAttributeWithName:(NSString *)attrName -{ - const char *path = [filePath UTF8String]; - const char *name = [attrName UTF8String]; - - int result = removexattr(path, name, 0); - - if (result < 0 && errno != ENOATTR) - { - NSLogError(@"DDLogFileInfo: removexattr(%@, %@): error = %i", attrName, self.fileName, result); - } -} - -#endif - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Comparisons -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (BOOL)isEqual:(id)object -{ - if ([object isKindOfClass:[self class]]) - { - DDLogFileInfo *another = (DDLogFileInfo *)object; - - return [filePath isEqualToString:[another filePath]]; - } - - return NO; -} - -- (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another -{ - NSDate *us = [self creationDate]; - NSDate *them = [another creationDate]; - - NSComparisonResult result = [us compare:them]; - - if (result == NSOrderedAscending) - return NSOrderedDescending; - - if (result == NSOrderedDescending) - return NSOrderedAscending; - - return NSOrderedSame; -} - -- (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another -{ - NSDate *us = [self modificationDate]; - NSDate *them = [another modificationDate]; - - NSComparisonResult result = [us compare:them]; - - if (result == NSOrderedAscending) - return NSOrderedDescending; - - if (result == NSOrderedDescending) - return NSOrderedAscending; - - return NSOrderedSame; -} - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/DDLog.h b/Pods/CocoaLumberjack/Lumberjack/DDLog.h deleted file mode 100755 index 57c2f09..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/DDLog.h +++ /dev/null @@ -1,597 +0,0 @@ -#import - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted - * - * Otherwise, here is a quick refresher. - * There are three steps to using the macros: - * - * Step 1: - * Import the header in your implementation file: - * - * #import "DDLog.h" - * - * Step 2: - * Define your logging level in your implementation file: - * - * // Log levels: off, error, warn, info, verbose - * static const int ddLogLevel = LOG_LEVEL_VERBOSE; - * - * Step 3: - * Replace your NSLog statements with DDLog statements according to the severity of the message. - * - * NSLog(@"Fatal error, no dohickey found!"); -> DDLogError(@"Fatal error, no dohickey found!"); - * - * DDLog works exactly the same as NSLog. - * This means you can pass it multiple variables just like NSLog. -**/ - - -@class DDLogMessage; - -@protocol DDLogger; -@protocol DDLogFormatter; - -/** - * This is the single macro that all other macros below compile into. - * This big multiline macro makes all the other macros easier to read. -**/ - -#define LOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \ - [DDLog log:isAsynchronous \ - level:lvl \ - flag:flg \ - context:ctx \ - file:__FILE__ \ - function:fnct \ - line:__LINE__ \ - tag:atag \ - format:(frmt), ##__VA_ARGS__] - -/** - * Define the Objective-C and C versions of the macro. - * These automatically inject the proper function name for either an objective-c method or c function. - * - * We also define shorthand versions for asynchronous and synchronous logging. -**/ - -#define LOG_OBJC_MACRO(async, lvl, flg, ctx, frmt, ...) \ - LOG_MACRO(async, lvl, flg, ctx, nil, sel_getName(_cmd), frmt, ##__VA_ARGS__) - -#define LOG_C_MACRO(async, lvl, flg, ctx, frmt, ...) \ - LOG_MACRO(async, lvl, flg, ctx, nil, __FUNCTION__, frmt, ##__VA_ARGS__) - -#define SYNC_LOG_OBJC_MACRO(lvl, flg, ctx, frmt, ...) \ - LOG_OBJC_MACRO( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__) - -#define ASYNC_LOG_OBJC_MACRO(lvl, flg, ctx, frmt, ...) \ - LOG_OBJC_MACRO(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__) - -#define SYNC_LOG_C_MACRO(lvl, flg, ctx, frmt, ...) \ - LOG_C_MACRO( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__) - -#define ASYNC_LOG_C_MACRO(lvl, flg, ctx, frmt, ...) \ - LOG_C_MACRO(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__) - -/** - * Define version of the macro that only execute if the logLevel is above the threshold. - * The compiled versions essentially look like this: - * - * if (logFlagForThisLogMsg & ddLogLevel) { execute log message } - * - * As shown further below, Lumberjack actually uses a bitmask as opposed to primitive log levels. - * This allows for a great amount of flexibility and some pretty advanced fine grained logging techniques. - * - * Note that when compiler optimizations are enabled (as they are for your release builds), - * the log messages above your logging threshold will automatically be compiled out. - * - * (If the compiler sees ddLogLevel declared as a constant, the compiler simply checks to see if the 'if' statement - * would execute, and if not it strips it from the binary.) - * - * We also define shorthand versions for asynchronous and synchronous logging. -**/ - -#define LOG_MAYBE(async, lvl, flg, ctx, fnct, frmt, ...) \ - do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, nil, fnct, frmt, ##__VA_ARGS__); } while(0) - -#define LOG_OBJC_MAYBE(async, lvl, flg, ctx, frmt, ...) \ - LOG_MAYBE(async, lvl, flg, ctx, sel_getName(_cmd), frmt, ##__VA_ARGS__) - -#define LOG_C_MAYBE(async, lvl, flg, ctx, frmt, ...) \ - LOG_MAYBE(async, lvl, flg, ctx, __FUNCTION__, frmt, ##__VA_ARGS__) - -#define SYNC_LOG_OBJC_MAYBE(lvl, flg, ctx, frmt, ...) \ - LOG_OBJC_MAYBE( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__) - -#define ASYNC_LOG_OBJC_MAYBE(lvl, flg, ctx, frmt, ...) \ - LOG_OBJC_MAYBE(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__) - -#define SYNC_LOG_C_MAYBE(lvl, flg, ctx, frmt, ...) \ - LOG_C_MAYBE( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__) - -#define ASYNC_LOG_C_MAYBE(lvl, flg, ctx, frmt, ...) \ - LOG_C_MAYBE(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__) - -/** - * Define versions of the macros that also accept tags. - * - * The DDLogMessage object includes a 'tag' ivar that may be used for a variety of purposes. - * It may be used to pass custom information to loggers or formatters. - * Or it may be used by 3rd party extensions to the framework. - * - * Thes macros just make it a little easier to extend logging functionality. -**/ - -#define LOG_OBJC_TAG_MACRO(async, lvl, flg, ctx, tag, frmt, ...) \ - LOG_MACRO(async, lvl, flg, ctx, tag, sel_getName(_cmd), frmt, ##__VA_ARGS__) - -#define LOG_C_TAG_MACRO(async, lvl, flg, ctx, tag, frmt, ...) \ - LOG_MACRO(async, lvl, flg, ctx, tag, __FUNCTION__, frmt, ##__VA_ARGS__) - -#define LOG_TAG_MAYBE(async, lvl, flg, ctx, tag, fnct, frmt, ...) \ - do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0) - -#define LOG_OBJC_TAG_MAYBE(async, lvl, flg, ctx, tag, frmt, ...) \ - LOG_TAG_MAYBE(async, lvl, flg, ctx, tag, sel_getName(_cmd), frmt, ##__VA_ARGS__) - -#define LOG_C_TAG_MAYBE(async, lvl, flg, ctx, tag, frmt, ...) \ - LOG_TAG_MAYBE(async, lvl, flg, ctx, tag, __FUNCTION__, frmt, ##__VA_ARGS__) - -/** - * Define the standard options. - * - * We default to only 4 levels because it makes it easier for beginners - * to make the transition to a logging framework. - * - * More advanced users may choose to completely customize the levels (and level names) to suite their needs. - * For more information on this see the "Custom Log Levels" page: - * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomLogLevels - * - * Advanced users may also notice that we're using a bitmask. - * This is to allow for custom fine grained logging: - * https://github.com/robbiehanson/CocoaLumberjack/wiki/FineGrainedLogging - * - * -- Flags -- - * - * Typically you will use the LOG_LEVELS (see below), but the flags may be used directly in certain situations. - * For example, say you have a lot of warning log messages, and you wanted to disable them. - * However, you still needed to see your error and info log messages. - * You could accomplish that with the following: - * - * static const int ddLogLevel = LOG_FLAG_ERROR | LOG_FLAG_INFO; - * - * Flags may also be consulted when writing custom log formatters, - * as the DDLogMessage class captures the individual flag that caused the log message to fire. - * - * -- Levels -- - * - * Log levels are simply the proper bitmask of the flags. - * - * -- Booleans -- - * - * The booleans may be used when your logging code involves more than one line. - * For example: - * - * if (LOG_VERBOSE) { - * for (id sprocket in sprockets) - * DDLogVerbose(@"sprocket: %@", [sprocket description]) - * } - * - * -- Async -- - * - * Defines the default asynchronous options. - * The default philosophy for asynchronous logging is very simple: - * - * Log messages with errors should be executed synchronously. - * After all, an error just occurred. The application could be unstable. - * - * All other log messages, such as debug output, are executed asynchronously. - * After all, if it wasn't an error, then it was just informational output, - * or something the application was easily able to recover from. - * - * -- Changes -- - * - * You are strongly discouraged from modifying this file. - * If you do, you make it more difficult on yourself to merge future bug fixes and improvements from the project. - * Instead, create your own MyLogging.h or ApplicationNameLogging.h or CompanyLogging.h - * - * For an example of customizing your logging experience, see the "Custom Log Levels" page: - * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomLogLevels -**/ - -#define LOG_FLAG_ERROR (1 << 0) // 0...0001 -#define LOG_FLAG_WARN (1 << 1) // 0...0010 -#define LOG_FLAG_INFO (1 << 2) // 0...0100 -#define LOG_FLAG_VERBOSE (1 << 3) // 0...1000 - -#define LOG_LEVEL_OFF 0 -#define LOG_LEVEL_ERROR (LOG_FLAG_ERROR) // 0...0001 -#define LOG_LEVEL_WARN (LOG_FLAG_ERROR | LOG_FLAG_WARN) // 0...0011 -#define LOG_LEVEL_INFO (LOG_FLAG_ERROR | LOG_FLAG_WARN | LOG_FLAG_INFO) // 0...0111 -#define LOG_LEVEL_VERBOSE (LOG_FLAG_ERROR | LOG_FLAG_WARN | LOG_FLAG_INFO | LOG_FLAG_VERBOSE) // 0...1111 - -#define LOG_ERROR (ddLogLevel & LOG_FLAG_ERROR) -#define LOG_WARN (ddLogLevel & LOG_FLAG_WARN) -#define LOG_INFO (ddLogLevel & LOG_FLAG_INFO) -#define LOG_VERBOSE (ddLogLevel & LOG_FLAG_VERBOSE) - -#define LOG_ASYNC_ENABLED YES - -#define LOG_ASYNC_ERROR ( NO && LOG_ASYNC_ENABLED) -#define LOG_ASYNC_WARN (YES && LOG_ASYNC_ENABLED) -#define LOG_ASYNC_INFO (YES && LOG_ASYNC_ENABLED) -#define LOG_ASYNC_VERBOSE (YES && LOG_ASYNC_ENABLED) - -#define DDLogError(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_ERROR, ddLogLevel, LOG_FLAG_ERROR, 0, frmt, ##__VA_ARGS__) -#define DDLogWarn(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_WARN, ddLogLevel, LOG_FLAG_WARN, 0, frmt, ##__VA_ARGS__) -#define DDLogInfo(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_INFO, ddLogLevel, LOG_FLAG_INFO, 0, frmt, ##__VA_ARGS__) -#define DDLogVerbose(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_VERBOSE, ddLogLevel, LOG_FLAG_VERBOSE, 0, frmt, ##__VA_ARGS__) - -#define DDLogCError(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_ERROR, ddLogLevel, LOG_FLAG_ERROR, 0, frmt, ##__VA_ARGS__) -#define DDLogCWarn(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_WARN, ddLogLevel, LOG_FLAG_WARN, 0, frmt, ##__VA_ARGS__) -#define DDLogCInfo(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_INFO, ddLogLevel, LOG_FLAG_INFO, 0, frmt, ##__VA_ARGS__) -#define DDLogCVerbose(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_VERBOSE, ddLogLevel, LOG_FLAG_VERBOSE, 0, frmt, ##__VA_ARGS__) - -/** - * The THIS_FILE macro gives you an NSString of the file name. - * For simplicity and clarity, the file name does not include the full path or file extension. - * - * For example: DDLogWarn(@"%@: Unable to find thingy", THIS_FILE) -> @"MyViewController: Unable to find thingy" -**/ - -NSString *DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy); - -#define THIS_FILE (DDExtractFileNameWithoutExtension(__FILE__, NO)) - -/** - * The THIS_METHOD macro gives you the name of the current objective-c method. - * - * For example: DDLogWarn(@"%@ - Requires non-nil strings") -> @"setMake:model: requires non-nil strings" - * - * Note: This does NOT work in straight C functions (non objective-c). - * Instead you should use the predefined __FUNCTION__ macro. -**/ - -#define THIS_METHOD NSStringFromSelector(_cmd) - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@interface DDLog : NSObject - -/** - * Provides access to the underlying logging queue. - * This may be helpful to Logger classes for things like thread synchronization. -**/ - -+ (dispatch_queue_t)loggingQueue; - -/** - * Logging Primitive. - * - * This method is used by the macros above. - * It is suggested you stick with the macros as they're easier to use. -**/ - -+ (void)log:(BOOL)synchronous - level:(int)level - flag:(int)flag - context:(int)context - file:(const char *)file - function:(const char *)function - line:(int)line - tag:(id)tag - format:(NSString *)format, ... __attribute__ ((format (__NSString__, 9, 10))); - -/** - * Logging Primitive. - * - * This method can be used if you have a prepared va_list. -**/ - -+ (void)log:(BOOL)asynchronous - level:(int)level - flag:(int)flag - context:(int)context - file:(const char *)file - function:(const char *)function - line:(int)line - tag:(id)tag - format:(NSString *)format - args:(va_list)argList; - - -/** - * Since logging can be asynchronous, there may be times when you want to flush the logs. - * The framework invokes this automatically when the application quits. -**/ - -+ (void)flushLog; - -/** - * Loggers - * - * If you want your log statements to go somewhere, - * you should create and add a logger. -**/ - -+ (void)addLogger:(id )logger; -+ (void)removeLogger:(id )logger; - -+ (void)removeAllLoggers; - -/** - * Registered Dynamic Logging - * - * These methods allow you to obtain a list of classes that are using registered dynamic logging, - * and also provides methods to get and set their log level during run time. -**/ - -+ (NSArray *)registeredClasses; -+ (NSArray *)registeredClassNames; - -+ (int)logLevelForClass:(Class)aClass; -+ (int)logLevelForClassWithName:(NSString *)aClassName; - -+ (void)setLogLevel:(int)logLevel forClass:(Class)aClass; -+ (void)setLogLevel:(int)logLevel forClassWithName:(NSString *)aClassName; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@protocol DDLogger -@required - -- (void)logMessage:(DDLogMessage *)logMessage; - -/** - * Formatters may optionally be added to any logger. - * - * If no formatter is set, the logger simply logs the message as it is given in logMessage, - * or it may use its own built in formatting style. -**/ -- (id )logFormatter; -- (void)setLogFormatter:(id )formatter; - -@optional - -/** - * Since logging is asynchronous, adding and removing loggers is also asynchronous. - * In other words, the loggers are added and removed at appropriate times with regards to log messages. - * - * - Loggers will not receive log messages that were executed prior to when they were added. - * - Loggers will not receive log messages that were executed after they were removed. - * - * These methods are executed in the logging thread/queue. - * This is the same thread/queue that will execute every logMessage: invocation. - * Loggers may use these methods for thread synchronization or other setup/teardown tasks. -**/ -- (void)didAddLogger; -- (void)willRemoveLogger; - -/** - * Some loggers may buffer IO for optimization purposes. - * For example, a database logger may only save occasionaly as the disk IO is slow. - * In such loggers, this method should be implemented to flush any pending IO. - * - * This allows invocations of DDLog's flushLog method to be propogated to loggers that need it. - * - * Note that DDLog's flushLog method is invoked automatically when the application quits, - * and it may be also invoked manually by the developer prior to application crashes, or other such reasons. -**/ -- (void)flush; - -/** - * Each logger is executed concurrently with respect to the other loggers. - * Thus, a dedicated dispatch queue is used for each logger. - * Logger implementations may optionally choose to provide their own dispatch queue. -**/ -- (dispatch_queue_t)loggerQueue; - -/** - * If the logger implementation does not choose to provide its own queue, - * one will automatically be created for it. - * The created queue will receive its name from this method. - * This may be helpful for debugging or profiling reasons. -**/ -- (NSString *)loggerName; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@protocol DDLogFormatter -@required - -/** - * Formatters may optionally be added to any logger. - * This allows for increased flexibility in the logging environment. - * For example, log messages for log files may be formatted differently than log messages for the console. - * - * For more information about formatters, see the "Custom Formatters" page: - * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters - * - * The formatter may also optionally filter the log message by returning nil, - * in which case the logger will not log the message. -**/ -- (NSString *)formatLogMessage:(DDLogMessage *)logMessage; - -@optional - -/** - * A single formatter instance can be added to multiple loggers. - * These methods provides hooks to notify the formatter of when it's added/removed. - * - * This is primarily for thread-safety. - * If a formatter is explicitly not thread-safe, it may wish to throw an exception if added to multiple loggers. - * Or if a formatter has potentially thread-unsafe code (e.g. NSDateFormatter), - * it could possibly use these hooks to switch to thread-safe versions of the code. -**/ -- (void)didAddToLogger:(id )logger; -- (void)willRemoveFromLogger:(id )logger; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@protocol DDRegisteredDynamicLogging - -/** - * Implement these methods to allow a file's log level to be managed from a central location. - * - * This is useful if you'd like to be able to change log levels for various parts - * of your code from within the running application. - * - * Imagine pulling up the settings for your application, - * and being able to configure the logging level on a per file basis. - * - * The implementation can be very straight-forward: - * - * + (int)ddLogLevel - * { - * return ddLogLevel; - * } - * - * + (void)ddSetLogLevel:(int)logLevel - * { - * ddLogLevel = logLevel; - * } -**/ - -+ (int)ddLogLevel; -+ (void)ddSetLogLevel:(int)logLevel; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * The DDLogMessage class encapsulates information about the log message. - * If you write custom loggers or formatters, you will be dealing with objects of this class. -**/ - -enum { - DDLogMessageCopyFile = 1 << 0, - DDLogMessageCopyFunction = 1 << 1, -}; -typedef int DDLogMessageOptions; - -@interface DDLogMessage : NSObject -{ - -// The public variables below can be accessed directly (for speed). -// For example: logMessage->logLevel - -@public - int logLevel; - int logFlag; - int logContext; - NSString *logMsg; - NSDate *timestamp; - char *file; - char *function; - int lineNumber; - mach_port_t machThreadID; - char *queueLabel; - NSString *threadName; - - // For 3rd party extensions to the framework, where flags and contexts aren't enough. - id tag; - - // For 3rd party extensions that manually create DDLogMessage instances. - DDLogMessageOptions options; -} - -/** - * Standard init method for a log message object. - * Used by the logging primitives. (And the macros use the logging primitives.) - * - * If you find need to manually create logMessage objects, there is one thing you should be aware of: - * - * If no flags are passed, the method expects the file and function parameters to be string literals. - * That is, it expects the given strings to exist for the duration of the object's lifetime, - * and it expects the given strings to be immutable. - * In other words, it does not copy these strings, it simply points to them. - * This is due to the fact that __FILE__ and __FUNCTION__ are usually used to specify these parameters, - * so it makes sense to optimize and skip the unnecessary allocations. - * However, if you need them to be copied you may use the options parameter to specify this. - * Options is a bitmask which supports DDLogMessageCopyFile and DDLogMessageCopyFunction. -**/ -- (id)initWithLogMsg:(NSString *)logMsg - level:(int)logLevel - flag:(int)logFlag - context:(int)logContext - file:(const char *)file - function:(const char *)function - line:(int)line - tag:(id)tag - options:(DDLogMessageOptions)optionsMask; - -/** - * Returns the threadID as it appears in NSLog. - * That is, it is a hexadecimal value which is calculated from the machThreadID. -**/ -- (NSString *)threadID; - -/** - * Convenience property to get just the file name, as the file variable is generally the full file path. - * This method does not include the file extension, which is generally unwanted for logging purposes. -**/ -- (NSString *)fileName; - -/** - * Returns the function variable in NSString form. -**/ -- (NSString *)methodName; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * The DDLogger protocol specifies that an optional formatter can be added to a logger. - * Most (but not all) loggers will want to support formatters. - * - * However, writting getters and setters in a thread safe manner, - * while still maintaining maximum speed for the logging process, is a difficult task. - * - * To do it right, the implementation of the getter/setter has strict requiremenets: - * - Must NOT require the logMessage method to acquire a lock. - * - Must NOT require the logMessage method to access an atomic property (also a lock of sorts). - * - * To simplify things, an abstract logger is provided that implements the getter and setter. - * - * Logger implementations may simply extend this class, - * and they can ACCESS THE FORMATTER VARIABLE DIRECTLY from within their logMessage method! -**/ - -@interface DDAbstractLogger : NSObject -{ - id formatter; - - dispatch_queue_t loggerQueue; -} - -- (id )logFormatter; -- (void)setLogFormatter:(id )formatter; - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/DDLog.m b/Pods/CocoaLumberjack/Lumberjack/DDLog.m deleted file mode 100755 index 7d75d81..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/DDLog.m +++ /dev/null @@ -1,1067 +0,0 @@ -#import "DDLog.h" - -#import -#import -#import -#import -#import - - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted - * -**/ - -#if ! __has_feature(objc_arc) -#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). -#endif - -// Does ARC support support GCD objects? -// It does if the minimum deployment target is iOS 6+ or Mac OS X 8+ - -#if TARGET_OS_IPHONE - - // Compiling for iOS - - #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 // iOS 6.0 or later - #define NEEDS_DISPATCH_RETAIN_RELEASE 0 - #else // iOS 5.X or earlier - #define NEEDS_DISPATCH_RETAIN_RELEASE 1 - #endif - -#else - - // Compiling for Mac OS X - - #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 // Mac OS X 10.8 or later - #define NEEDS_DISPATCH_RETAIN_RELEASE 0 - #else - #define NEEDS_DISPATCH_RETAIN_RELEASE 1 // Mac OS X 10.7 or earlier - #endif - -#endif - -// We probably shouldn't be using DDLog() statements within the DDLog implementation. -// But we still want to leave our log statements for any future debugging, -// and to allow other developers to trace the implementation (which is a great learning tool). -// -// So we use a primitive logging macro around NSLog. -// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog. - -#define DD_DEBUG NO - -#define NSLogDebug(frmt, ...) do{ if(DD_DEBUG) NSLog((frmt), ##__VA_ARGS__); } while(0) - -// Specifies the maximum queue size of the logging thread. -// -// Since most logging is asynchronous, its possible for rogue threads to flood the logging queue. -// That is, to issue an abundance of log statements faster than the logging thread can keepup. -// Typically such a scenario occurs when log statements are added haphazardly within large loops, -// but may also be possible if relatively slow loggers are being used. -// -// This property caps the queue size at a given number of outstanding log statements. -// If a thread attempts to issue a log statement when the queue is already maxed out, -// the issuing thread will block until the queue size drops below the max again. - -#define LOG_MAX_QUEUE_SIZE 1000 // Should not exceed INT32_MAX - - -@interface DDLoggerNode : NSObject { -@public - id logger; - dispatch_queue_t loggerQueue; -} - -+ (DDLoggerNode *)nodeWithLogger:(id )logger loggerQueue:(dispatch_queue_t)loggerQueue; - -@end - - -@interface DDLog (PrivateAPI) - -+ (void)lt_addLogger:(id )logger; -+ (void)lt_removeLogger:(id )logger; -+ (void)lt_removeAllLoggers; -+ (void)lt_log:(DDLogMessage *)logMessage; -+ (void)lt_flush; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation DDLog - -// An array used to manage all the individual loggers. -// The array is only modified on the loggingQueue/loggingThread. -static NSMutableArray *loggers; - -// All logging statements are added to the same queue to ensure FIFO operation. -static dispatch_queue_t loggingQueue; - -// Individual loggers are executed concurrently per log statement. -// Each logger has it's own associated queue, and a dispatch group is used for synchrnoization. -static dispatch_group_t loggingGroup; - -// In order to prevent to queue from growing infinitely large, -// a maximum size is enforced (LOG_MAX_QUEUE_SIZE). -static dispatch_semaphore_t queueSemaphore; - -// Minor optimization for uniprocessor machines -static unsigned int numProcessors; - -/** - * The runtime sends initialize to each class in a program exactly one time just before the class, - * or any class that inherits from it, is sent its first message from within the program. (Thus the - * method may never be invoked if the class is not used.) The runtime sends the initialize message to - * classes in a thread-safe manner. Superclasses receive this message before their subclasses. - * - * This method may also be called directly (assumably by accident), hence the safety mechanism. -**/ -+ (void)initialize -{ - static BOOL initialized = NO; - if (!initialized) - { - initialized = YES; - - loggers = [[NSMutableArray alloc] initWithCapacity:4]; - - NSLogDebug(@"DDLog: Using grand central dispatch"); - - loggingQueue = dispatch_queue_create("cocoa.lumberjack", NULL); - loggingGroup = dispatch_group_create(); - - queueSemaphore = dispatch_semaphore_create(LOG_MAX_QUEUE_SIZE); - - // Figure out how many processors are available. - // This may be used later for an optimization on uniprocessor machines. - - host_basic_info_data_t hostInfo; - mach_msg_type_number_t infoCount; - - infoCount = HOST_BASIC_INFO_COUNT; - host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); - - unsigned int result = (unsigned int)(hostInfo.max_cpus); - unsigned int one = (unsigned int)(1); - - numProcessors = MAX(result, one); - - NSLogDebug(@"DDLog: numProcessors = %u", numProcessors); - - - #if TARGET_OS_IPHONE - NSString *notificationName = @"UIApplicationWillTerminateNotification"; - #else - NSString *notificationName = @"NSApplicationWillTerminateNotification"; - #endif - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationWillTerminate:) - name:notificationName - object:nil]; - } -} - -/** - * Provides access to the logging queue. -**/ -+ (dispatch_queue_t)loggingQueue -{ - return loggingQueue; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Notifications -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -+ (void)applicationWillTerminate:(NSNotification *)notification -{ - [self flushLog]; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Logger Management -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -+ (void)addLogger:(id )logger -{ - if (logger == nil) return; - - dispatch_async(loggingQueue, ^{ @autoreleasepool { - - [self lt_addLogger:logger]; - }}); -} - -+ (void)removeLogger:(id )logger -{ - if (logger == nil) return; - - dispatch_async(loggingQueue, ^{ @autoreleasepool { - - [self lt_removeLogger:logger]; - }}); -} - -+ (void)removeAllLoggers -{ - dispatch_async(loggingQueue, ^{ @autoreleasepool { - - [self lt_removeAllLoggers]; - }}); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Master Logging -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -+ (void)queueLogMessage:(DDLogMessage *)logMessage asynchronously:(BOOL)asyncFlag -{ - // We have a tricky situation here... - // - // In the common case, when the queueSize is below the maximumQueueSize, - // we want to simply enqueue the logMessage. And we want to do this as fast as possible, - // which means we don't want to block and we don't want to use any locks. - // - // However, if the queueSize gets too big, we want to block. - // But we have very strict requirements as to when we block, and how long we block. - // - // The following example should help illustrate our requirements: - // - // Imagine that the maximum queue size is configured to be 5, - // and that there are already 5 log messages queued. - // Let us call these 5 queued log messages A, B, C, D, and E. (A is next to be executed) - // - // Now if our thread issues a log statement (let us call the log message F), - // it should block before the message is added to the queue. - // Furthermore, it should be unblocked immediately after A has been unqueued. - // - // The requirements are strict in this manner so that we block only as long as necessary, - // and so that blocked threads are unblocked in the order in which they were blocked. - // - // Returning to our previous example, let us assume that log messages A through E are still queued. - // Our aforementioned thread is blocked attempting to queue log message F. - // Now assume we have another separate thread that attempts to issue log message G. - // It should block until log messages A and B have been unqueued. - - - // We are using a counting semaphore provided by GCD. - // The semaphore is initialized with our LOG_MAX_QUEUE_SIZE value. - // Everytime we want to queue a log message we decrement this value. - // If the resulting value is less than zero, - // the semaphore function waits in FIFO order for a signal to occur before returning. - // - // A dispatch semaphore is an efficient implementation of a traditional counting semaphore. - // Dispatch semaphores call down to the kernel only when the calling thread needs to be blocked. - // If the calling semaphore does not need to block, no kernel call is made. - - dispatch_semaphore_wait(queueSemaphore, DISPATCH_TIME_FOREVER); - - // We've now sure we won't overflow the queue. - // It is time to queue our log message. - - dispatch_block_t logBlock = ^{ @autoreleasepool { - - [self lt_log:logMessage]; - }}; - - if (asyncFlag) - dispatch_async(loggingQueue, logBlock); - else - dispatch_sync(loggingQueue, logBlock); -} - -+ (void)log:(BOOL)asynchronous - level:(int)level - flag:(int)flag - context:(int)context - file:(const char *)file - function:(const char *)function - line:(int)line - tag:(id)tag - format:(NSString *)format, ... -{ - va_list args; - if (format) - { - va_start(args, format); - - NSString *logMsg = [[NSString alloc] initWithFormat:format arguments:args]; - DDLogMessage *logMessage = [[DDLogMessage alloc] initWithLogMsg:logMsg - level:level - flag:flag - context:context - file:file - function:function - line:line - tag:tag - options:0]; - - [self queueLogMessage:logMessage asynchronously:asynchronous]; - - va_end(args); - } -} - -+ (void)log:(BOOL)asynchronous - level:(int)level - flag:(int)flag - context:(int)context - file:(const char *)file - function:(const char *)function - line:(int)line - tag:(id)tag - format:(NSString *)format - args:(va_list)args -{ - if (format) - { - NSString *logMsg = [[NSString alloc] initWithFormat:format arguments:args]; - DDLogMessage *logMessage = [[DDLogMessage alloc] initWithLogMsg:logMsg - level:level - flag:flag - context:context - file:file - function:function - line:line - tag:tag - options:0]; - - [self queueLogMessage:logMessage asynchronously:asynchronous]; - } -} - -+ (void)flushLog -{ - dispatch_sync(loggingQueue, ^{ @autoreleasepool { - - [self lt_flush]; - }}); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Registered Dynamic Logging -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -+ (BOOL)isRegisteredClass:(Class)class -{ - SEL getterSel = @selector(ddLogLevel); - SEL setterSel = @selector(ddSetLogLevel:); - -#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR - - // Issue #6 (GoogleCode) - Crashes on iOS 4.2.1 and iPhone 4 - // - // Crash caused by class_getClassMethod(2). - // - // "It's a bug with UIAccessibilitySafeCategory__NSObject so it didn't pop up until - // users had VoiceOver enabled [...]. I was able to work around it by searching the - // result of class_copyMethodList() instead of calling class_getClassMethod()" - - BOOL result = NO; - - unsigned int methodCount, i; - Method *methodList = class_copyMethodList(object_getClass(class), &methodCount); - - if (methodList != NULL) - { - BOOL getterFound = NO; - BOOL setterFound = NO; - - for (i = 0; i < methodCount; ++i) - { - SEL currentSel = method_getName(methodList[i]); - - if (currentSel == getterSel) - { - getterFound = YES; - } - else if (currentSel == setterSel) - { - setterFound = YES; - } - - if (getterFound && setterFound) - { - result = YES; - break; - } - } - - free(methodList); - } - - return result; - -#else - - // Issue #24 (GitHub) - Crashing in in ARC+Simulator - // - // The method +[DDLog isRegisteredClass] will crash a project when using it with ARC + Simulator. - // For running in the Simulator, it needs to execute the non-iOS code. - - Method getter = class_getClassMethod(class, getterSel); - Method setter = class_getClassMethod(class, setterSel); - - if ((getter != NULL) && (setter != NULL)) - { - return YES; - } - - return NO; - -#endif -} - -+ (NSArray *)registeredClasses -{ - int numClasses, i; - - // We're going to get the list of all registered classes. - // The Objective-C runtime library automatically registers all the classes defined in your source code. - // - // To do this we use the following method (documented in the Objective-C Runtime Reference): - // - // int objc_getClassList(Class *buffer, int bufferLen) - // - // We can pass (NULL, 0) to obtain the total number of - // registered class definitions without actually retrieving any class definitions. - // This allows us to allocate the minimum amount of memory needed for the application. - - numClasses = objc_getClassList(NULL, 0); - - // The numClasses method now tells us how many classes we have. - // So we can allocate our buffer, and get pointers to all the class definitions. - - Class *classes = (Class *)malloc(sizeof(Class) * numClasses); - - numClasses = objc_getClassList(classes, numClasses); - - // We can now loop through the classes, and test each one to see if it is a DDLogging class. - - NSMutableArray *result = [NSMutableArray arrayWithCapacity:numClasses]; - - for (i = 0; i < numClasses; i++) - { - Class class = classes[i]; - - if ([self isRegisteredClass:class]) - { - [result addObject:class]; - } - } - - free(classes); - - return result; -} - -+ (NSArray *)registeredClassNames -{ - NSArray *registeredClasses = [self registeredClasses]; - NSMutableArray *result = [NSMutableArray arrayWithCapacity:[registeredClasses count]]; - - for (Class class in registeredClasses) - { - [result addObject:NSStringFromClass(class)]; - } - - return result; -} - -+ (int)logLevelForClass:(Class)aClass -{ - if ([self isRegisteredClass:aClass]) - { - return [aClass ddLogLevel]; - } - - return -1; -} - -+ (int)logLevelForClassWithName:(NSString *)aClassName -{ - Class aClass = NSClassFromString(aClassName); - - return [self logLevelForClass:aClass]; -} - -+ (void)setLogLevel:(int)logLevel forClass:(Class)aClass -{ - if ([self isRegisteredClass:aClass]) - { - [aClass ddSetLogLevel:logLevel]; - } -} - -+ (void)setLogLevel:(int)logLevel forClassWithName:(NSString *)aClassName -{ - Class aClass = NSClassFromString(aClassName); - - [self setLogLevel:logLevel forClass:aClass]; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Logging Thread -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * This method should only be run on the logging thread/queue. -**/ -+ (void)lt_addLogger:(id )logger -{ - // Add to loggers array. - // Need to create loggerQueue if loggerNode doesn't provide one. - - dispatch_queue_t loggerQueue = NULL; - - if ([logger respondsToSelector:@selector(loggerQueue)]) - { - // Logger may be providing its own queue - - loggerQueue = [logger loggerQueue]; - } - - if (loggerQueue == nil) - { - // Automatically create queue for the logger. - // Use the logger name as the queue name if possible. - - const char *loggerQueueName = NULL; - if ([logger respondsToSelector:@selector(loggerName)]) - { - loggerQueueName = [[logger loggerName] UTF8String]; - } - - loggerQueue = dispatch_queue_create(loggerQueueName, NULL); - } - - DDLoggerNode *loggerNode = [DDLoggerNode nodeWithLogger:logger loggerQueue:loggerQueue]; - [loggers addObject:loggerNode]; - - if ([logger respondsToSelector:@selector(didAddLogger)]) - { - dispatch_async(loggerNode->loggerQueue, ^{ @autoreleasepool { - - [logger didAddLogger]; - }}); - } -} - -/** - * This method should only be run on the logging thread/queue. -**/ -+ (void)lt_removeLogger:(id )logger -{ - // Find associated loggerNode in list of added loggers - - DDLoggerNode *loggerNode = nil; - - for (DDLoggerNode *node in loggers) - { - if (node->logger == logger) - { - loggerNode = node; - break; - } - } - - if (loggerNode == nil) - { - NSLogDebug(@"DDLog: Request to remove logger which wasn't added"); - return; - } - - // Notify logger - - if ([logger respondsToSelector:@selector(willRemoveLogger)]) - { - dispatch_async(loggerNode->loggerQueue, ^{ @autoreleasepool { - - [logger willRemoveLogger]; - }}); - } - - // Remove from loggers array - - [loggers removeObject:loggerNode]; -} - -/** - * This method should only be run on the logging thread/queue. -**/ -+ (void)lt_removeAllLoggers -{ - // Notify all loggers - - for (DDLoggerNode *loggerNode in loggers) - { - if ([loggerNode->logger respondsToSelector:@selector(willRemoveLogger)]) - { - dispatch_async(loggerNode->loggerQueue, ^{ @autoreleasepool { - - [loggerNode->logger willRemoveLogger]; - }}); - } - } - - // Remove all loggers from array - - [loggers removeAllObjects]; -} - -/** - * This method should only be run on the logging thread/queue. -**/ -+ (void)lt_log:(DDLogMessage *)logMessage -{ - // Execute the given log message on each of our loggers. - - if (numProcessors > 1) - { - // Execute each logger concurrently, each within its own queue. - // All blocks are added to same group. - // After each block has been queued, wait on group. - // - // The waiting ensures that a slow logger doesn't end up with a large queue of pending log messages. - // This would defeat the purpose of the efforts we made earlier to restrict the max queue size. - - for (DDLoggerNode *loggerNode in loggers) - { - dispatch_group_async(loggingGroup, loggerNode->loggerQueue, ^{ @autoreleasepool { - - [loggerNode->logger logMessage:logMessage]; - - }}); - } - - dispatch_group_wait(loggingGroup, DISPATCH_TIME_FOREVER); - } - else - { - // Execute each logger serialy, each within its own queue. - - for (DDLoggerNode *loggerNode in loggers) - { - dispatch_sync(loggerNode->loggerQueue, ^{ @autoreleasepool { - - [loggerNode->logger logMessage:logMessage]; - - }}); - } - } - - // If our queue got too big, there may be blocked threads waiting to add log messages to the queue. - // Since we've now dequeued an item from the log, we may need to unblock the next thread. - - // We are using a counting semaphore provided by GCD. - // The semaphore is initialized with our LOG_MAX_QUEUE_SIZE value. - // When a log message is queued this value is decremented. - // When a log message is dequeued this value is incremented. - // If the value ever drops below zero, - // the queueing thread blocks and waits in FIFO order for us to signal it. - // - // A dispatch semaphore is an efficient implementation of a traditional counting semaphore. - // Dispatch semaphores call down to the kernel only when the calling thread needs to be blocked. - // If the calling semaphore does not need to block, no kernel call is made. - - dispatch_semaphore_signal(queueSemaphore); -} - -/** - * This method should only be run on the background logging thread. -**/ -+ (void)lt_flush -{ - // All log statements issued before the flush method was invoked have now been executed. - // - // Now we need to propogate the flush request to any loggers that implement the flush method. - // This is designed for loggers that buffer IO. - - for (DDLoggerNode *loggerNode in loggers) - { - if ([loggerNode->logger respondsToSelector:@selector(flush)]) - { - dispatch_group_async(loggingGroup, loggerNode->loggerQueue, ^{ @autoreleasepool { - - [loggerNode->logger flush]; - - }}); - } - } - - dispatch_group_wait(loggingGroup, DISPATCH_TIME_FOREVER); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Utilities -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -NSString *DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy) -{ - if (filePath == NULL) return nil; - - char *lastSlash = NULL; - char *lastDot = NULL; - - char *p = (char *)filePath; - - while (*p != '\0') - { - if (*p == '/') - lastSlash = p; - else if (*p == '.') - lastDot = p; - - p++; - } - - char *subStr; - NSUInteger subLen; - - if (lastSlash) - { - if (lastDot) - { - // lastSlash -> lastDot - subStr = lastSlash + 1; - subLen = lastDot - subStr; - } - else - { - // lastSlash -> endOfString - subStr = lastSlash + 1; - subLen = p - subStr; - } - } - else - { - if (lastDot) - { - // startOfString -> lastDot - subStr = (char *)filePath; - subLen = lastDot - subStr; - } - else - { - // startOfString -> endOfString - subStr = (char *)filePath; - subLen = p - subStr; - } - } - - if (copy) - { - return [[NSString alloc] initWithBytes:subStr - length:subLen - encoding:NSUTF8StringEncoding]; - } - else - { - // We can take advantage of the fact that __FILE__ is a string literal. - // Specifically, we don't need to waste time copying the string. - // We can just tell NSString to point to a range within the string literal. - - return [[NSString alloc] initWithBytesNoCopy:subStr - length:subLen - encoding:NSUTF8StringEncoding - freeWhenDone:NO]; - } -} - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation DDLoggerNode - -- (id)initWithLogger:(id )aLogger loggerQueue:(dispatch_queue_t)aLoggerQueue -{ - if ((self = [super init])) - { - logger = aLogger; - - if (aLoggerQueue) { - loggerQueue = aLoggerQueue; - #if NEEDS_DISPATCH_RETAIN_RELEASE - dispatch_retain(loggerQueue); - #endif - } - } - return self; -} - -+ (DDLoggerNode *)nodeWithLogger:(id )logger loggerQueue:(dispatch_queue_t)loggerQueue -{ - return [[DDLoggerNode alloc] initWithLogger:logger loggerQueue:loggerQueue]; -} - -- (void)dealloc -{ - #if NEEDS_DISPATCH_RETAIN_RELEASE - if (loggerQueue) dispatch_release(loggerQueue); - #endif -} - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation DDLogMessage - -static char *dd_str_copy(const char *str) -{ - if (str == NULL) return NULL; - - size_t length = strlen(str); - char * result = malloc(length + 1); - strncpy(result, str, length); - result[length] = 0; - - return result; -} - -- (id)initWithLogMsg:(NSString *)msg - level:(int)level - flag:(int)flag - context:(int)context - file:(const char *)aFile - function:(const char *)aFunction - line:(int)line - tag:(id)aTag - options:(DDLogMessageOptions)optionsMask -{ - if ((self = [super init])) - { - logMsg = msg; - logLevel = level; - logFlag = flag; - logContext = context; - lineNumber = line; - tag = aTag; - options = optionsMask; - - if (options & DDLogMessageCopyFile) - file = dd_str_copy(aFile); - else - file = (char *)aFile; - - if (options & DDLogMessageCopyFunction) - file = dd_str_copy(aFunction); - else - function = (char *)aFunction; - - timestamp = [[NSDate alloc] init]; - - machThreadID = pthread_mach_thread_np(pthread_self()); - - queueLabel = dd_str_copy(dispatch_queue_get_label(dispatch_get_current_queue())); - - threadName = [[NSThread currentThread] name]; - } - return self; -} - -- (NSString *)threadID -{ - return [[NSString alloc] initWithFormat:@"%x", machThreadID]; -} - -- (NSString *)fileName -{ - return DDExtractFileNameWithoutExtension(file, NO); -} - -- (NSString *)methodName -{ - if (function == NULL) - return nil; - else - return [[NSString alloc] initWithUTF8String:function]; -} - -- (void)dealloc -{ - if (file && (options & DDLogMessageCopyFile)) - free(file); - - if (function && (options & DDLogMessageCopyFunction)) - free(function); - - if (queueLabel) - free(queueLabel); -} - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation DDAbstractLogger - -- (id)init -{ - if ((self = [super init])) - { - const char *loggerQueueName = NULL; - if ([self respondsToSelector:@selector(loggerName)]) - { - loggerQueueName = [[self loggerName] UTF8String]; - } - - loggerQueue = dispatch_queue_create(loggerQueueName, NULL); - } - return self; -} - -- (void)dealloc -{ - #if NEEDS_DISPATCH_RETAIN_RELEASE - if (loggerQueue) dispatch_release(loggerQueue); - #endif -} - -- (void)logMessage:(DDLogMessage *)logMessage -{ - // Override me -} - -- (id )logFormatter -{ - // This method must be thread safe and intuitive. - // Therefore if somebody executes the following code: - // - // [logger setLogFormatter:myFormatter]; - // formatter = [logger logFormatter]; - // - // They would expect formatter to equal myFormatter. - // This functionality must be ensured by the getter and setter method. - // - // The thread safety must not come at a cost to the performance of the logMessage method. - // This method is likely called sporadically, while the logMessage method is called repeatedly. - // This means, the implementation of this method: - // - Must NOT require the logMessage method to acquire a lock. - // - Must NOT require the logMessage method to access an atomic property (also a lock of sorts). - // - // Thread safety is ensured by executing access to the formatter variable on the loggerQueue. - // This is the same queue that the logMessage method operates on. - // - // Note: The last time I benchmarked the performance of direct access vs atomic property access, - // direct access was over twice as fast on the desktop and over 6 times as fast on the iPhone. - // - // - // loggerQueue : Our own private internal queue that the logMessage method runs on. - // Operations are added to this queue from the global loggingQueue. - // - // loggingQueue : The queue that all log messages go through before they arrive in our loggerQueue. - // - // It is important to note that, while the loggerQueue is used to create thread-safety for our formatter, - // changes to the formatter variable are queued through the loggingQueue. - // - // Since this will obviously confuse the hell out of me later, here is a better description. - // Imagine the following code: - // - // DDLogVerbose(@"log msg 1"); - // DDLogVerbose(@"log msg 2"); - // [logger setFormatter:myFormatter]; - // DDLogVerbose(@"log msg 3"); - // - // Our intuitive requirement means that the new formatter will only apply to the 3rd log message. - // But notice what happens if we have asynchronous logging enabled for verbose mode. - // - // Log msg 1 starts executing asynchronously on the loggingQueue. - // The loggingQueue executes the log statement on each logger concurrently. - // That means it executes log msg 1 on our loggerQueue. - // While log msg 1 is executing, log msg 2 gets added to the loggingQueue. - // Then the user requests that we change our formatter. - // So at this exact moment, our queues look like this: - // - // loggerQueue : executing log msg 1, nil - // loggingQueue : executing log msg 1, log msg 2, nil - // - // So direct access to the formatter is only available if requested from the loggerQueue. - // In all other circumstances we need to go through the loggingQueue to get the proper value. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - return formatter; - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - __block id result; - - dispatch_sync(globalLoggingQueue, ^{ - dispatch_sync(loggerQueue, ^{ - result = formatter; - }); - }); - - return result; - } -} - -- (void)setLogFormatter:(id )logFormatter -{ - // The design of this method is documented extensively in the logFormatter message (above in code). - - dispatch_block_t block = ^{ @autoreleasepool { - - if (formatter != logFormatter) - { - if ([formatter respondsToSelector:@selector(willRemoveFromLogger:)]) { - [formatter willRemoveFromLogger:self]; - } - - formatter = logFormatter; - - if ([formatter respondsToSelector:@selector(didAddToLogger:)]) { - [formatter didAddToLogger:self]; - } - } - }}; - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (dispatch_queue_t)loggerQueue -{ - return loggerQueue; -} - -- (NSString *)loggerName -{ - return NSStringFromClass([self class]); -} - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h b/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h deleted file mode 100755 index 4cbd2e8..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.h +++ /dev/null @@ -1,167 +0,0 @@ -#import -#if TARGET_OS_IPHONE -#import -#else -#import -#endif - -#import "DDLog.h" - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted - * - * - * This class provides a logger for Terminal output or Xcode console output, - * depending on where you are running your code. - * - * As described in the "Getting Started" page, - * the traditional NSLog() function directs it's output to two places: - * - * - Apple System Log (so it shows up in Console.app) - * - StdErr (if stderr is a TTY, so log statements show up in Xcode console) - * - * To duplicate NSLog() functionality you can simply add this logger and an asl logger. - * However, if you instead choose to use file logging (for faster performance), - * you may choose to use only a file logger and a tty logger. -**/ - -@interface DDTTYLogger : DDAbstractLogger -{ - NSCalendar *calendar; - NSUInteger calendarUnitFlags; - - NSString *appName; - char *app; - size_t appLen; - - NSString *processID; - char *pid; - size_t pidLen; - - BOOL colorsEnabled; - NSMutableArray *colorProfilesArray; - NSMutableDictionary *colorProfilesDict; -} - -+ (DDTTYLogger *)sharedInstance; - -/* Inherited from the DDLogger protocol: - * - * Formatters may optionally be added to any logger. - * - * If no formatter is set, the logger simply logs the message as it is given in logMessage, - * or it may use its own built in formatting style. - * - * More information about formatters can be found here: - * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters - * - * The actual implementation of these methods is inherited from DDAbstractLogger. - -- (id )logFormatter; -- (void)setLogFormatter:(id )formatter; - -*/ - -/** - * Want to use different colors for different log levels? - * Enable this property. - * - * If you run the application via the Terminal (not Xcode), - * the logger will map colors to xterm-256color or xterm-color (if available). - * - * Xcode does NOT natively support colors in the Xcode debugging console. - * You'll need to install the XcodeColors plugin to see colors in the Xcode console. - * https://github.com/robbiehanson/XcodeColors - * - * The default value if NO. -**/ -@property (readwrite, assign) BOOL colorsEnabled; - -/** - * The default color set (foregroundColor, backgroundColor) is: - * - * - LOG_FLAG_ERROR = (red, nil) - * - LOG_FLAG_WARN = (orange, nil) - * - * You can customize the colors however you see fit. - * Please note that you are passing a flag, NOT a level. - * - * GOOD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:LOG_FLAG_INFO]; // <- Good :) - * BAD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:LOG_LEVEL_INFO]; // <- BAD! :( - * - * LOG_FLAG_INFO = 0...00100 - * LOG_LEVEL_INFO = 0...00111 <- Would match LOG_FLAG_INFO and LOG_FLAG_WARN and LOG_FLAG_ERROR - * - * If you run the application within Xcode, then the XcodeColors plugin is required. - * - * If you run the application from a shell, then DDTTYLogger will automatically map the given color to - * the closest available color. (xterm-256color or xterm-color which have 256 and 16 supported colors respectively.) - * - * This method invokes setForegroundColor:backgroundColor:forFlag:context: and passes the default context (0). -**/ -#if TARGET_OS_IPHONE -- (void)setForegroundColor:(UIColor *)txtColor backgroundColor:(UIColor *)bgColor forFlag:(int)mask; -#else -- (void)setForegroundColor:(NSColor *)txtColor backgroundColor:(NSColor *)bgColor forFlag:(int)mask; -#endif - -/** - * Just like setForegroundColor:backgroundColor:flag, but allows you to specify a particular logging context. - * - * A logging context is often used to identify log messages coming from a 3rd party framework, - * although logging context's can be used for many different functions. - * - * Logging context's are explained in further detail here: - * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomContext -**/ -#if TARGET_OS_IPHONE -- (void)setForegroundColor:(UIColor *)txtColor backgroundColor:(UIColor *)bgColor forFlag:(int)mask context:(int)ctxt; -#else -- (void)setForegroundColor:(NSColor *)txtColor backgroundColor:(NSColor *)bgColor forFlag:(int)mask context:(int)ctxt; -#endif - -/** - * Similar to the methods above, but allows you to map DDLogMessage->tag to a particular color profile. - * For example, you could do something like this: - * - * static NSString *const PurpleTag = @"PurpleTag"; - * - * #define DDLogPurple(frmt, ...) LOG_OBJC_TAG_MACRO(NO, 0, 0, 0, PurpleTag, frmt, ##__VA_ARGS__) - * - * And then in your applicationDidFinishLaunching, or wherever you configure Lumberjack: - * - * #if TARGET_OS_IPHONE - * UIColor *purple = [UIColor colorWithRed:(64/255.0) green:(0/255.0) blue:(128/255.0) alpha:1.0]; - * #else - * NSColor *purple = [NSColor colorWithCalibratedRed:(64/255.0) green:(0/255.0) blue:(128/255.0) alpha:1.0]; - * - * [[DDTTYLogger sharedInstance] setForegroundColor:purple backgroundColor:nil forTag:PurpleTag]; - * [DDLog addLogger:[DDTTYLogger sharedInstance]]; - * - * This would essentially give you a straight NSLog replacement that prints in purple: - * - * DDLogPurple(@"I'm a purple log message!"); -**/ -#if TARGET_OS_IPHONE -- (void)setForegroundColor:(UIColor *)txtColor backgroundColor:(UIColor *)bgColor forTag:(id )tag; -#else -- (void)setForegroundColor:(NSColor *)txtColor backgroundColor:(NSColor *)bgColor forTag:(id )tag; -#endif - -/** - * Clearing color profiles. -**/ -- (void)clearColorsForFlag:(int)mask; -- (void)clearColorsForFlag:(int)mask context:(int)context; -- (void)clearColorsForTag:(id )tag; -- (void)clearColorsForAllFlags; -- (void)clearColorsForAllTags; -- (void)clearAllColors; - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m b/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m deleted file mode 100755 index 3157d84..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/DDTTYLogger.m +++ /dev/null @@ -1,1480 +0,0 @@ -#import "DDTTYLogger.h" - -#import -#import - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted -**/ - -#if ! __has_feature(objc_arc) -#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). -#endif - -// We probably shouldn't be using DDLog() statements within the DDLog implementation. -// But we still want to leave our log statements for any future debugging, -// and to allow other developers to trace the implementation (which is a great learning tool). -// -// So we use primitive logging macros around NSLog. -// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog. - -#define LOG_LEVEL 2 - -#define NSLogError(frmt, ...) do{ if(LOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0) -#define NSLogWarn(frmt, ...) do{ if(LOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0) -#define NSLogInfo(frmt, ...) do{ if(LOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0) -#define NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0) - -// Xcode does NOT natively support colors in the Xcode debugging console. -// You'll need to install the XcodeColors plugin to see colors in the Xcode console. -// https://github.com/robbiehanson/XcodeColors -// -// The following is documentation from the XcodeColors project: -// -// -// How to apply color formatting to your log statements: -// -// To set the foreground color: -// Insert the ESCAPE_SEQ into your string, followed by "fg124,12,255;" where r=124, g=12, b=255. -// -// To set the background color: -// Insert the ESCAPE_SEQ into your string, followed by "bg12,24,36;" where r=12, g=24, b=36. -// -// To reset the foreground color (to default value): -// Insert the ESCAPE_SEQ into your string, followed by "fg;" -// -// To reset the background color (to default value): -// Insert the ESCAPE_SEQ into your string, followed by "bg;" -// -// To reset the foreground and background color (to default values) in one operation: -// Insert the ESCAPE_SEQ into your string, followed by ";" - -#define XCODE_COLORS_ESCAPE_SEQ "\033[" - -#define XCODE_COLORS_RESET_FG XCODE_COLORS_ESCAPE_SEQ "fg;" // Clear any foreground color -#define XCODE_COLORS_RESET_BG XCODE_COLORS_ESCAPE_SEQ "bg;" // Clear any background color -#define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE_SEQ ";" // Clear any foreground or background color - -// Some simple defines to make life easier on ourself - -#if TARGET_OS_IPHONE - #define MakeColor(r, g, b) [UIColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f] -#else - #define MakeColor(r, g, b) [NSColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f] -#endif - -#if TARGET_OS_IPHONE - #define OSColor UIColor -#else - #define OSColor NSColor -#endif - -// If running in a shell, not all RGB colors will be supported. -// In this case we automatically map to the closest available color. -// In order to provide this mapping, we have a hard-coded set of the standard RGB values available in the shell. -// However, not every shell is the same, and Apple likes to think different even when it comes to shell colors. -// -// Map to standard Terminal.app colors (1), or -// map to standard xterm colors (0). - -#define MAP_TO_TERMINAL_APP_COLORS 1 - - -@interface DDTTYLoggerColorProfile : NSObject { -@public - int mask; - int context; - - uint8_t fg_r; - uint8_t fg_g; - uint8_t fg_b; - - uint8_t bg_r; - uint8_t bg_g; - uint8_t bg_b; - - NSUInteger fgCodeIndex; - NSString *fgCodeRaw; - - NSUInteger bgCodeIndex; - NSString *bgCodeRaw; - - char fgCode[24]; - size_t fgCodeLen; - - char bgCode[24]; - size_t bgCodeLen; - - char resetCode[8]; - size_t resetCodeLen; -} - -- (id)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)mask context:(int)ctxt; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation DDTTYLogger - -static BOOL isaTTY; -static BOOL isaColorTTY; -static BOOL isaColor256TTY; -static BOOL isaXcodeColorTTY; - -static NSArray *codes_fg = nil; -static NSArray *codes_bg = nil; -static NSArray *colors = nil; - -static DDTTYLogger *sharedInstance; - -/** - * Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 16 color mode. - * - * This method is used when the application is running from within a shell that only supports 16 color mode. - * This method is not invoked if the application is running within Xcode, or via normal UI app launch. -**/ -+ (void)initialize_colors_16 -{ - if (codes_fg || codes_bg || colors) return; - - NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:16]; - NSMutableArray *m_colors = [NSMutableArray arrayWithCapacity:16]; - - // In a standard shell only 16 colors are supported. - // - // More information about ansi escape codes can be found online. - // http://en.wikipedia.org/wiki/ANSI_escape_code - - [m_codes_fg addObject:@"30m"]; // normal - black - [m_codes_fg addObject:@"31m"]; // normal - red - [m_codes_fg addObject:@"32m"]; // normal - green - [m_codes_fg addObject:@"33m"]; // normal - yellow - [m_codes_fg addObject:@"34m"]; // normal - blue - [m_codes_fg addObject:@"35m"]; // normal - magenta - [m_codes_fg addObject:@"36m"]; // normal - cyan - [m_codes_fg addObject:@"37m"]; // normal - gray - [m_codes_fg addObject:@"1;30m"]; // bright - darkgray - [m_codes_fg addObject:@"1;31m"]; // bright - red - [m_codes_fg addObject:@"1;32m"]; // bright - green - [m_codes_fg addObject:@"1;33m"]; // bright - yellow - [m_codes_fg addObject:@"1;34m"]; // bright - blue - [m_codes_fg addObject:@"1;35m"]; // bright - magenta - [m_codes_fg addObject:@"1;36m"]; // bright - cyan - [m_codes_fg addObject:@"1;37m"]; // bright - white - - [m_codes_bg addObject:@"40m"]; // normal - black - [m_codes_bg addObject:@"41m"]; // normal - red - [m_codes_bg addObject:@"42m"]; // normal - green - [m_codes_bg addObject:@"43m"]; // normal - yellow - [m_codes_bg addObject:@"44m"]; // normal - blue - [m_codes_bg addObject:@"45m"]; // normal - magenta - [m_codes_bg addObject:@"46m"]; // normal - cyan - [m_codes_bg addObject:@"47m"]; // normal - gray - [m_codes_bg addObject:@"1;40m"]; // bright - darkgray - [m_codes_bg addObject:@"1;41m"]; // bright - red - [m_codes_bg addObject:@"1;42m"]; // bright - green - [m_codes_bg addObject:@"1;43m"]; // bright - yellow - [m_codes_bg addObject:@"1;44m"]; // bright - blue - [m_codes_bg addObject:@"1;45m"]; // bright - magenta - [m_codes_bg addObject:@"1;46m"]; // bright - cyan - [m_codes_bg addObject:@"1;47m"]; // bright - white - -#if MAP_TO_TERMINAL_APP_COLORS - - // Standard Terminal.app colors: - // - // These are the default colors used by Apple's Terminal.app. - - [m_colors addObject:MakeColor( 0, 0, 0)]; // normal - black - [m_colors addObject:MakeColor(194, 54, 33)]; // normal - red - [m_colors addObject:MakeColor( 37, 188, 36)]; // normal - green - [m_colors addObject:MakeColor(173, 173, 39)]; // normal - yellow - [m_colors addObject:MakeColor( 73, 46, 225)]; // normal - blue - [m_colors addObject:MakeColor(211, 56, 211)]; // normal - magenta - [m_colors addObject:MakeColor( 51, 187, 200)]; // normal - cyan - [m_colors addObject:MakeColor(203, 204, 205)]; // normal - gray - [m_colors addObject:MakeColor(129, 131, 131)]; // bright - darkgray - [m_colors addObject:MakeColor(252, 57, 31)]; // bright - red - [m_colors addObject:MakeColor( 49, 231, 34)]; // bright - green - [m_colors addObject:MakeColor(234, 236, 35)]; // bright - yellow - [m_colors addObject:MakeColor( 88, 51, 255)]; // bright - blue - [m_colors addObject:MakeColor(249, 53, 248)]; // bright - magenta - [m_colors addObject:MakeColor( 20, 240, 240)]; // bright - cyan - [m_colors addObject:MakeColor(233, 235, 235)]; // bright - white - -#else - - // Standard xterm colors: - // - // These are the default colors used by most xterm shells. - - [m_colors addObject:MakeColor( 0, 0, 0)]; // normal - black - [m_colors addObject:MakeColor(205, 0, 0)]; // normal - red - [m_colors addObject:MakeColor( 0, 205, 0)]; // normal - green - [m_colors addObject:MakeColor(205, 205, 0)]; // normal - yellow - [m_colors addObject:MakeColor( 0, 0, 238)]; // normal - blue - [m_colors addObject:MakeColor(205, 0, 205)]; // normal - magenta - [m_colors addObject:MakeColor( 0, 205, 205)]; // normal - cyan - [m_colors addObject:MakeColor(229, 229, 229)]; // normal - gray - [m_colors addObject:MakeColor(127, 127, 127)]; // bright - darkgray - [m_colors addObject:MakeColor(255, 0, 0)]; // bright - red - [m_colors addObject:MakeColor( 0, 255, 0)]; // bright - green - [m_colors addObject:MakeColor(255, 255, 0)]; // bright - yellow - [m_colors addObject:MakeColor( 92, 92, 255)]; // bright - blue - [m_colors addObject:MakeColor(255, 0, 255)]; // bright - magenta - [m_colors addObject:MakeColor( 0, 255, 255)]; // bright - cyan - [m_colors addObject:MakeColor(255, 255, 255)]; // bright - white - -#endif - - codes_fg = [m_codes_fg copy]; - codes_bg = [m_codes_bg copy]; - colors = [m_colors copy]; - - NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)"); - NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)"); -} - -/** - * Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 256 color mode. - * - * This method is used when the application is running from within a shell that supports 256 color mode. - * This method is not invoked if the application is running within Xcode, or via normal UI app launch. -**/ -+ (void)initialize_colors_256 -{ - if (codes_fg || codes_bg || colors) return; - - NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:(256-16)]; - NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:(256-16)]; - NSMutableArray *m_colors = [NSMutableArray arrayWithCapacity:(256-16)]; - - #if MAP_TO_TERMINAL_APP_COLORS - - // Standard Terminal.app colors: - // - // These are the colors the Terminal.app uses in xterm-256color mode. - // In this mode, the terminal supports 256 different colors, specified by 256 color codes. - // - // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode. - // These are actually configurable, and thus we ignore them for the purposes of mapping, - // as we can't rely on them being constant. They are largely duplicated anyway. - // - // The next 216 color codes are designed to run the spectrum, with several shades of every color. - // While the color codes are standardized, the actual RGB values for each color code is not. - // Apple's Terminal.app uses different RGB values from that of a standard xterm. - // Apple's choices in colors are designed to be a little nicer on the eyes. - // - // The last 24 color codes represent a grayscale. - // - // Unfortunately, unlike the standard xterm color chart, - // Apple's RGB values cannot be calculated using a simple formula (at least not that I know of). - // Also, I don't know of any ways to programmatically query the shell for the RGB values. - // So this big giant color chart had to be made by hand. - // - // More information about ansi escape codes can be found online. - // http://en.wikipedia.org/wiki/ANSI_escape_code - - // Colors - - [m_colors addObject:MakeColor( 47, 49, 49)]; - [m_colors addObject:MakeColor( 60, 42, 144)]; - [m_colors addObject:MakeColor( 66, 44, 183)]; - [m_colors addObject:MakeColor( 73, 46, 222)]; - [m_colors addObject:MakeColor( 81, 50, 253)]; - [m_colors addObject:MakeColor( 88, 51, 255)]; - - [m_colors addObject:MakeColor( 42, 128, 37)]; - [m_colors addObject:MakeColor( 42, 127, 128)]; - [m_colors addObject:MakeColor( 44, 126, 169)]; - [m_colors addObject:MakeColor( 56, 125, 209)]; - [m_colors addObject:MakeColor( 59, 124, 245)]; - [m_colors addObject:MakeColor( 66, 123, 255)]; - - [m_colors addObject:MakeColor( 51, 163, 41)]; - [m_colors addObject:MakeColor( 39, 162, 121)]; - [m_colors addObject:MakeColor( 42, 161, 162)]; - [m_colors addObject:MakeColor( 53, 160, 202)]; - [m_colors addObject:MakeColor( 45, 159, 240)]; - [m_colors addObject:MakeColor( 58, 158, 255)]; - - [m_colors addObject:MakeColor( 31, 196, 37)]; - [m_colors addObject:MakeColor( 48, 196, 115)]; - [m_colors addObject:MakeColor( 39, 195, 155)]; - [m_colors addObject:MakeColor( 49, 195, 195)]; - [m_colors addObject:MakeColor( 32, 194, 235)]; - [m_colors addObject:MakeColor( 53, 193, 255)]; - - [m_colors addObject:MakeColor( 50, 229, 35)]; - [m_colors addObject:MakeColor( 40, 229, 109)]; - [m_colors addObject:MakeColor( 27, 229, 149)]; - [m_colors addObject:MakeColor( 49, 228, 189)]; - [m_colors addObject:MakeColor( 33, 228, 228)]; - [m_colors addObject:MakeColor( 53, 227, 255)]; - - [m_colors addObject:MakeColor( 27, 254, 30)]; - [m_colors addObject:MakeColor( 30, 254, 103)]; - [m_colors addObject:MakeColor( 45, 254, 143)]; - [m_colors addObject:MakeColor( 38, 253, 182)]; - [m_colors addObject:MakeColor( 38, 253, 222)]; - [m_colors addObject:MakeColor( 42, 253, 252)]; - - [m_colors addObject:MakeColor(140, 48, 40)]; - [m_colors addObject:MakeColor(136, 51, 136)]; - [m_colors addObject:MakeColor(135, 52, 177)]; - [m_colors addObject:MakeColor(134, 52, 217)]; - [m_colors addObject:MakeColor(135, 56, 248)]; - [m_colors addObject:MakeColor(134, 53, 255)]; - - [m_colors addObject:MakeColor(125, 125, 38)]; - [m_colors addObject:MakeColor(124, 125, 125)]; - [m_colors addObject:MakeColor(122, 124, 166)]; - [m_colors addObject:MakeColor(123, 124, 207)]; - [m_colors addObject:MakeColor(123, 122, 247)]; - [m_colors addObject:MakeColor(124, 121, 255)]; - - [m_colors addObject:MakeColor(119, 160, 35)]; - [m_colors addObject:MakeColor(117, 160, 120)]; - [m_colors addObject:MakeColor(117, 160, 160)]; - [m_colors addObject:MakeColor(115, 159, 201)]; - [m_colors addObject:MakeColor(116, 158, 240)]; - [m_colors addObject:MakeColor(117, 157, 255)]; - - [m_colors addObject:MakeColor(113, 195, 39)]; - [m_colors addObject:MakeColor(110, 194, 114)]; - [m_colors addObject:MakeColor(111, 194, 154)]; - [m_colors addObject:MakeColor(108, 194, 194)]; - [m_colors addObject:MakeColor(109, 193, 234)]; - [m_colors addObject:MakeColor(108, 192, 255)]; - - [m_colors addObject:MakeColor(105, 228, 30)]; - [m_colors addObject:MakeColor(103, 228, 109)]; - [m_colors addObject:MakeColor(105, 228, 148)]; - [m_colors addObject:MakeColor(100, 227, 188)]; - [m_colors addObject:MakeColor( 99, 227, 227)]; - [m_colors addObject:MakeColor( 99, 226, 253)]; - - [m_colors addObject:MakeColor( 92, 253, 34)]; - [m_colors addObject:MakeColor( 96, 253, 103)]; - [m_colors addObject:MakeColor( 97, 253, 142)]; - [m_colors addObject:MakeColor( 88, 253, 182)]; - [m_colors addObject:MakeColor( 93, 253, 221)]; - [m_colors addObject:MakeColor( 88, 254, 251)]; - - [m_colors addObject:MakeColor(177, 53, 34)]; - [m_colors addObject:MakeColor(174, 54, 131)]; - [m_colors addObject:MakeColor(172, 55, 172)]; - [m_colors addObject:MakeColor(171, 57, 213)]; - [m_colors addObject:MakeColor(170, 55, 249)]; - [m_colors addObject:MakeColor(170, 57, 255)]; - - [m_colors addObject:MakeColor(165, 123, 37)]; - [m_colors addObject:MakeColor(163, 123, 123)]; - [m_colors addObject:MakeColor(162, 123, 164)]; - [m_colors addObject:MakeColor(161, 122, 205)]; - [m_colors addObject:MakeColor(161, 121, 241)]; - [m_colors addObject:MakeColor(161, 121, 255)]; - - [m_colors addObject:MakeColor(158, 159, 33)]; - [m_colors addObject:MakeColor(157, 158, 118)]; - [m_colors addObject:MakeColor(157, 158, 159)]; - [m_colors addObject:MakeColor(155, 157, 199)]; - [m_colors addObject:MakeColor(155, 157, 239)]; - [m_colors addObject:MakeColor(154, 156, 255)]; - - [m_colors addObject:MakeColor(152, 193, 40)]; - [m_colors addObject:MakeColor(151, 193, 113)]; - [m_colors addObject:MakeColor(150, 193, 153)]; - [m_colors addObject:MakeColor(150, 192, 193)]; - [m_colors addObject:MakeColor(148, 192, 232)]; - [m_colors addObject:MakeColor(149, 191, 253)]; - - [m_colors addObject:MakeColor(146, 227, 28)]; - [m_colors addObject:MakeColor(144, 227, 108)]; - [m_colors addObject:MakeColor(144, 227, 147)]; - [m_colors addObject:MakeColor(144, 227, 187)]; - [m_colors addObject:MakeColor(142, 226, 227)]; - [m_colors addObject:MakeColor(142, 225, 252)]; - - [m_colors addObject:MakeColor(138, 253, 36)]; - [m_colors addObject:MakeColor(137, 253, 102)]; - [m_colors addObject:MakeColor(136, 253, 141)]; - [m_colors addObject:MakeColor(138, 254, 181)]; - [m_colors addObject:MakeColor(135, 255, 220)]; - [m_colors addObject:MakeColor(133, 255, 250)]; - - [m_colors addObject:MakeColor(214, 57, 30)]; - [m_colors addObject:MakeColor(211, 59, 126)]; - [m_colors addObject:MakeColor(209, 57, 168)]; - [m_colors addObject:MakeColor(208, 55, 208)]; - [m_colors addObject:MakeColor(207, 58, 247)]; - [m_colors addObject:MakeColor(206, 61, 255)]; - - [m_colors addObject:MakeColor(204, 121, 32)]; - [m_colors addObject:MakeColor(202, 121, 121)]; - [m_colors addObject:MakeColor(201, 121, 161)]; - [m_colors addObject:MakeColor(200, 120, 202)]; - [m_colors addObject:MakeColor(200, 120, 241)]; - [m_colors addObject:MakeColor(198, 119, 255)]; - - [m_colors addObject:MakeColor(198, 157, 37)]; - [m_colors addObject:MakeColor(196, 157, 116)]; - [m_colors addObject:MakeColor(195, 156, 157)]; - [m_colors addObject:MakeColor(195, 156, 197)]; - [m_colors addObject:MakeColor(194, 155, 236)]; - [m_colors addObject:MakeColor(193, 155, 255)]; - - [m_colors addObject:MakeColor(191, 192, 36)]; - [m_colors addObject:MakeColor(190, 191, 112)]; - [m_colors addObject:MakeColor(189, 191, 152)]; - [m_colors addObject:MakeColor(189, 191, 191)]; - [m_colors addObject:MakeColor(188, 190, 230)]; - [m_colors addObject:MakeColor(187, 190, 253)]; - - [m_colors addObject:MakeColor(185, 226, 28)]; - [m_colors addObject:MakeColor(184, 226, 106)]; - [m_colors addObject:MakeColor(183, 225, 146)]; - [m_colors addObject:MakeColor(183, 225, 186)]; - [m_colors addObject:MakeColor(182, 225, 225)]; - [m_colors addObject:MakeColor(181, 224, 252)]; - - [m_colors addObject:MakeColor(178, 255, 35)]; - [m_colors addObject:MakeColor(178, 255, 101)]; - [m_colors addObject:MakeColor(177, 254, 141)]; - [m_colors addObject:MakeColor(176, 254, 180)]; - [m_colors addObject:MakeColor(176, 254, 220)]; - [m_colors addObject:MakeColor(175, 253, 249)]; - - [m_colors addObject:MakeColor(247, 56, 30)]; - [m_colors addObject:MakeColor(245, 57, 122)]; - [m_colors addObject:MakeColor(243, 59, 163)]; - [m_colors addObject:MakeColor(244, 60, 204)]; - [m_colors addObject:MakeColor(242, 59, 241)]; - [m_colors addObject:MakeColor(240, 55, 255)]; - - [m_colors addObject:MakeColor(241, 119, 36)]; - [m_colors addObject:MakeColor(240, 120, 118)]; - [m_colors addObject:MakeColor(238, 119, 158)]; - [m_colors addObject:MakeColor(237, 119, 199)]; - [m_colors addObject:MakeColor(237, 118, 238)]; - [m_colors addObject:MakeColor(236, 118, 255)]; - - [m_colors addObject:MakeColor(235, 154, 36)]; - [m_colors addObject:MakeColor(235, 154, 114)]; - [m_colors addObject:MakeColor(234, 154, 154)]; - [m_colors addObject:MakeColor(232, 154, 194)]; - [m_colors addObject:MakeColor(232, 153, 234)]; - [m_colors addObject:MakeColor(232, 153, 255)]; - - [m_colors addObject:MakeColor(230, 190, 30)]; - [m_colors addObject:MakeColor(229, 189, 110)]; - [m_colors addObject:MakeColor(228, 189, 150)]; - [m_colors addObject:MakeColor(227, 189, 190)]; - [m_colors addObject:MakeColor(227, 189, 229)]; - [m_colors addObject:MakeColor(226, 188, 255)]; - - [m_colors addObject:MakeColor(224, 224, 35)]; - [m_colors addObject:MakeColor(223, 224, 105)]; - [m_colors addObject:MakeColor(222, 224, 144)]; - [m_colors addObject:MakeColor(222, 223, 184)]; - [m_colors addObject:MakeColor(222, 223, 224)]; - [m_colors addObject:MakeColor(220, 223, 253)]; - - [m_colors addObject:MakeColor(217, 253, 28)]; - [m_colors addObject:MakeColor(217, 253, 99)]; - [m_colors addObject:MakeColor(216, 252, 139)]; - [m_colors addObject:MakeColor(216, 252, 179)]; - [m_colors addObject:MakeColor(215, 252, 218)]; - [m_colors addObject:MakeColor(215, 251, 250)]; - - [m_colors addObject:MakeColor(255, 61, 30)]; - [m_colors addObject:MakeColor(255, 60, 118)]; - [m_colors addObject:MakeColor(255, 58, 159)]; - [m_colors addObject:MakeColor(255, 56, 199)]; - [m_colors addObject:MakeColor(255, 55, 238)]; - [m_colors addObject:MakeColor(255, 59, 255)]; - - [m_colors addObject:MakeColor(255, 117, 29)]; - [m_colors addObject:MakeColor(255, 117, 115)]; - [m_colors addObject:MakeColor(255, 117, 155)]; - [m_colors addObject:MakeColor(255, 117, 195)]; - [m_colors addObject:MakeColor(255, 116, 235)]; - [m_colors addObject:MakeColor(254, 116, 255)]; - - [m_colors addObject:MakeColor(255, 152, 27)]; - [m_colors addObject:MakeColor(255, 152, 111)]; - [m_colors addObject:MakeColor(254, 152, 152)]; - [m_colors addObject:MakeColor(255, 152, 192)]; - [m_colors addObject:MakeColor(254, 151, 231)]; - [m_colors addObject:MakeColor(253, 151, 253)]; - - [m_colors addObject:MakeColor(255, 187, 33)]; - [m_colors addObject:MakeColor(253, 187, 107)]; - [m_colors addObject:MakeColor(252, 187, 148)]; - [m_colors addObject:MakeColor(253, 187, 187)]; - [m_colors addObject:MakeColor(254, 187, 227)]; - [m_colors addObject:MakeColor(252, 186, 252)]; - - [m_colors addObject:MakeColor(252, 222, 34)]; - [m_colors addObject:MakeColor(251, 222, 103)]; - [m_colors addObject:MakeColor(251, 222, 143)]; - [m_colors addObject:MakeColor(250, 222, 182)]; - [m_colors addObject:MakeColor(251, 221, 222)]; - [m_colors addObject:MakeColor(252, 221, 252)]; - - [m_colors addObject:MakeColor(251, 252, 15)]; - [m_colors addObject:MakeColor(251, 252, 97)]; - [m_colors addObject:MakeColor(249, 252, 137)]; - [m_colors addObject:MakeColor(247, 252, 177)]; - [m_colors addObject:MakeColor(247, 253, 217)]; - [m_colors addObject:MakeColor(254, 255, 255)]; - - // Grayscale - - [m_colors addObject:MakeColor( 52, 53, 53)]; - [m_colors addObject:MakeColor( 57, 58, 59)]; - [m_colors addObject:MakeColor( 66, 67, 67)]; - [m_colors addObject:MakeColor( 75, 76, 76)]; - [m_colors addObject:MakeColor( 83, 85, 85)]; - [m_colors addObject:MakeColor( 92, 93, 94)]; - - [m_colors addObject:MakeColor(101, 102, 102)]; - [m_colors addObject:MakeColor(109, 111, 111)]; - [m_colors addObject:MakeColor(118, 119, 119)]; - [m_colors addObject:MakeColor(126, 127, 128)]; - [m_colors addObject:MakeColor(134, 136, 136)]; - [m_colors addObject:MakeColor(143, 144, 145)]; - - [m_colors addObject:MakeColor(151, 152, 153)]; - [m_colors addObject:MakeColor(159, 161, 161)]; - [m_colors addObject:MakeColor(167, 169, 169)]; - [m_colors addObject:MakeColor(176, 177, 177)]; - [m_colors addObject:MakeColor(184, 185, 186)]; - [m_colors addObject:MakeColor(192, 193, 194)]; - - [m_colors addObject:MakeColor(200, 201, 202)]; - [m_colors addObject:MakeColor(208, 209, 210)]; - [m_colors addObject:MakeColor(216, 218, 218)]; - [m_colors addObject:MakeColor(224, 226, 226)]; - [m_colors addObject:MakeColor(232, 234, 234)]; - [m_colors addObject:MakeColor(240, 242, 242)]; - - // Color codes - - int index = 16; - - while (index < 256) - { - [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]]; - [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]]; - - index++; - } - - #else - - // Standard xterm colors: - // - // These are the colors xterm shells use in xterm-256color mode. - // In this mode, the shell supports 256 different colors, specified by 256 color codes. - // - // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode. - // These are generally configurable, and thus we ignore them for the purposes of mapping, - // as we can't rely on them being constant. They are largely duplicated anyway. - // - // The next 216 color codes are designed to run the spectrum, with several shades of every color. - // The last 24 color codes represent a grayscale. - // - // While the color codes are standardized, the actual RGB values for each color code is not. - // However most standard xterms follow a well known color chart, - // which can easily be calculated using the simple formula below. - // - // More information about ansi escape codes can be found online. - // http://en.wikipedia.org/wiki/ANSI_escape_code - - int index = 16; - - int r; // red - int g; // green - int b; // blue - - int ri; // r increment - int gi; // g increment - int bi; // b increment - - // Calculate xterm colors (using standard algorithm) - - int r = 0; - int g = 0; - int b = 0; - - for (ri = 0; ri < 6; ri++) - { - r = (ri == 0) ? 0 : 95 + (40 * (ri - 1)); - - for (gi = 0; gi < 6; gi++) - { - g = (gi == 0) ? 0 : 95 + (40 * (gi - 1)); - - for (bi = 0; bi < 6; bi++) - { - b = (bi == 0) ? 0 : 95 + (40 * (bi - 1)); - - [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]]; - [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]]; - [m_colors addObject:MakeColor(r, g, b)]; - - index++; - } - } - } - - // Calculate xterm grayscale (using standard algorithm) - - r = 8; - g = 8; - b = 8; - - while (index < 256) - { - [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]]; - [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]]; - [m_colors addObject:MakeColor(r, g, b)]; - - r += 10; - g += 10; - b += 10; - - index++; - } - - #endif - - codes_fg = [m_codes_fg copy]; - codes_bg = [m_codes_bg copy]; - colors = [m_colors copy]; - - NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)"); - NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)"); -} - -+ (void)getRed:(CGFloat *)rPtr green:(CGFloat *)gPtr blue:(CGFloat *)bPtr fromColor:(OSColor *)color -{ - #if TARGET_OS_IPHONE - - // iOS - - if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)]) - { - [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL]; - } - else - { - // The method getRed:green:blue:alpha: was only available starting iOS 5. - // So in iOS 4 and earlier, we have to jump through hoops. - - CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); - - unsigned char pixel[4]; - CGContextRef context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, rgbColorSpace, kCGImageAlphaNoneSkipLast); - - CGContextSetFillColorWithColor(context, [color CGColor]); - CGContextFillRect(context, CGRectMake(0, 0, 1, 1)); - - if (rPtr) { *rPtr = pixel[0] / 255.0f; } - if (gPtr) { *gPtr = pixel[1] / 255.0f; } - if (bPtr) { *bPtr = pixel[2] / 255.0f; } - - CGContextRelease(context); - CGColorSpaceRelease(rgbColorSpace); - } - - #else - - // Mac OS X - - [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL]; - - #endif -} - -/** - * Maps the given color to the closest available color supported by the shell. - * The shell may support 256 colors, or only 16. - * - * This method loops through the known supported color set, and calculates the closest color. - * The array index of that color, within the colors array, is then returned. - * This array index may also be used as the index within the codes_fg and codes_bg arrays. -**/ -+ (NSUInteger)codeIndexForColor:(OSColor *)inColor -{ - CGFloat inR, inG, inB; - [self getRed:&inR green:&inG blue:&inB fromColor:inColor]; - - NSUInteger bestIndex = 0; - CGFloat lowestDistance = 100.0f; - - NSUInteger i = 0; - for (OSColor *color in colors) - { - // Calculate Euclidean distance (lower value means closer to given color) - - CGFloat r, g, b; - [self getRed:&r green:&g blue:&b fromColor:color]; - - #if CGFLOAT_IS_DOUBLE - CGFloat distance = sqrt(pow(r-inR, 2.0) + pow(g-inG, 2.0) + pow(b-inB, 2.0)); - #else - CGFloat distance = sqrtf(powf(r-inR, 2.0f) + powf(g-inG, 2.0f) + powf(b-inB, 2.0f)); - #endif - - NSLogVerbose(@"DDTTYLogger: %3lu : %.3f,%.3f,%.3f & %.3f,%.3f,%.3f = %.6f", - (unsigned long)i, inR, inG, inB, r, g, b, distance); - - if (distance < lowestDistance) - { - bestIndex = i; - lowestDistance = distance; - - NSLogVerbose(@"DDTTYLogger: New best index = %lu", (unsigned long)bestIndex); - } - - i++; - } - - return bestIndex; -} - -/** - * The runtime sends initialize to each class in a program exactly one time just before the class, - * or any class that inherits from it, is sent its first message from within the program. (Thus the - * method may never be invoked if the class is not used.) The runtime sends the initialize message to - * classes in a thread-safe manner. Superclasses receive this message before their subclasses. - * - * This method may also be called directly (assumably by accident), hence the safety mechanism. -**/ -+ (void)initialize -{ - static BOOL initialized = NO; - if (!initialized) - { - initialized = YES; - - isaTTY = isatty(STDERR_FILENO); - - char *term = getenv("TERM"); - if (term) - { - if (strcasestr(term, "color") != NULL) - { - isaColorTTY = YES; - isaColor256TTY = (strcasestr(term, "256") != NULL); - - if (isaColor256TTY) - [self initialize_colors_256]; - else - [self initialize_colors_16]; - } - } - else - { - // Xcode does NOT natively support colors in the Xcode debugging console. - // You'll need to install the XcodeColors plugin to see colors in the Xcode console. - // - // PS - Please read the header file before diving into the source code. - - char *xcode_colors = getenv("XcodeColors"); - if (xcode_colors && (strcmp(xcode_colors, "YES") == 0)) - { - isaXcodeColorTTY = YES; - } - } - - NSLogInfo(@"DDTTYLogger: isaColorTTY = %@", (isaColorTTY ? @"YES" : @"NO")); - NSLogInfo(@"DDTTYLogger: isaColor256TTY: %@", (isaColor256TTY ? @"YES" : @"NO")); - NSLogInfo(@"DDTTYLogger: isaXcodeColorTTY: %@", (isaXcodeColorTTY ? @"YES" : @"NO")); - - sharedInstance = [[DDTTYLogger alloc] init]; - } -} - -+ (DDTTYLogger *)sharedInstance -{ - return sharedInstance; -} - -- (id)init -{ - if (sharedInstance != nil) - { - return nil; - } - - if ((self = [super init])) - { - if (isaTTY) - { - calendar = [NSCalendar autoupdatingCurrentCalendar]; - - calendarUnitFlags = 0; - calendarUnitFlags |= NSYearCalendarUnit; - calendarUnitFlags |= NSMonthCalendarUnit; - calendarUnitFlags |= NSDayCalendarUnit; - calendarUnitFlags |= NSHourCalendarUnit; - calendarUnitFlags |= NSMinuteCalendarUnit; - calendarUnitFlags |= NSSecondCalendarUnit; - - // Initialze 'app' variable (char *) - - appName = [[NSProcessInfo processInfo] processName]; - - appLen = [appName lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - app = (char *)malloc(appLen + 1); - - [appName getCString:app maxLength:(appLen+1) encoding:NSUTF8StringEncoding]; - - // Initialize 'pid' variable (char *) - - processID = [NSString stringWithFormat:@"%i", (int)getpid()]; - - pidLen = [processID lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - pid = (char *)malloc(pidLen + 1); - - [processID getCString:pid maxLength:(pidLen+1) encoding:NSUTF8StringEncoding]; - - // Initialize color stuff - - colorsEnabled = NO; - colorProfilesArray = [[NSMutableArray alloc] initWithCapacity:8]; - colorProfilesDict = [[NSMutableDictionary alloc] initWithCapacity:8]; - } - } - return self; -} - -- (void)loadDefaultColorProfiles -{ - [self setForegroundColor:MakeColor(214, 57, 30) backgroundColor:nil forFlag:LOG_FLAG_ERROR]; - [self setForegroundColor:MakeColor(204, 121, 32) backgroundColor:nil forFlag:LOG_FLAG_WARN]; -} - -- (BOOL)colorsEnabled -{ - // The design of this method is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - return colorsEnabled; - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - __block BOOL result; - - dispatch_sync(globalLoggingQueue, ^{ - dispatch_sync(loggerQueue, ^{ - result = colorsEnabled; - }); - }); - - return result; - } -} - -- (void)setColorsEnabled:(BOOL)newColorsEnabled -{ - dispatch_block_t block = ^{ @autoreleasepool { - - colorsEnabled = newColorsEnabled; - - if ([colorProfilesArray count] == 0) { - [self loadDefaultColorProfiles]; - } - }}; - - // The design of the setter logic below is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forFlag:(int)mask -{ - [self setForegroundColor:txtColor backgroundColor:bgColor forFlag:mask context:0]; -} - -- (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forFlag:(int)mask context:(int)ctxt -{ - dispatch_block_t block = ^{ @autoreleasepool { - - DDTTYLoggerColorProfile *newColorProfile = - [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor - backgroundColor:bgColor - flag:mask - context:ctxt]; - - NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile); - - NSUInteger i = 0; - for (DDTTYLoggerColorProfile *colorProfile in colorProfilesArray) - { - if ((colorProfile->mask == mask) && (colorProfile->context == ctxt)) - { - break; - } - - i++; - } - - if (i < [colorProfilesArray count]) - [colorProfilesArray replaceObjectAtIndex:i withObject:newColorProfile]; - else - [colorProfilesArray addObject:newColorProfile]; - }}; - - // The design of the setter logic below is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forTag:(id )tag -{ - NSAssert([(id )tag conformsToProtocol:@protocol(NSCopying)], @"Invalid tag"); - - dispatch_block_t block = ^{ @autoreleasepool { - - DDTTYLoggerColorProfile *newColorProfile = - [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor - backgroundColor:bgColor - flag:0 - context:0]; - - NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile); - - [colorProfilesDict setObject:newColorProfile forKey:tag]; - }}; - - // The design of the setter logic below is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (void)clearColorsForFlag:(int)mask -{ - [self clearColorsForFlag:mask context:0]; -} - -- (void)clearColorsForFlag:(int)mask context:(int)context -{ - dispatch_block_t block = ^{ @autoreleasepool { - - NSUInteger i = 0; - for (DDTTYLoggerColorProfile *colorProfile in colorProfilesArray) - { - if ((colorProfile->mask == mask) && (colorProfile->context == context)) - { - break; - } - - i++; - } - - if (i < [colorProfilesArray count]) - { - [colorProfilesArray removeObjectAtIndex:i]; - } - }}; - - // The design of the setter logic below is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (void)clearColorsForTag:(id )tag -{ - NSAssert([(id )tag conformsToProtocol:@protocol(NSCopying)], @"Invalid tag"); - - dispatch_block_t block = ^{ @autoreleasepool { - - [colorProfilesDict removeObjectForKey:tag]; - }}; - - // The design of the setter logic below is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (void)clearColorsForAllFlags -{ - dispatch_block_t block = ^{ @autoreleasepool { - - [colorProfilesArray removeAllObjects]; - }}; - - // The design of the setter logic below is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (void)clearColorsForAllTags -{ - dispatch_block_t block = ^{ @autoreleasepool { - - [colorProfilesDict removeAllObjects]; - }}; - - // The design of the setter logic below is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (void)clearAllColors -{ - dispatch_block_t block = ^{ @autoreleasepool { - - [colorProfilesArray removeAllObjects]; - [colorProfilesDict removeAllObjects]; - }}; - - // The design of the setter logic below is taken from the DDAbstractLogger implementation. - // For documentation please refer to the DDAbstractLogger implementation. - - dispatch_queue_t currentQueue = dispatch_get_current_queue(); - if (currentQueue == loggerQueue) - { - block(); - } - else - { - dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue]; - NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure"); - - dispatch_async(globalLoggingQueue, ^{ - dispatch_async(loggerQueue, block); - }); - } -} - -- (void)logMessage:(DDLogMessage *)logMessage -{ - if (!isaTTY) return; - - NSString *logMsg = logMessage->logMsg; - BOOL isFormatted = NO; - - if (formatter) - { - logMsg = [formatter formatLogMessage:logMessage]; - isFormatted = logMsg != logMessage->logMsg; - } - - if (logMsg) - { - // Search for a color profile associated with the log message - - DDTTYLoggerColorProfile *colorProfile = nil; - - if (colorsEnabled) - { - if (logMessage->tag) - { - colorProfile = [colorProfilesDict objectForKey:logMessage->tag]; - } - if (colorProfile == nil) - { - for (DDTTYLoggerColorProfile *cp in colorProfilesArray) - { - if ((logMessage->logFlag & cp->mask) && (logMessage->logContext == cp->context)) - { - colorProfile = cp; - break; - } - } - } - } - - // Convert log message to C string. - // - // We use the stack instead of the heap for speed if possible. - // But we're extra cautious to avoid a stack overflow. - - NSUInteger msgLen = [logMsg lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - const BOOL useStack = msgLen < (1024 * 4); - - char msgStack[useStack ? (msgLen + 1) : 1]; // Analyzer doesn't like zero-size array, hence the 1 - char *msg = useStack ? msgStack : (char *)malloc(msgLen + 1); - - [logMsg getCString:msg maxLength:(msgLen + 1) encoding:NSUTF8StringEncoding]; - - // Write the log message to STDERR - - if (isFormatted) - { - // The log message has already been formatted. - - struct iovec v[4]; - - if (colorProfile) - { - v[0].iov_base = colorProfile->fgCode; - v[0].iov_len = colorProfile->fgCodeLen; - - v[3].iov_base = colorProfile->resetCode; - v[3].iov_len = colorProfile->resetCodeLen; - } - else - { - v[0].iov_base = ""; - v[0].iov_len = 0; - - v[3].iov_base = ""; - v[3].iov_len = 0; - } - - v[1].iov_base = (char *)msg; - v[1].iov_len = msgLen; - - v[2].iov_base = "\n"; - v[2].iov_len = (msg[msgLen] == '\n') ? 0 : 1; - - writev(STDERR_FILENO, v, 4); - } - else - { - // The log message is unformatted, so apply standard NSLog style formatting. - - int len; - - // Calculate timestamp. - // The technique below is faster than using NSDateFormatter. - - NSDateComponents *components = [calendar components:calendarUnitFlags fromDate:logMessage->timestamp]; - - NSTimeInterval epoch = [logMessage->timestamp timeIntervalSinceReferenceDate]; - int milliseconds = (int)((epoch - floor(epoch)) * 1000); - - char ts[24]; - len = snprintf(ts, 24, "%04ld-%02ld-%02ld %02ld:%02ld:%02ld:%03d", // yyyy-MM-dd HH:mm:ss:SSS - (long)components.year, - (long)components.month, - (long)components.day, - (long)components.hour, - (long)components.minute, - (long)components.second, milliseconds); - - size_t tsLen = MIN(24-1, len); - - // Calculate thread ID - // - // How many characters do we need for the thread id? - // logMessage->machThreadID is of type mach_port_t, which is an unsigned int. - // - // 1 hex char = 4 bits - // 8 hex chars for 32 bit, plus ending '\0' = 9 - - char tid[9]; - len = snprintf(tid, 9, "%x", logMessage->machThreadID); - - size_t tidLen = MIN(9-1, len); - - // Here is our format: "%s %s[%i:%s] %s", timestamp, appName, processID, threadID, logMsg - - struct iovec v[12]; - - if (colorProfile) - { - v[0].iov_base = colorProfile->fgCode; - v[0].iov_len = colorProfile->fgCodeLen; - - v[11].iov_base = colorProfile->resetCode; - v[11].iov_len = colorProfile->resetCodeLen; - } - else - { - v[0].iov_base = ""; - v[0].iov_len = 0; - - v[11].iov_base = ""; - v[11].iov_len = 0; - } - - v[1].iov_base = ts; - v[1].iov_len = tsLen; - - v[2].iov_base = " "; - v[2].iov_len = 1; - - v[3].iov_base = app; - v[3].iov_len = appLen; - - v[4].iov_base = "["; - v[4].iov_len = 1; - - v[5].iov_base = pid; - v[5].iov_len = pidLen; - - v[6].iov_base = ":"; - v[6].iov_len = 1; - - v[7].iov_base = tid; - v[7].iov_len = MIN((size_t)8, tidLen); // snprintf doesn't return what you might think - - v[8].iov_base = "] "; - v[8].iov_len = 2; - - v[9].iov_base = (char *)msg; - v[9].iov_len = msgLen; - - v[10].iov_base = "\n"; - v[10].iov_len = (msg[msgLen] == '\n') ? 0 : 1; - - writev(STDERR_FILENO, v, 12); - } - - if (!useStack) { - free(msg); - } - } -} - -- (NSString *)loggerName -{ - return @"cocoa.lumberjack.ttyLogger"; -} - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation DDTTYLoggerColorProfile - -- (id)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)aMask context:(int)ctxt -{ - if ((self = [super init])) - { - mask = aMask; - context = ctxt; - - CGFloat r, g, b; - - if (fgColor) - { - [DDTTYLogger getRed:&r green:&g blue:&b fromColor:fgColor]; - - fg_r = (uint8_t)(r * 255.0f); - fg_g = (uint8_t)(g * 255.0f); - fg_b = (uint8_t)(b * 255.0f); - } - if (bgColor) - { - [DDTTYLogger getRed:&r green:&g blue:&b fromColor:bgColor]; - - bg_r = (uint8_t)(r * 255.0f); - bg_g = (uint8_t)(g * 255.0f); - bg_b = (uint8_t)(b * 255.0f); - } - - if (fgColor && isaColorTTY) - { - // Map foreground color to closest available shell color - - fgCodeIndex = [DDTTYLogger codeIndexForColor:fgColor]; - fgCodeRaw = [codes_fg objectAtIndex:fgCodeIndex]; - - NSString *escapeSeq = @"\033["; - - NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - NSUInteger len2 = [fgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - - [escapeSeq getCString:(fgCode) maxLength:(len1+1) encoding:NSUTF8StringEncoding]; - [fgCodeRaw getCString:(fgCode+len1) maxLength:(len2+1) encoding:NSUTF8StringEncoding]; - - fgCodeLen = len1+len2; - } - else if (fgColor && isaXcodeColorTTY) - { - // Convert foreground color to color code sequence - - const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ; - - int result = snprintf(fgCode, 24, "%sfg%u,%u,%u;", escapeSeq, fg_r, fg_g, fg_b); - fgCodeLen = MIN(result, (24-1)); - } - else - { - // No foreground color or no color support - - fgCode[0] = '\0'; - fgCodeLen = 0; - } - - if (bgColor && isaColorTTY) - { - // Map background color to closest available shell color - - bgCodeIndex = [DDTTYLogger codeIndexForColor:bgColor]; - bgCodeRaw = [codes_bg objectAtIndex:bgCodeIndex]; - - NSString *escapeSeq = @"\033["; - - NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - NSUInteger len2 = [bgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - - [escapeSeq getCString:(bgCode) maxLength:(len1+1) encoding:NSUTF8StringEncoding]; - [bgCodeRaw getCString:(bgCode+len1) maxLength:(len2+1) encoding:NSUTF8StringEncoding]; - - bgCodeLen = len1+len2; - } - else if (bgColor && isaXcodeColorTTY) - { - // Convert background color to color code sequence - - const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ; - - int result = snprintf(bgCode, 24, "%sbg%u,%u,%u;", escapeSeq, bg_r, bg_g, bg_b); - bgCodeLen = MIN(result, (24-1)); - } - else - { - // No background color or no color support - - bgCode[0] = '\0'; - bgCodeLen = 0; - } - - if (isaColorTTY) - { - resetCodeLen = snprintf(resetCode, 8, "\033[0m"); - } - else if (isaXcodeColorTTY) - { - resetCodeLen = snprintf(resetCode, 8, XCODE_COLORS_RESET); - } - else - { - resetCode[0] = '\0'; - resetCodeLen = 0; - } - } - return self; -} - -- (NSString *)description -{ - return [NSString stringWithFormat: - @"", - self, mask, context, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b, fgCodeRaw, bgCodeRaw]; -} - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.h b/Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.h deleted file mode 100644 index dffc865..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.h +++ /dev/null @@ -1,65 +0,0 @@ -#import -#import "DDLog.h" - -@class ContextFilterLogFormatter; - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" page. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted - * - * - * This class provides a log formatter that filters log statements from a logging context not on the whitelist. - * - * A log formatter can be added to any logger to format and/or filter its output. - * You can learn more about log formatters here: - * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters - * - * You can learn more about logging context's here: - * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomContext - * - * But here's a quick overview / refresher: - * - * Every log statement has a logging context. - * These come from the underlying logging macros defined in DDLog.h. - * The default logging context is zero. - * You can define multiple logging context's for use in your application. - * For example, logically separate parts of your app each have a different logging context. - * Also 3rd party frameworks that make use of Lumberjack generally use their own dedicated logging context. -**/ -@interface ContextWhitelistFilterLogFormatter : NSObject - -- (id)init; - -- (void)addToWhitelist:(int)loggingContext; -- (void)removeFromWhitelist:(int)loggingContext; - -- (NSArray *)whitelist; - -- (BOOL)isOnWhitelist:(int)loggingContext; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * This class provides a log formatter that filters log statements from a logging context on the blacklist. -**/ -@interface ContextBlacklistFilterLogFormatter : NSObject - -- (id)init; - -- (void)addToBlacklist:(int)loggingContext; -- (void)removeFromBlacklist:(int)loggingContext; - -- (NSArray *)blacklist; - -- (BOOL)isOnBlacklist:(int)loggingContext; - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.m b/Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.m deleted file mode 100644 index 570efde..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/Extensions/ContextFilterLogFormatter.m +++ /dev/null @@ -1,191 +0,0 @@ -#import "ContextFilterLogFormatter.h" -#import - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted -**/ - -#if ! __has_feature(objc_arc) -#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). -#endif - -@interface LoggingContextSet : NSObject - -- (void)addToSet:(int)loggingContext; -- (void)removeFromSet:(int)loggingContext; - -- (NSArray *)currentSet; - -- (BOOL)isInSet:(int)loggingContext; - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation ContextWhitelistFilterLogFormatter -{ - LoggingContextSet *contextSet; -} - -- (id)init -{ - if ((self = [super init])) - { - contextSet = [[LoggingContextSet alloc] init]; - } - return self; -} - - -- (void)addToWhitelist:(int)loggingContext -{ - [contextSet addToSet:loggingContext]; -} - -- (void)removeFromWhitelist:(int)loggingContext -{ - [contextSet removeFromSet:loggingContext]; -} - -- (NSArray *)whitelist -{ - return [contextSet currentSet]; -} - -- (BOOL)isOnWhitelist:(int)loggingContext -{ - return [contextSet isInSet:loggingContext]; -} - -- (NSString *)formatLogMessage:(DDLogMessage *)logMessage -{ - if ([self isOnWhitelist:logMessage->logContext]) - return logMessage->logMsg; - else - return nil; -} - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation ContextBlacklistFilterLogFormatter -{ - LoggingContextSet *contextSet; -} - -- (id)init -{ - if ((self = [super init])) - { - contextSet = [[LoggingContextSet alloc] init]; - } - return self; -} - - -- (void)addToBlacklist:(int)loggingContext -{ - [contextSet addToSet:loggingContext]; -} - -- (void)removeFromBlacklist:(int)loggingContext -{ - [contextSet removeFromSet:loggingContext]; -} - -- (NSArray *)blacklist -{ - return [contextSet currentSet]; -} - -- (BOOL)isOnBlacklist:(int)loggingContext -{ - return [contextSet isInSet:loggingContext]; -} - -- (NSString *)formatLogMessage:(DDLogMessage *)logMessage -{ - if ([self isOnBlacklist:logMessage->logContext]) - return nil; - else - return logMessage->logMsg; -} - -@end - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@implementation LoggingContextSet -{ - OSSpinLock lock; - NSMutableSet *set; -} - -- (id)init -{ - if ((self = [super init])) - { - set = [[NSMutableSet alloc] init]; - } - return self; -} - - -- (void)addToSet:(int)loggingContext -{ - OSSpinLockLock(&lock); - { - [set addObject:[NSNumber numberWithInt:loggingContext]]; - } - OSSpinLockUnlock(&lock); -} - -- (void)removeFromSet:(int)loggingContext -{ - OSSpinLockLock(&lock); - { - [set removeObject:[NSNumber numberWithInt:loggingContext]]; - } - OSSpinLockUnlock(&lock); -} - -- (NSArray *)currentSet -{ - NSArray *result = nil; - - OSSpinLockLock(&lock); - { - result = [set allObjects]; - } - OSSpinLockUnlock(&lock); - - return result; -} - -- (BOOL)isInSet:(int)loggingContext -{ - BOOL result = NO; - - OSSpinLockLock(&lock); - { - result = [set containsObject:[NSNumber numberWithInt:loggingContext]]; - } - OSSpinLockUnlock(&lock); - - return result; -} - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.h b/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.h deleted file mode 100644 index 7cc5772..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.h +++ /dev/null @@ -1,122 +0,0 @@ -#import -#import -#import "DDLog.h" - - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" page. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted - * - * - * This class provides a log formatter that prints the dispatch_queue label instead of the mach_thread_id. - * - * A log formatter can be added to any logger to format and/or filter its output. - * You can learn more about log formatters here: - * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters - * - * A typical NSLog (or DDTTYLogger) prints detailed info as [:]. - * For example: - * - * 2011-10-17 20:21:45.435 AppName[19928:5207] Your log message here - * - * Where: - * - 19928 = process id - * - 5207 = thread id (mach_thread_id printed in hex) - * - * When using grand central dispatch (GCD), this information is less useful. - * This is because a single serial dispatch queue may be run on any thread from an internally managed thread pool. - * For example: - * - * 2011-10-17 20:32:31.111 AppName[19954:4d07] Message from my_serial_dispatch_queue - * 2011-10-17 20:32:31.112 AppName[19954:5207] Message from my_serial_dispatch_queue - * 2011-10-17 20:32:31.113 AppName[19954:2c55] Message from my_serial_dispatch_queue - * - * This formatter allows you to replace the standard [box:info] with the dispatch_queue name. - * For example: - * - * 2011-10-17 20:32:31.111 AppName[img-scaling] Message from my_serial_dispatch_queue - * 2011-10-17 20:32:31.112 AppName[img-scaling] Message from my_serial_dispatch_queue - * 2011-10-17 20:32:31.113 AppName[img-scaling] Message from my_serial_dispatch_queue - * - * If the dispatch_queue doesn't have a set name, then it falls back to the thread name. - * If the current thread doesn't have a set name, then it falls back to the mach_thread_id in hex (like normal). - * - * Note: If manually creating your own background threads (via NSThread/alloc/init or NSThread/detachNeThread), - * you can use [[NSThread currentThread] setName:(NSString *)]. -**/ -@interface DispatchQueueLogFormatter : NSObject -{ - @protected - - NSString *dateFormatString; - - @private - - int32_t atomicLoggerCount; - NSDateFormatter *threadUnsafeDateFormatter; // Use [self stringFromDate] - - OSSpinLock lock; - - NSUInteger _minQueueLength; // _prefix == Only access via atomic property - NSUInteger _maxQueueLength; // _prefix == Only access via atomic property - NSMutableDictionary *_replacements; // _prefix == Only access from within spinlock -} - -/** - * Standard init method. - * Configure using properties as desired. -**/ -- (id)init; - -/** - * The minQueueLength restricts the minimum size of the [detail box]. - * If the minQueueLength is set to 0, there is no restriction. - * - * For example, say a dispatch_queue has a label of "diskIO": - * - * If the minQueueLength is 0: [diskIO] - * If the minQueueLength is 4: [diskIO] - * If the minQueueLength is 5: [diskIO] - * If the minQueueLength is 6: [diskIO] - * If the minQueueLength is 7: [diskIO ] - * If the minQueueLength is 8: [diskIO ] - * - * The default minQueueLength is 0 (no minimum, so [detail box] won't be padded). -**/ -@property (assign) NSUInteger minQueueLength; - -/** - * The maxQueueLength restricts the number of characters that will be inside the [detail box]. - * If the maxQueueLength is 0, there is no restriction. - * For example: - * - * Say a dispatch_queue has a label of "diskIO". (standardizedQueueLength==NO) - * If the maxQueueLength is 0: [diskIO] - * If the maxQueueLength is 4: [disk] - * If the maxQueueLength is 5: [diskI] - * If the maxQueueLength is 6: [diskIO] - * If the maxQueueLength is 7: [diskIO] - * If the maxQueueLength is 8: [diskIO] - * - * The default maxQueueLength is 0 (no maximum, so [thread box] queue names won't be truncated). -**/ -@property (assign) NSUInteger maxQueueLength; - -/** - * Sometimes queue labels have long names like "com.apple.main-queue", - * but you'd prefer something shorter like simply "main". - * - * This method allows you to set such preferred replacements. - * The above example is set by default. - * - * To remove/undo a previous replacement, invoke this method with nil for the 'shortLabel' parameter. -**/ -- (NSString *)replacementStringForQueueLabel:(NSString *)longLabel; -- (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel; - -@end diff --git a/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.m b/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.m deleted file mode 100644 index c8e55a1..0000000 --- a/Pods/CocoaLumberjack/Lumberjack/Extensions/DispatchQueueLogFormatter.m +++ /dev/null @@ -1,241 +0,0 @@ -#import "DispatchQueueLogFormatter.h" -#import - -/** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted -**/ - -#if ! __has_feature(objc_arc) -#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). -#endif - - -@implementation DispatchQueueLogFormatter - -- (id)init -{ - if ((self = [super init])) - { - dateFormatString = @"yyyy-MM-dd HH:mm:ss:SSS"; - - atomicLoggerCount = 0; - threadUnsafeDateFormatter = nil; - - _minQueueLength = 0; - _maxQueueLength = 0; - _replacements = [[NSMutableDictionary alloc] init]; - - // Set default replacements: - - [_replacements setObject:@"main" forKey:@"com.apple.main-thread"]; - } - return self; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark Configuration -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -@synthesize minQueueLength = _minQueueLength; -@synthesize maxQueueLength = _maxQueueLength; - -- (NSString *)replacementStringForQueueLabel:(NSString *)longLabel -{ - NSString *result = nil; - - OSSpinLockLock(&lock); - { - result = [_replacements objectForKey:longLabel]; - } - OSSpinLockUnlock(&lock); - - return result; -} - -- (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel -{ - OSSpinLockLock(&lock); - { - if (shortLabel) - [_replacements setObject:shortLabel forKey:longLabel]; - else - [_replacements removeObjectForKey:longLabel]; - } - OSSpinLockUnlock(&lock); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#pragma mark DDLogFormatter -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -- (NSString *)stringFromDate:(NSDate *)date -{ - int32_t loggerCount = OSAtomicAdd32(0, &atomicLoggerCount); - - if (loggerCount <= 1) - { - // Single-threaded mode. - - if (threadUnsafeDateFormatter == nil) - { - threadUnsafeDateFormatter = [[NSDateFormatter alloc] init]; - [threadUnsafeDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; - [threadUnsafeDateFormatter setDateFormat:dateFormatString]; - } - - return [threadUnsafeDateFormatter stringFromDate:date]; - } - else - { - // Multi-threaded mode. - // NSDateFormatter is NOT thread-safe. - - NSString *key = @"DispatchQueueLogFormatter_NSDateFormatter"; - - NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary]; - NSDateFormatter *dateFormatter = [threadDictionary objectForKey:key]; - - if (dateFormatter == nil) - { - dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; - [dateFormatter setDateFormat:dateFormatString]; - - [threadDictionary setObject:dateFormatter forKey:key]; - } - - return [dateFormatter stringFromDate:date]; - } -} - -- (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage -{ - // As per the DDLogFormatter contract, this method is always invoked on the same thread/dispatch_queue - - NSUInteger minQueueLength = self.minQueueLength; - NSUInteger maxQueueLength = self.maxQueueLength; - - // Get the name of the queue, thread, or machID (whichever we are to use). - - NSString *queueThreadLabel = nil; - - BOOL useQueueLabel = YES; - BOOL useThreadName = NO; - - if (logMessage->queueLabel) - { - // If you manually create a thread, it's dispatch_queue will have one of the thread names below. - // Since all such threads have the same name, we'd prefer to use the threadName or the machThreadID. - - char *names[] = { "com.apple.root.low-priority", - "com.apple.root.default-priority", - "com.apple.root.high-priority", - "com.apple.root.low-overcommit-priority", - "com.apple.root.default-overcommit-priority", - "com.apple.root.high-overcommit-priority" }; - - int length = sizeof(names) / sizeof(char *); - - int i; - for (i = 0; i < length; i++) - { - if (strcmp(logMessage->queueLabel, names[i]) == 0) - { - useQueueLabel = NO; - useThreadName = [logMessage->threadName length] > 0; - break; - } - } - } - else - { - useQueueLabel = NO; - useThreadName = [logMessage->threadName length] > 0; - } - - if (useQueueLabel || useThreadName) - { - NSString *fullLabel; - NSString *abrvLabel; - - if (useQueueLabel) - fullLabel = [NSString stringWithUTF8String:logMessage->queueLabel]; - else - fullLabel = logMessage->threadName; - - OSSpinLockLock(&lock); - { - abrvLabel = [_replacements objectForKey:fullLabel]; - } - OSSpinLockUnlock(&lock); - - if (abrvLabel) - queueThreadLabel = abrvLabel; - else - queueThreadLabel = fullLabel; - } - else - { - queueThreadLabel = [NSString stringWithFormat:@"%x", logMessage->machThreadID]; - } - - // Now use the thread label in the output - - NSUInteger labelLength = [queueThreadLabel length]; - - // labelLength > maxQueueLength : truncate - // labelLength < minQueueLength : padding - // : exact - - if ((maxQueueLength > 0) && (labelLength > maxQueueLength)) - { - // Truncate - - return [queueThreadLabel substringToIndex:maxQueueLength]; - } - else if (labelLength < minQueueLength) - { - // Padding - - NSUInteger numSpaces = minQueueLength - labelLength; - - char spaces[numSpaces + 1]; - memset(spaces, ' ', numSpaces); - spaces[numSpaces] = '\0'; - - return [NSString stringWithFormat:@"%@%s", queueThreadLabel, spaces]; - } - else - { - // Exact - - return queueThreadLabel; - } -} - -- (NSString *)formatLogMessage:(DDLogMessage *)logMessage -{ - NSString *timestamp = [self stringFromDate:(logMessage->timestamp)]; - NSString *queueThreadLabel = [self queueThreadLabelForLogMessage:logMessage]; - - return [NSString stringWithFormat:@"%@ [%@] %@", timestamp, queueThreadLabel, logMessage->logMsg]; -} - -- (void)didAddToLogger:(id )logger -{ - OSAtomicIncrement32(&atomicLoggerCount); -} - -- (void)willRemoveFromLogger:(id )logger -{ - OSAtomicDecrement32(&atomicLoggerCount); -} - -@end diff --git a/Pods/CocoaLumberjack/README.markdown b/Pods/CocoaLumberjack/README.markdown deleted file mode 100644 index 8ee32fd..0000000 --- a/Pods/CocoaLumberjack/README.markdown +++ /dev/null @@ -1,37 +0,0 @@ -### Lumberjack is Fast & Simple, yet Powerful & Flexible. - -It is similar in concept to other popular logging frameworks such as log4j, yet is designed specifically for Objective-C, and takes advantage of features such as multi-threading, grand central dispatch (if available), lockless atomic operations, and the dynamic nature of the Objective-C runtime. - -### Lumberjack is Fast - -In most cases it is an order of magnitude faster than NSLog. - -### Lumberjack is Simple - -It takes as little as a single line of code to configure lumberjack when your application launches. Then simply replace your NSLog statements with DDLog statements and that's about it. (And the DDLog macros have the exact same format and syntax as NSLog, so it's super easy.) - -### Lumberjack is Powerful: - -One log statement can be sent to multiple loggers, meaning you can log to a file and the console simultaneously. Want more? Create your own loggers (it's easy) and send your log statements over the network. Or to a database or distributed file system. The sky is the limit. - -### Lumberjack is Flexible: - -Configure your logging however you want. Change log levels per file (perfect for debugging). Change log levels per logger (verbose console, but concise log file). Change log levels per xcode configuration (verbose debug, but concise release). Have your log statements compiled out of the release build. Customize the number of log levels for your application. Add your own fine-grained logging. Dynamically change log levels during runtime. Choose how & when you want your log files to be rolled. Upload your log files to a central server. Compress archived log files to save disk space... - -
-This framework is for you if: - -- You're looking for a way to track down that impossible-to-reproduce bug that keeps popping up in the field. -- You're frustrated with the super short console log on the iPhone. -- You're looking to take your application to the next level in terms of support and stability. -- You're looking for an enterprise level logging solution for your application (Mac or iPhone). - -
-**[Get started using Lumberjack](https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted)**
-**[Learn more about Lumberjack](https://github.com/robbiehanson/CocoaLumberjack/wiki)**
- -
-Can't find the answer to your question in any of the [wiki](https://github.com/robbiehanson/CocoaLumberjack/wiki) articles? Try the **[mailing list](http://groups.google.com/group/cocoalumberjack)**. -
-
-Love the project? Wanna buy me a coffee? (or a beer :D) [![donation](http://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UZRA26JPJB3DA) diff --git a/Pods/CocoaLumberjack/README.md b/Pods/CocoaLumberjack/README.md new file mode 100644 index 0000000..e9a2fc1 --- /dev/null +++ b/Pods/CocoaLumberjack/README.md @@ -0,0 +1,301 @@ +

+ +

+ +CocoaLumberjack +=============== +[![Version](https://img.shields.io/github/release/CocoaLumberjack/CocoaLumberjack.svg?display_name=tag&style=flat)](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/latest) +[![License](https://img.shields.io/github/license/CocoaLumberjack/CocoaLumberjack.svg?style=flat)](https://opensource.org/licenses/BSD-3-Clause) +[![Pod Platform](https://img.shields.io/cocoapods/p/CocoaLumberjack.svg?style=flat)](https://cocoadocs.org/docsets/CocoaLumberjack/) +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +![Unit Tests](https://github.com/CocoaLumberjack/CocoaLumberjack/workflows/Unit%20Tests/badge.svg) +[![codecov](https://codecov.io/gh/CocoaLumberjack/CocoaLumberjack/branch/master/graph/badge.svg)](https://codecov.io/gh/CocoaLumberjack/CocoaLumberjack) +[![codebeat badge](https://codebeat.co/badges/840b714a-c8f3-4936-ada4-363473cd4e6b)](https://codebeat.co/projects/github-com-cocoalumberjack-cocoalumberjack-master) + + +**CocoaLumberjack** is a fast & simple, yet powerful & flexible logging framework for macOS, iOS, tvOS and watchOS. + +## How to get started + +First, install CocoaLumberjack via [CocoaPods](https://cocoapods.org), [Carthage](https://github.com/Carthage/Carthage), [Swift Package Manager](https://swift.org/package-manager/) or manually. +Then use `DDOSLogger` for iOS 10 and later, or `DDTTYLogger` and `DDASLLogger` for earlier versions to begin logging messages. + +### CocoaPods + +```ruby +platform :ios, '11.0' + +target 'SampleTarget' do + use_frameworks! + pod 'CocoaLumberjack/Swift' +end +``` +Note: `Swift` is a subspec which will include all the Obj-C code plus the Swift one, so this is sufficient. +For more details about how to use Swift with Lumberjack, see [this conversation](https://github.com/CocoaLumberjack/CocoaLumberjack/issues/405). + +For Objective-C use the following: +```ruby +platform :ios, '11.0' + +target 'SampleTarget' do + pod 'CocoaLumberjack' +end +``` + +### Carthage + +Carthage is a lightweight dependency manager for Swift and Objective-C. It leverages CocoaTouch modules and is less invasive than CocoaPods. + +To install with Carthage, follow the instruction on [Carthage](https://github.com/Carthage/Carthage) + +Cartfile +``` +github "CocoaLumberjack/CocoaLumberjack" +``` + + +### Swift Package Manager + +As of CocoaLumberjack 3.6.0, you can use the Swift Package Manager as integration method. +If you want to use the Swift Package Manager as integration method, either use Xcode to add the package dependency or add the following dependency to your Package.swift: + +```swift +.package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack.git", from: "3.8.0"), +``` + +Note that you may need to add both products, `CocoaLumberjack` and `CocoaLumberjackSwift` to your target since SPM sometimes fails to detect that `CocoaLumerjackSwift` depends on `CocoaLumberjack`. + +### Install manually + +If you want to install CocoaLumberjack manually, read the [manual installation](Documentation/GettingStarted.md#manual-installation) guide for more information. + +### Swift Usage + +Usually, you can simply `import CocoaLumberjackSwift`. If you installed CocoaLumberjack using CocoaPods, you need to use `import CocoaLumberjack` instead. + +```swift +DDLog.add(DDOSLogger.sharedInstance) // Uses os_log + +let fileLogger: DDFileLogger = DDFileLogger() // File Logger +fileLogger.rollingFrequency = 60 * 60 * 24 // 24 hours +fileLogger.logFileManager.maximumNumberOfLogFiles = 7 +DDLog.add(fileLogger) + +... + +DDLogVerbose("Verbose") +DDLogDebug("Debug") +DDLogInfo("Info") +DDLogWarn("Warn") +DDLogError("Error") +``` + +### Obj-C usage + +If you're using Lumberjack as a framework, you can `@import CocoaLumberjack;`. +Otherwise, `#import ` + +```objc +[DDLog addLogger:[DDOSLogger sharedInstance]]; // Uses os_log + +DDFileLogger *fileLogger = [[DDFileLogger alloc] init]; // File Logger +fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling +fileLogger.logFileManager.maximumNumberOfLogFiles = 7; +[DDLog addLogger:fileLogger]; + +... + +DDLogVerbose(@"Verbose"); +DDLogDebug(@"Debug"); +DDLogInfo(@"Info"); +DDLogWarn(@"Warn"); +DDLogError(@"Error"); +``` +### Objective-C ARC Semantic Issue + +When integrating Lumberjack into an existing Objective-C it is possible to run into `Multiple methods named 'tag' found with mismatched result, parameter type or attributes` build error. + +Add `#define DD_LEGACY_MESSAGE_TAG 0` before importing CocoaLumberjack or add `#define DD_LEGACY_MESSAGE_TAG 0` or add `-DDD_LEGACY_MESSAGE_TAG=0` to *Other C Flags*/*OTHER_CFLAGS* in your Xcode project. + +## [swift-log](https://github.com/apple/swift-log) backend + +CocoaLumberjack also ships with a backend implementation for [swift-log](https://github.com/apple/swift-log). +Simply add CocoaLumberjack as dependency to your SPM target (see above) and also add the `CocoaLumberjackSwiftLogBackend` product as dependency to your target. + +You can then use `DDLogHandler` as backend for swift-log, which will forward all messages to CocoaLumberjack's `DDLog`. You will still configure the loggers and log formatters you want via `DDLog`, but writing log messages will be done using `Logger` from swift-log. + +In your own log formatters, you can make use of the `swiftLogInfo` property on `DDLogMessage` to retrieve the details of a message that is logged via swift-log. + +To use swift-log with CocoaLumberjack, take a look the following code snippet to see how to get started. + +```swift +import CocoaLumberjack +import CocoaLumberjackSwiftLogBackend +import Logging + +// In your application's entry point (e.g. AppDelegate): +DDLog.add(DDOSLogger.sharedInstance) // Configure loggers +LoggingSystem.bootstrapWithCocoaLumberjack() // Use CocoaLumberjack as swift-log backend +``` + + +## More information + +- read the [Getting started](Documentation/GettingStarted.md) guide, check out the [FAQ](Documentation/FAQ.md) section or the other [docs](Documentation/) +- if you find issues or want to suggest improvements, create an issue or a pull request +- for all kinds of questions involving CocoaLumberjack, use the [Google group](https://groups.google.com/group/cocoalumberjack) or StackOverflow (use [#lumberjack](https://stackoverflow.com/questions/tagged/lumberjack)). + + +## CocoaLumberjack 3 + +### Migrating to 3.x + +* To be determined + +## Features + +### Lumberjack is Fast & Simple, yet Powerful & Flexible. + +It is similar in concept to other popular logging frameworks such as log4j, yet is designed specifically for Objective-C, and takes advantage of features such as multi-threading, grand central dispatch (if available), lockless atomic operations, and the dynamic nature of the Objective-C runtime. + +### Lumberjack is Fast + +In most cases it is an order of magnitude faster than NSLog. + +### Lumberjack is Simple + +It takes as little as a single line of code to configure lumberjack when your application launches. Then simply replace your NSLog statements with DDLog statements and that's about it. (And the DDLog macros have the exact same format and syntax as NSLog, so it's super easy.) + +### Lumberjack is Powerful: + +One log statement can be sent to multiple loggers, meaning you can log to a file and the console simultaneously. Want more? Create your own loggers (it's easy) and send your log statements over the network. Or to a database or distributed file system. The sky is the limit. + +### Lumberjack is Flexible: + +Configure your logging however you want. Change log levels per file (perfect for debugging). Change log levels per logger (verbose console, but concise log file). Change log levels per xcode configuration (verbose debug, but concise release). Have your log statements compiled out of the release build. Customize the number of log levels for your application. Add your own fine-grained logging. Dynamically change log levels during runtime. Choose how & when you want your log files to be rolled. Upload your log files to a central server. Compress archived log files to save disk space... + +## This framework is for you if: + +- You're looking for a way to track down that impossible-to-reproduce bug that keeps popping up in the field. +- You're frustrated with the super short console log on the iPhone. +- You're looking to take your application to the next level in terms of support and stability. +- You're looking for an enterprise level logging solution for your application (Mac or iPhone). + +## Documentation + +- **[Get started using Lumberjack](Documentation/GettingStarted.md)**
+- [Different log levels for Debug and Release builds](Documentation/XcodeTricks.md)
+- [Different log levels for each logger](Documentation/PerLoggerLogLevels.md)
+- [Use colors in the Xcode debugging console](Documentation/XcodeColors.md)
+- [Write your own custom formatters](Documentation/CustomFormatters.md)
+- [FAQ](Documentation/FAQ.md)
+- [Analysis of performance with benchmarks](Documentation/Performance.md)
+- [Common issues you may encounter and their solutions](Documentation/ProblemSolution.md)
+- [AppCode support](Documentation/AppCode-support.md) +- **[Full Lumberjack documentation](Documentation/)**
+ +## Requirements +The current version of Lumberjack requires: +- Xcode 14.1 or later +- Swift 5.5 or later +- macOS 10.13 or later +- iOS 11 or later +- tvOS 11 or later +- watchOS 4 or later + +### Backwards compatibility +- for iOS/tvOS up to 10, watchOS up to 3, macOS up to 10.12, Xcode up to 13 and Swift up to 5.4, use the 3.7.4 version +- for Xcode 11 and Swift up to 5.2, use the 3.6.2 version +- for Xcode 10 and Swift 4.2, use the 3.5.2 version +- for iOS 8, use the 3.6.1 version +- for iOS 6, iOS 7, OS X 10.8, OS X 10.9 and Xcode 9, use the 3.4.2 version +- for iOS 5 and OS X 10.7, use the 3.3 version +- for Xcode 8 and Swift 3, use the 3.2 version +- for Xcode 7.3 and Swift 2.3, use the 2.4.0 version +- for Xcode 7.3 and Swift 2.2, use the 2.3.0 version +- for Xcode 7.2 and 7.1, use the 2.2.0 version +- for Xcode 7.0 or earlier, use the 2.1.0 version +- for Xcode 6 or earlier, use the 2.0.x version +- for OS X < 10.7 support, use the 1.6.0 version + +## Communication + +- If you **need help**, use [Stack Overflow](https://stackoverflow.com/questions/tagged/lumberjack). (Tag 'lumberjack') +- If you'd like to **ask a general question**, use [Stack Overflow](https://stackoverflow.com/questions/tagged/lumberjack). +- If you **found a bug**, open an issue. +- If you **have a feature request**, open an issue. +- If you **want to contribute**, submit a pull request. + +## Data Collection Practices + +Per [App privacy details on the App Store](https://developer.apple.com/app-store/app-privacy-details/), Apple is requesting app developers to provide info about their data collection, us SDK maintainers must provide them with the same data. + +### Data collection by the framework + +**By default, CocoaLumberjack does NOT collect any data on its own.** + +[See our Data Collection Practices list.](https://cocoalumberjack.github.io/DataCollection/index.html) + +### Indirect data collection through the framework + +CocoaLumberjack is a logging framework which makes it easy to send those logs to different platforms. + +This is why collecting data might happen quite easily, if app developers include any sensitive data into their log messages. + +**Important note: app developers are fully responsible for any sensitive data collected through our logging system!** + +In consequence, you must comply to the Apple's privacy details policy (mentioned above) and document the ways in which user data is being collected. +Since the number of scenarios where data might be indirectly collected through CocoaLumberjack is quite large, it's up to you, as app developers, to properly review your app's code and identify those cases. +What we can do to help is raise awareness about potential data collection through our framework. + +Private data includes but isn't limited to: + +- user info (name, email, address, ...) +- location info +- contacts +- identifiers (user id, device id, ...) +- app usage data +- performance data +- health and fitness info +- financial info +- sensitive info +- user content +- history (browsing, search, ...) +- purchases +- diagnostics +- ... + +_Example_: `DDLogInfo("User: \(myUser)")` will add the `myUser` info to the logs, so if those are forwarded to a 3rd party or sent via email, that may qualify as data collection. + +## Author + +- [Robbie Hanson](https://github.com/robbiehanson) +- Love the project? Wanna buy me a coffee? (or a beer :D) [![donation](https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UZRA26JPJB3DA) + +## Collaborators +- [Ernesto Rivera](https://github.com/rivera-ernesto) +- [Dmitry Vorobyov](https://github.com/dvor) +- [Bogdan Poplauschi](https://github.com/bpoplauschi) +- [C.W. Betts](https://github.com/MaddTheSane) +- [Koichi Yokota (sushichop)](https://github.com/sushichop) +- [Nick Brook](https://github.com/nrbrook) +- [Florian Friedrich](https://github.com/ffried) +- [Stephan Diederich](https://github.com/diederich) +- [Kent Sutherland](https://github.com/ksuther) +- [Dmitry Lobanov](https://github.com/lolgear) +- [Hakon Hanesand](https://github.com/hhanesand) + +## License +- CocoaLumberjack is available under the BSD 3 license. See the [LICENSE file](LICENSE). + +## Extensions +- [Birch-Lumberjack](https://github.com/gruffins/birch-lumberjack) A remote logger for CocoaLumberjack +- [BugfenderSDK-CocoaLumberjack](https://github.com/bugfender/BugfenderSDK-CocoaLumberjack) A Bugfender logger for CocoaLumberjack +- [LogIO-CocoaLumberjack](https://github.com/s4nchez/LogIO-CocoaLumberjack) A log.io logger for CocoaLumberjack +- [XCDLumberjackNSLogger](https://github.com/0xced/XCDLumberjackNSLogger) CocoaLumberjack logger which sends logs to NSLogger + +## Architecture + +

+ +

diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/CLI/CLIColor.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/CLI/CLIColor.m new file mode 100644 index 0000000..08c6330 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/CLI/CLIColor.m @@ -0,0 +1,57 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +#if TARGET_OS_OSX + +#import + +@interface CLIColor () { + CGFloat _red, _green, _blue, _alpha; +} + +@end + + +@implementation CLIColor + ++ (instancetype)colorWithCalibratedRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha { + __auto_type color = [CLIColor new]; + color->_red = red; + color->_green = green; + color->_blue = blue; + color->_alpha = alpha; + return color; +} + +- (void)getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha { + if (red) { + *red = _red; + } + if (green) { + *green = _green; + } + if (blue) { + *blue = _blue; + } + if (alpha) { + *alpha = _alpha; + } +} + +@end + +#endif diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDASLLogCapture.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDASLLogCapture.m new file mode 100644 index 0000000..db7254d --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDASLLogCapture.m @@ -0,0 +1,205 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +#if !TARGET_OS_WATCH + +#include +#include +#include +#include + +#import + +// Disable legacy macros +#ifndef DD_LEGACY_MACROS + #define DD_LEGACY_MACROS 0 +#endif + +static __auto_type _cancel = YES; +static __auto_type _captureLevel = DDLogLevelVerbose; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +@implementation DDASLLogCapture +#pragma clang diagnostic pop + ++ (void)start { + // Ignore subsequent calls + if (!_cancel) { + return; + } + + _cancel = NO; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { + [self captureAslLogs]; + }); +} + ++ (void)stop { + _cancel = YES; +} + ++ (DDLogLevel)captureLevel { + return _captureLevel; +} + ++ (void)setCaptureLevel:(DDLogLevel)level { + _captureLevel = level; +} + +#pragma mark - Private methods + ++ (void)configureAslQuery:(aslmsg)query { + const char param[] = "7"; // ASL_LEVEL_DEBUG, which is everything. We'll rely on regular DDlog log level to filter + + asl_set_query(query, ASL_KEY_LEVEL, param, ASL_QUERY_OP_LESS_EQUAL | ASL_QUERY_OP_NUMERIC); + + // Don't retrieve logs from our own DDASLLogger + asl_set_query(query, kDDASLKeyDDLog, kDDASLDDLogValue, ASL_QUERY_OP_NOT_EQUAL); + +#if !TARGET_OS_IPHONE || (defined(TARGET_SIMULATOR) && TARGET_SIMULATOR) + __auto_type processId = [[NSProcessInfo processInfo] processIdentifier]; + char pid[16]; + snprintf(pid, sizeof(pid), "%d", processId); + asl_set_query(query, ASL_KEY_PID, pid, ASL_QUERY_OP_EQUAL | ASL_QUERY_OP_NUMERIC); +#endif +} + ++ (void)aslMessageReceived:(aslmsg)msg { + __auto_type messageCString = asl_get(msg, ASL_KEY_MSG); + if (messageCString == NULL) + return; + + DDLogFlag flag; + BOOL async; + + __auto_type levelCString = asl_get(msg, ASL_KEY_LEVEL); + switch (levelCString? atoi(levelCString) : 0) { + // By default all NSLog's with a ASL_LEVEL_WARNING level + case ASL_LEVEL_EMERG : + case ASL_LEVEL_ALERT : + case ASL_LEVEL_CRIT : flag = DDLogFlagError; async = NO; break; + case ASL_LEVEL_ERR : flag = DDLogFlagWarning; async = YES; break; + case ASL_LEVEL_WARNING : flag = DDLogFlagInfo; async = YES; break; + case ASL_LEVEL_NOTICE : flag = DDLogFlagDebug; async = YES; break; + case ASL_LEVEL_INFO : + case ASL_LEVEL_DEBUG : + default : flag = DDLogFlagVerbose; async = YES; break; + } + + if (!(_captureLevel & flag)) { + return; + } + + // NSString * sender = [NSString stringWithCString:asl_get(msg, ASL_KEY_SENDER) encoding:NSUTF8StringEncoding]; + NSString *message = @(messageCString); + + __auto_type secondsCString = asl_get(msg, ASL_KEY_TIME); + __auto_type nanoCString = asl_get(msg, ASL_KEY_TIME_NSEC); + __auto_type seconds = secondsCString ? strtod(secondsCString, NULL) : [NSDate timeIntervalSinceReferenceDate] - NSTimeIntervalSince1970; + __auto_type nanoSeconds = nanoCString? strtod(nanoCString, NULL) : 0; + __auto_type totalSeconds = seconds + (nanoSeconds / 1e9); + + __auto_type timeStamp = [NSDate dateWithTimeIntervalSince1970:totalSeconds]; + + __auto_type logMessage = [[DDLogMessage alloc] initWithMessage:message + level:_captureLevel + flag:flag + context:0 + file:@"DDASLLogCapture" + function:nil + line:0 + tag:nil + options:DDLogMessageDontCopyMessage + timestamp:timeStamp]; + + [DDLog log:async message:logMessage]; +} + ++ (void)captureAslLogs { + @autoreleasepool + { + /* + We use ASL_KEY_MSG_ID to see each message once, but there's no + obvious way to get the "next" ID. To bootstrap the process, we'll + search by timestamp until we've seen a message. + */ + + struct timeval timeval = { + .tv_sec = 0 + }; + gettimeofday(&timeval, NULL); + __auto_type startTime = (unsigned long long)timeval.tv_sec; + __block unsigned long long lastSeenID = 0; + + /* + syslogd posts kNotifyASLDBUpdate (com.apple.system.logger.message) + through the notify API when it saves messages to the ASL database. + There is some coalescing - currently it is sent at most twice per + second - but there is no documented guarantee about this. In any + case, there may be multiple messages per notification. + + Notify notifications don't carry any payload, so we need to search + for the messages. + */ + int notifyToken = 0; // Can be used to unregister with notify_cancel(). + notify_register_dispatch(kNotifyASLDBUpdate, ¬ifyToken, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int token) + { + // At least one message has been posted; build a search query. + @autoreleasepool + { + __auto_type query = asl_new(ASL_TYPE_QUERY); + char stringValue[64]; + + if (lastSeenID > 0) { + snprintf(stringValue, sizeof stringValue, "%llu", lastSeenID); + asl_set_query(query, ASL_KEY_MSG_ID, stringValue, ASL_QUERY_OP_GREATER | ASL_QUERY_OP_NUMERIC); + } else { + snprintf(stringValue, sizeof stringValue, "%llu", startTime); + asl_set_query(query, ASL_KEY_TIME, stringValue, ASL_QUERY_OP_GREATER_EQUAL | ASL_QUERY_OP_NUMERIC); + } + + [self configureAslQuery:query]; + + // Iterate over new messages. + aslmsg msg; + __auto_type response = asl_search(NULL, query); + + while ((msg = asl_next(response))) + { + [self aslMessageReceived:msg]; + + // Keep track of which messages we've seen. + lastSeenID = (unsigned long long)atoll(asl_get(msg, ASL_KEY_MSG_ID)); + } + asl_release(response); + asl_free(query); + + if (_cancel) { + notify_cancel(token); + return; + } + + } + }); + } +} + +@end + +#endif diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDASLLogger.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDASLLogger.m new file mode 100644 index 0000000..e9b8c6a --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDASLLogger.m @@ -0,0 +1,133 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +#if !TARGET_OS_WATCH + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +#import + +#import + +const char* const kDDASLKeyDDLog = "DDLog"; +const char* const kDDASLDDLogValue = "1"; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +static DDASLLogger *sharedInstance; +#pragma clang diagnostic pop + +@interface DDASLLogger () { + aslclient _client; +} + +@end + + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +@implementation DDASLLogger +#pragma clang diagnostic pop + ++ (instancetype)sharedInstance { + static dispatch_once_t DDASLLoggerOnceToken; + + dispatch_once(&DDASLLoggerOnceToken, ^{ + sharedInstance = [[[self class] alloc] init]; + }); + + return sharedInstance; +} + +- (instancetype)init { + if (sharedInstance != nil) { + return nil; + } + + if ((self = [super init])) { + // A default asl client is provided for the main thread, + // but background threads need to create their own client. + + _client = asl_open(NULL, "com.apple.console", 0); + } + + return self; +} + +- (DDLoggerName)loggerName { + return DDLoggerNameASL; +} + +- (void)logMessage:(DDLogMessage *)logMessage { + // Skip captured log messages + if ([logMessage->_fileName isEqualToString:@"DDASLLogCapture"]) { + return; + } + + __auto_type message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message; + + if (message) { + __auto_type msg = [message UTF8String]; + + size_t aslLogLevel; + switch (logMessage->_flag) { + // Note: By default ASL will filter anything above level 5 (Notice). + // So our mappings shouldn't go above that level. + case DDLogFlagError : aslLogLevel = ASL_LEVEL_CRIT; break; + case DDLogFlagWarning : aslLogLevel = ASL_LEVEL_ERR; break; + case DDLogFlagInfo : aslLogLevel = ASL_LEVEL_WARNING; break; // Regular NSLog's level + case DDLogFlagDebug : + case DDLogFlagVerbose : + default : aslLogLevel = ASL_LEVEL_NOTICE; break; + } + + static char const *const level_strings[] = { "0", "1", "2", "3", "4", "5", "6", "7" }; + + // NSLog uses the current euid to set the ASL_KEY_READ_UID. + const __auto_type readUID = geteuid(); + + char readUIDString[16]; +#ifndef NS_BLOCK_ASSERTIONS + __auto_type l = (size_t)snprintf(readUIDString, sizeof(readUIDString), "%d", readUID); +#else + snprintf(readUIDString, sizeof(readUIDString), "%d", readUID); +#endif + + NSAssert(l < sizeof(readUIDString), + @"Formatted euid is too long."); + NSAssert(aslLogLevel < (sizeof(level_strings) / sizeof(level_strings[0])), + @"Unhandled ASL log level."); + + __auto_type m = asl_new(ASL_TYPE_MSG); + if (m != NULL) { + if (asl_set(m, ASL_KEY_LEVEL, level_strings[aslLogLevel]) == 0 && + asl_set(m, ASL_KEY_MSG, msg) == 0 && + asl_set(m, ASL_KEY_READ_UID, readUIDString) == 0 && + asl_set(m, kDDASLKeyDDLog, kDDASLDDLogValue) == 0) { + asl_send(_client, m); + } + asl_free(m); + } + //TODO handle asl_* failures non-silently? + } +} + +@end + +#endif diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDAbstractDatabaseLogger.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDAbstractDatabaseLogger.m new file mode 100644 index 0000000..232846a --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDAbstractDatabaseLogger.m @@ -0,0 +1,636 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +#import + +@interface DDAbstractDatabaseLogger () + +- (void)destroySaveTimer; +- (void)updateAndResumeSaveTimer; +- (void)createSuspendedSaveTimer; +- (void)destroyDeleteTimer; +- (void)updateDeleteTimer; +- (void)createAndStartDeleteTimer; + +@end + +#pragma mark - + +@implementation DDAbstractDatabaseLogger + +- (instancetype)init { + if ((self = [super init])) { + _saveThreshold = 500; + _saveInterval = 60; // 60 seconds + _maxAge = (60 * 60 * 24 * 7); // 7 days + _deleteInterval = (60 * 5); // 5 minutes + } + + return self; +} + +- (void)dealloc { + [self destroySaveTimer]; + [self destroyDeleteTimer]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Override Me +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)db_log:(__unused DDLogMessage *)logMessage { + // Override me and add your implementation. + // + // Return YES if an item was added to the buffer. + // Return NO if the logMessage was ignored. + + return NO; +} + +- (void)db_save { + // Override me and add your implementation. +} + +- (void)db_delete { + // Override me and add your implementation. +} + +- (void)db_saveAndDelete { + // Override me and add your implementation. +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Private API +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)performSaveAndSuspendSaveTimer { + if (_unsavedCount > 0) { + if (_deleteOnEverySave) { + [self db_saveAndDelete]; + } else { + [self db_save]; + } + } + + _unsavedCount = 0; + _unsavedTime = 0; + + if (_saveTimer != NULL && _saveTimerSuspended == 0) { + dispatch_suspend(_saveTimer); + _saveTimerSuspended = 1; + } +} + +- (void)performDelete { + if (_maxAge > 0.0) { + [self db_delete]; + + _lastDeleteTime = dispatch_time(DISPATCH_TIME_NOW, 0); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Timers +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)destroySaveTimer { + if (_saveTimer != NULL) { + dispatch_source_cancel(_saveTimer); + + // Must activate a timer before releasing it (or it will crash) + if (_saveTimerSuspended < 0) { + dispatch_activate(_saveTimer); + } else if (_saveTimerSuspended > 0) { + dispatch_resume(_saveTimer); + } + +#if !OS_OBJECT_USE_OBJC + dispatch_release(_saveTimer); +#endif + _saveTimer = NULL; + _saveTimerSuspended = 0; + } +} + +- (void)updateAndResumeSaveTimer { + if ((_saveTimer != NULL) && (_saveInterval > 0.0) && (_unsavedTime > 0)) { + __auto_type interval = (uint64_t)(_saveInterval * (NSTimeInterval) NSEC_PER_SEC); + __auto_type startTime = dispatch_time(_unsavedTime, (int64_t)interval); + + dispatch_source_set_timer(_saveTimer, startTime, interval, 1ull * NSEC_PER_SEC); + + if (_saveTimerSuspended < 0) { + dispatch_activate(_saveTimer); + _saveTimerSuspended = 0; + } else if (_saveTimerSuspended > 0) { + dispatch_resume(_saveTimer); + _saveTimerSuspended = 0; + } + } +} + +- (void)createSuspendedSaveTimer { + if ((_saveTimer == NULL) && (_saveInterval > 0.0)) { + _saveTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue); + + dispatch_source_set_event_handler(_saveTimer, ^{ @autoreleasepool { + [self performSaveAndSuspendSaveTimer]; + } }); + + _saveTimerSuspended = -1; + } +} + +- (void)destroyDeleteTimer { + if (_deleteTimer != NULL) { + dispatch_source_cancel(_deleteTimer); +#if !OS_OBJECT_USE_OBJC + dispatch_release(_deleteTimer); +#endif + _deleteTimer = NULL; + } +} + +- (void)updateDeleteTimer { + if ((_deleteTimer != NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) { + __auto_type interval = (int64_t)(_deleteInterval * (NSTimeInterval) NSEC_PER_SEC); + dispatch_time_t startTime; + + if (_lastDeleteTime > 0) { + startTime = dispatch_time(_lastDeleteTime, interval); + } else { + startTime = dispatch_time(DISPATCH_TIME_NOW, interval); + } + + dispatch_source_set_timer(_deleteTimer, startTime, (uint64_t)interval, 1ull * NSEC_PER_SEC); + } +} + +- (void)createAndStartDeleteTimer { + if ((_deleteTimer == NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) { + _deleteTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue); + + if (_deleteTimer != NULL) { + dispatch_source_set_event_handler(_deleteTimer, ^{ @autoreleasepool { + [self performDelete]; + } }); + + [self updateDeleteTimer]; + + // We are sure that -updateDeleteTimer did call dispatch_source_set_timer() + // since it has the same guards on _deleteInterval and _maxAge + dispatch_activate(_deleteTimer); + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Configuration +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSUInteger)saveThreshold { + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + __block NSUInteger result; + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = self->_saveThreshold; + }); + }); + + return result; +} + +- (void)setSaveThreshold:(NSUInteger)threshold { + dispatch_block_t block = ^{ + @autoreleasepool { + if (self->_saveThreshold != threshold) { + self->_saveThreshold = threshold; + + // Since the saveThreshold has changed, + // we check to see if the current unsavedCount has surpassed the new threshold. + // + // If it has, we immediately save the log. + + if ((self->_unsavedCount >= self->_saveThreshold) && (self->_saveThreshold > 0)) { + [self performSaveAndSuspendSaveTimer]; + } + } + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (NSTimeInterval)saveInterval { + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + __block NSTimeInterval result; + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = self->_saveInterval; + }); + }); + + return result; +} + +- (void)setSaveInterval:(NSTimeInterval)interval { + __auto_type block = ^{ + @autoreleasepool { + // C99 recommended floating point comparison macro + // Read: isLessThanOrGreaterThan(floatA, floatB) + + if (/* saveInterval != interval */ islessgreater(self->_saveInterval, interval)) { + self->_saveInterval = interval; + + // There are several cases we need to handle here. + // + // 1. If the saveInterval was previously enabled and it just got disabled, + // then we need to stop the saveTimer. (And we might as well release it.) + // + // 2. If the saveInterval was previously disabled and it just got enabled, + // then we need to setup the saveTimer. (Plus we might need to do an immediate save.) + // + // 3. If the saveInterval increased, then we need to reset the timer so that it fires at the later date. + // + // 4. If the saveInterval decreased, then we need to reset the timer so that it fires at an earlier date. + // (Plus we might need to do an immediate save.) + + if (self->_saveInterval > 0.0) { + if (self->_saveTimer == NULL) { + // Handles #2 + // + // Since the saveTimer uses the unsavedTime to calculate it's first fireDate, + // if a save is needed the timer will fire immediately. + + [self createSuspendedSaveTimer]; + [self updateAndResumeSaveTimer]; + } else { + // Handles #3 + // Handles #4 + // + // Since the saveTimer uses the unsavedTime to calculate it's first fireDate, + // if a save is needed the timer will fire immediately. + + [self updateAndResumeSaveTimer]; + } + } else if (self->_saveTimer) { + // Handles #1 + + [self destroySaveTimer]; + } + } + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (NSTimeInterval)maxAge { + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + __block NSTimeInterval result; + + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = self->_maxAge; + }); + }); + + return result; +} + +- (void)setMaxAge:(NSTimeInterval)interval { + __auto_type block = ^{ + @autoreleasepool { + // C99 recommended floating point comparison macro + // Read: isLessThanOrGreaterThan(floatA, floatB) + + if (/* maxAge != interval */ islessgreater(self->_maxAge, interval)) { + __auto_type oldMaxAge = self->_maxAge; + __auto_type newMaxAge = interval; + + self->_maxAge = interval; + + // There are several cases we need to handle here. + // + // 1. If the maxAge was previously enabled and it just got disabled, + // then we need to stop the deleteTimer. (And we might as well release it.) + // + // 2. If the maxAge was previously disabled and it just got enabled, + // then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.) + // + // 3. If the maxAge was increased, + // then we don't need to do anything. + // + // 4. If the maxAge was decreased, + // then we should do an immediate delete. + + __auto_type shouldDeleteNow = NO; + + if (oldMaxAge > 0.0) { + if (newMaxAge <= 0.0) { + // Handles #1 + + [self destroyDeleteTimer]; + } else if (oldMaxAge > newMaxAge) { + // Handles #4 + shouldDeleteNow = YES; + } + } else if (newMaxAge > 0.0) { + // Handles #2 + shouldDeleteNow = YES; + } + + if (shouldDeleteNow) { + [self performDelete]; + + if (self->_deleteTimer) { + [self updateDeleteTimer]; + } else { + [self createAndStartDeleteTimer]; + } + } + } + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (NSTimeInterval)deleteInterval { + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + __block NSTimeInterval result; + + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = self->_deleteInterval; + }); + }); + + return result; +} + +- (void)setDeleteInterval:(NSTimeInterval)interval { + __auto_type block = ^{ + @autoreleasepool { + // C99 recommended floating point comparison macro + // Read: isLessThanOrGreaterThan(floatA, floatB) + + if (/* deleteInterval != interval */ islessgreater(self->_deleteInterval, interval)) { + self->_deleteInterval = interval; + + // There are several cases we need to handle here. + // + // 1. If the deleteInterval was previously enabled and it just got disabled, + // then we need to stop the deleteTimer. (And we might as well release it.) + // + // 2. If the deleteInterval was previously disabled and it just got enabled, + // then we need to setup the deleteTimer. (Plus we might need to do an immediate delete.) + // + // 3. If the deleteInterval increased, then we need to reset the timer so that it fires at the later date. + // + // 4. If the deleteInterval decreased, then we need to reset the timer so that it fires at an earlier date. + // (Plus we might need to do an immediate delete.) + + if (self->_deleteInterval > 0.0) { + if (self->_deleteTimer == NULL) { + // Handles #2 + // + // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate, + // if a delete is needed the timer will fire immediately. + + [self createAndStartDeleteTimer]; + } else { + // Handles #3 + // Handles #4 + // + // Since the deleteTimer uses the lastDeleteTime to calculate it's first fireDate, + // if a save is needed the timer will fire immediately. + + [self updateDeleteTimer]; + } + } else if (self->_deleteTimer) { + // Handles #1 + + [self destroyDeleteTimer]; + } + } + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (BOOL)deleteOnEverySave { + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + __block BOOL result; + + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = self->_deleteOnEverySave; + }); + }); + + return result; +} + +- (void)setDeleteOnEverySave:(BOOL)flag { + __auto_type block = ^{ + self->_deleteOnEverySave = flag; + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Public API +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)savePendingLogEntries { + __auto_type block = ^{ + @autoreleasepool { + [self performSaveAndSuspendSaveTimer]; + } + }; + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_async(self.loggerQueue, block); + } +} + +- (void)deleteOldLogEntries { + __auto_type block = ^{ + @autoreleasepool { + [self performDelete]; + } + }; + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_async(self.loggerQueue, block); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark DDLogger +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)didAddLogger { + // If you override me be sure to invoke [super didAddLogger]; + [self createSuspendedSaveTimer]; + [self createAndStartDeleteTimer]; +} + +- (void)willRemoveLogger { + // If you override me be sure to invoke [super willRemoveLogger]; + [self performSaveAndSuspendSaveTimer]; + [self destroySaveTimer]; + [self destroyDeleteTimer]; +} + +- (void)logMessage:(DDLogMessage *)logMessage { + if ([self db_log:logMessage]) { + __auto_type firstUnsavedEntry = (++_unsavedCount == 1); + + if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) { + [self performSaveAndSuspendSaveTimer]; + } else if (firstUnsavedEntry) { + _unsavedTime = dispatch_time(DISPATCH_TIME_NOW, 0); + [self updateAndResumeSaveTimer]; + } + } +} + +- (void)flush { + // This method is invoked by DDLog's flushLog method. + // + // It is called automatically when the application quits, + // or if the developer invokes DDLog's flushLog method prior to crashing or something. + [self performSaveAndSuspendSaveTimer]; +} + +@end diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDFileLogger+Internal.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDFileLogger+Internal.h new file mode 100644 index 0000000..0ca0609 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDFileLogger+Internal.h @@ -0,0 +1,31 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DDFileLogger (Internal) + +- (void)logData:(NSData *)data; + +// Will assert if used outside logger's queue. +- (void)lt_logData:(NSData *)data; + +- (nullable NSData *)lt_dataForMessage:(DDLogMessage *)message; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDFileLogger.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDFileLogger.m new file mode 100644 index 0000000..5caee8c --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDFileLogger.m @@ -0,0 +1,1865 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +#import +#import +#import +#import + +#import "DDFileLogger+Internal.h" + +// We probably shouldn't be using DDLog() statements within the DDLog implementation. +// But we still want to leave our log statements for any future debugging, +// and to allow other developers to trace the implementation (which is a great learning tool). +// +// So we use primitive logging macros around NSLog. +// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog. + +#ifndef DD_NSLOG_LEVEL + #define DD_NSLOG_LEVEL 2 +#endif + +#define NSLogError(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0) +#define NSLogWarn(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0) +#define NSLogInfo(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0) +#define NSLogDebug(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0) +#define NSLogVerbose(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0) + + +#if TARGET_OS_IPHONE +BOOL doesAppRunInBackground(void); +#endif + +unsigned long long const kDDDefaultLogMaxFileSize = 1024 * 1024; // 1 MB +NSTimeInterval const kDDDefaultLogRollingFrequency = 60 * 60 * 24; // 24 Hours +NSUInteger const kDDDefaultLogMaxNumLogFiles = 5; // 5 Files +unsigned long long const kDDDefaultLogFilesDiskQuota = 20 * 1024 * 1024; // 20 MB + +NSTimeInterval const kDDRollingLeeway = 1.0; // 1s + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation DDFileLogPlainTextMessageSerializer + +- (instancetype)init { + return [super init]; +} + +- (NSData *)dataForString:(NSString *)string originatingFromMessage:(DDLogMessage *)message { + return [string dataUsingEncoding:NSUTF8StringEncoding] ?: [NSData data]; +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface DDLogFileManagerDefault () { + NSDateFormatter *_fileDateFormatter; + NSUInteger _maximumNumberOfLogFiles; + unsigned long long _logFilesDiskQuota; + NSString *_logsDirectory; + BOOL _wasAddedToLogger; +#if TARGET_OS_IPHONE + NSFileProtectionType _defaultFileProtectionLevel; +#endif +} + +@end + +@implementation DDLogFileManagerDefault + +@synthesize maximumNumberOfLogFiles = _maximumNumberOfLogFiles; +@synthesize logFilesDiskQuota = _logFilesDiskQuota; +@synthesize logMessageSerializer = _logMessageSerializer; + +- (instancetype)initWithLogsDirectory:(nullable NSString *)aLogsDirectory { + if ((self = [super init])) { + _maximumNumberOfLogFiles = kDDDefaultLogMaxNumLogFiles; + _logFilesDiskQuota = kDDDefaultLogFilesDiskQuota; + _wasAddedToLogger = NO; + + _fileDateFormatter = [[NSDateFormatter alloc] init]; + [_fileDateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]]; + [_fileDateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + [_fileDateFormatter setDateFormat: @"yyyy'-'MM'-'dd'--'HH'-'mm'-'ss'-'SSS'"]; + + if (aLogsDirectory.length > 0) { + _logsDirectory = [aLogsDirectory copy]; + } else { + _logsDirectory = [[self defaultLogsDirectory] copy]; + } + + _logMessageSerializer = [[DDFileLogPlainTextMessageSerializer alloc] init]; + + NSLogVerbose(@"DDFileLogManagerDefault: logsDirectory:\n%@", [self logsDirectory]); + NSLogVerbose(@"DDFileLogManagerDefault: sortedLogFileNames:\n%@", [self sortedLogFileNames]); + } + + return self; +} + +#if TARGET_OS_IPHONE +- (instancetype)initWithLogsDirectory:(NSString *)logsDirectory + defaultFileProtectionLevel:(NSFileProtectionType)fileProtectionLevel { + + if ((self = [self initWithLogsDirectory:logsDirectory])) { + if ([fileProtectionLevel isEqualToString:NSFileProtectionNone] || + [fileProtectionLevel isEqualToString:NSFileProtectionComplete] || + [fileProtectionLevel isEqualToString:NSFileProtectionCompleteUnlessOpen] || + [fileProtectionLevel isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication]) { + _defaultFileProtectionLevel = fileProtectionLevel; + } + } + + return self; +} +#endif + +- (instancetype)init { + return [self initWithLogsDirectory:nil]; +} + +- (void)didAddToFileLogger:(DDFileLogger *)fileLogger { + _wasAddedToLogger = YES; +} + +- (void)deleteOldFilesForConfigurationChange { + if (!_wasAddedToLogger) return; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + @autoreleasepool { + // See method header for queue reasoning. + [self deleteOldLogFilesWithError:nil]; + } + }); +} + +- (void)setLogFilesDiskQuota:(unsigned long long)logFilesDiskQuota { + if (_logFilesDiskQuota != logFilesDiskQuota) { + _logFilesDiskQuota = logFilesDiskQuota; + NSLogInfo(@"DDFileLogManagerDefault: Responding to configuration change: logFilesDiskQuota"); + [self deleteOldFilesForConfigurationChange]; + } +} + +- (void)setMaximumNumberOfLogFiles:(NSUInteger)maximumNumberOfLogFiles { + if (_maximumNumberOfLogFiles != maximumNumberOfLogFiles) { + _maximumNumberOfLogFiles = maximumNumberOfLogFiles; + NSLogInfo(@"DDFileLogManagerDefault: Responding to configuration change: maximumNumberOfLogFiles"); + [self deleteOldFilesForConfigurationChange]; + } +} + +#if TARGET_OS_IPHONE +- (NSFileProtectionType)logFileProtection { + if (_defaultFileProtectionLevel.length > 0) { + return _defaultFileProtectionLevel; + } else if (doesAppRunInBackground()) { + return NSFileProtectionCompleteUntilFirstUserAuthentication; + } else { + return NSFileProtectionCompleteUnlessOpen; + } +} +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark File Deleting +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Deletes archived log files that exceed the maximumNumberOfLogFiles or logFilesDiskQuota configuration values. + * Method may take a while to execute since we're performing IO. It's not critical that this is synchronized with + * log output, since the files we're deleting are all archived and not in use, therefore this method is called on a + * background queue. + **/ +- (BOOL)deleteOldLogFilesWithError:(NSError *__autoreleasing _Nullable *)error { + NSLogVerbose(@"DDLogFileManagerDefault: %@", NSStringFromSelector(_cmd)); + + if (error) *error = nil; + + __auto_type sortedLogFileInfos = [self sortedLogFileInfos]; + NSUInteger firstIndexToDelete = NSNotFound; + + const unsigned long long diskQuota = self.logFilesDiskQuota; + const NSUInteger maxNumLogFiles = self.maximumNumberOfLogFiles; + + if (diskQuota) { + unsigned long long used = 0; + + for (NSUInteger i = 0; i < sortedLogFileInfos.count; i++) { + DDLogFileInfo *info = sortedLogFileInfos[i]; + used += info.fileSize; + + if (used > diskQuota) { + firstIndexToDelete = i; + break; + } + } + } + + if (maxNumLogFiles) { + if (firstIndexToDelete == NSNotFound) { + firstIndexToDelete = maxNumLogFiles; + } else { + firstIndexToDelete = MIN(firstIndexToDelete, maxNumLogFiles); + } + } + + if (firstIndexToDelete == 0) { + // Do we consider the first file? + // We are only supposed to be deleting archived files. + // In most cases, the first file is likely the log file that is currently being written to. + // So in most cases, we do not want to consider this file for deletion. + + if (sortedLogFileInfos.count > 0) { + if (!sortedLogFileInfos[0].isArchived) { + // Don't delete active file. + firstIndexToDelete++; + } + } + } + + if (firstIndexToDelete != NSNotFound) { + // removing all log files starting with firstIndexToDelete + for (NSUInteger i = firstIndexToDelete; i < sortedLogFileInfos.count; i++) { + __auto_type logFileInfo = sortedLogFileInfos[i]; + + __autoreleasing NSError *deletionError = nil; + __auto_type success = [[NSFileManager defaultManager] removeItemAtPath:logFileInfo.filePath error:&deletionError]; + if (success) { + NSLogInfo(@"DDLogFileManagerDefault: Deleting file: %@", logFileInfo.fileName); + } else { + NSLogError(@"DDLogFileManagerDefault: Error deleting file %@", deletionError); + if (error) { + *error = deletionError; + return NO; // If we were given an error, stop after the first failure! + } + } + } + } + + return YES; +} + +- (BOOL)cleanupLogFilesWithError:(NSError *__autoreleasing _Nullable *)error { + return [self deleteOldLogFilesWithError:error]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Log Files +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Returns the path to the default logs directory. + * If the logs directory doesn't exist, this method automatically creates it. + **/ +- (NSString *)defaultLogsDirectory { +#if TARGET_OS_IPHONE + __auto_type paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + __auto_type baseDir = paths.firstObject; + __auto_type logsDirectory = [baseDir stringByAppendingPathComponent:@"Logs"]; +#else + __auto_type appName = [[NSProcessInfo processInfo] processName]; + __auto_type paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); + __auto_type basePath = ([paths count] > 0) ? paths[0] : NSTemporaryDirectory(); + __auto_type logsDirectory = [[basePath stringByAppendingPathComponent:@"Logs"] stringByAppendingPathComponent:appName]; +#endif + + return logsDirectory; +} + +- (NSString *)logsDirectory { + // We could do this check once, during initialization, and not bother again. + // But this way the code continues to work if the directory gets deleted while the code is running. + + NSAssert(_logsDirectory.length > 0, @"Directory must be set."); + + __autoreleasing NSError *error = nil; + __auto_type success = [[NSFileManager defaultManager] createDirectoryAtPath:_logsDirectory + withIntermediateDirectories:YES + attributes:nil + error:&error]; + if (!success) { + NSLogError(@"DDFileLogManagerDefault: Error creating logsDirectory: %@", error); + } + + return _logsDirectory; +} + +- (BOOL)isLogFile:(NSString *)fileName { + __auto_type appName = [self applicationName]; + + // We need to add a space to the name as otherwise we could match applications that have the name prefix. + return [fileName hasPrefix:[appName stringByAppendingString:@" "]] && [fileName hasSuffix:@".log"]; +} + +// if you change formatter, then change sortedLogFileInfos method also accordingly +- (NSDateFormatter *)logFileDateFormatter { + return _fileDateFormatter; +} + +- (NSArray *)unsortedLogFilePaths { + __auto_type logsDirectory = [self logsDirectory]; + + __autoreleasing NSError *error = nil; + __auto_type fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logsDirectory error:&error]; + if (!fileNames && error) { + NSLogError(@"DDFileLogManagerDefault: Error listing log file directory: %@", error); + return [[NSArray alloc] init]; + } + + __auto_type unsortedLogFilePaths = [NSMutableArray arrayWithCapacity:[fileNames count]]; + + for (NSString *fileName in fileNames) { + // Filter out any files that aren't log files. (Just for extra safety) +#if TARGET_IPHONE_SIMULATOR + // This is only used on the iPhone simulator for backward compatibility reason. + // + // In case of iPhone simulator there can be 'archived' extension. isLogFile: + // method knows nothing about it. Thus removing it for this method. + __auto_type theFileName = [fileName stringByReplacingOccurrencesOfString:@".archived" + withString:@""]; + + if ([self isLogFile:theFileName]) +#else + if ([self isLogFile:fileName]) +#endif + { + __auto_type filePath = [logsDirectory stringByAppendingPathComponent:fileName]; + [unsortedLogFilePaths addObject:filePath]; + } + } + + return unsortedLogFilePaths; +} + +- (NSArray *)unsortedLogFileNames { + __auto_type unsortedLogFilePaths = [self unsortedLogFilePaths]; + __auto_type unsortedLogFileNames = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]]; + + for (NSString *filePath in unsortedLogFilePaths) { + [unsortedLogFileNames addObject:[filePath lastPathComponent]]; + } + + return unsortedLogFileNames; +} + +- (NSArray *)unsortedLogFileInfos { + __auto_type unsortedLogFilePaths = [self unsortedLogFilePaths]; + __auto_type unsortedLogFileInfos = [NSMutableArray arrayWithCapacity:[unsortedLogFilePaths count]]; + + for (NSString *filePath in unsortedLogFilePaths) { + __auto_type logFileInfo = [[DDLogFileInfo alloc] initWithFilePath:filePath]; + [unsortedLogFileInfos addObject:logFileInfo]; + } + + return unsortedLogFileInfos; +} + +- (NSArray *)sortedLogFilePaths { + __auto_type sortedLogFileInfos = [self sortedLogFileInfos]; + __auto_type sortedLogFilePaths = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]]; + + for (DDLogFileInfo *logFileInfo in sortedLogFileInfos) { + [sortedLogFilePaths addObject:[logFileInfo filePath]]; + } + + return sortedLogFilePaths; +} + +- (NSArray *)sortedLogFileNames { + __auto_type sortedLogFileInfos = [self sortedLogFileInfos]; + __auto_type sortedLogFileNames = [NSMutableArray arrayWithCapacity:[sortedLogFileInfos count]]; + + for (DDLogFileInfo *logFileInfo in sortedLogFileInfos) { + [sortedLogFileNames addObject:[logFileInfo fileName]]; + } + + return sortedLogFileNames; +} + +- (NSArray *)sortedLogFileInfos { + return [[self unsortedLogFileInfos] sortedArrayUsingComparator:^NSComparisonResult(DDLogFileInfo *obj1, + DDLogFileInfo *obj2) { + NSDate *date1 = [NSDate date]; + NSDate *date2 = [NSDate date]; + + __auto_type arrayComponent = [[obj1 fileName] componentsSeparatedByString:@" "]; + if (arrayComponent.count > 0) { + NSString *stringDate = arrayComponent.lastObject; + stringDate = [stringDate stringByReplacingOccurrencesOfString:@".log" withString:@""]; +#if TARGET_IPHONE_SIMULATOR + // This is only used on the iPhone simulator for backward compatibility reason. + stringDate = [stringDate stringByReplacingOccurrencesOfString:@".archived" withString:@""]; +#endif + date1 = [[self logFileDateFormatter] dateFromString:stringDate] ?: [obj1 creationDate]; + } + + arrayComponent = [[obj2 fileName] componentsSeparatedByString:@" "]; + if (arrayComponent.count > 0) { + NSString *stringDate = arrayComponent.lastObject; + stringDate = [stringDate stringByReplacingOccurrencesOfString:@".log" withString:@""]; +#if TARGET_IPHONE_SIMULATOR + // This is only used on the iPhone simulator for backward compatibility reason. + stringDate = [stringDate stringByReplacingOccurrencesOfString:@".archived" withString:@""]; +#endif + date2 = [[self logFileDateFormatter] dateFromString:stringDate] ?: [obj2 creationDate]; + } + + return [date2 compare:date1 ?: [NSDate date]]; + }]; + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Creation +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// If you change newLogFileName, then change `isLogFile:` method also accordingly. +- (NSString *)newLogFileName { + __auto_type appName = [self applicationName]; + __auto_type dateFormatter = [self logFileDateFormatter]; + __auto_type formattedDate = [dateFormatter stringFromDate:[NSDate date]]; + + return [NSString stringWithFormat:@"%@ %@.log", appName, formattedDate]; +} + +- (nullable NSString *)logFileHeader { + return nil; +} + +- (NSData *)logFileHeaderData { + NSString *fileHeaderStr = [self logFileHeader]; + + if (fileHeaderStr.length == 0) { + return nil; + } + + if (![fileHeaderStr hasSuffix:@"\n"]) { + fileHeaderStr = [fileHeaderStr stringByAppendingString:@"\n"]; + } + + return [_logMessageSerializer dataForString:fileHeaderStr originatingFromMessage:nil]; +} + +- (NSString *)createNewLogFileWithError:(NSError *__autoreleasing _Nullable *)error { + static NSUInteger MAX_ALLOWED_ERROR = 5; + + __auto_type fileName = [self newLogFileName]; + __auto_type logsDirectory = [self logsDirectory]; + __auto_type fileHeader = [self logFileHeaderData] ?: [NSData data]; + + NSString *baseName = nil; + NSString *extension; + NSUInteger attempt = 1; + NSUInteger criticalErrors = 0; + NSError *lastCriticalError; + + if (error) *error = nil; + do { + if (criticalErrors >= MAX_ALLOWED_ERROR) { + NSLogError(@"DDLogFileManagerDefault: Bailing file creation, encountered %ld errors.", + (unsigned long)criticalErrors); + if (error) *error = lastCriticalError; + return nil; + } + + NSString *actualFileName; + if (attempt > 1) { + if (baseName == nil) { + baseName = [fileName stringByDeletingPathExtension]; + extension = [fileName pathExtension]; + } + + actualFileName = [baseName stringByAppendingFormat:@" %lu", (unsigned long)attempt]; + if (extension.length) { + actualFileName = [actualFileName stringByAppendingPathExtension:extension]; + } + } else { + actualFileName = fileName; + } + + __auto_type filePath = [logsDirectory stringByAppendingPathComponent:actualFileName]; + + __autoreleasing NSError *currentError = nil; + __auto_type success = [fileHeader writeToFile:filePath options:NSDataWritingAtomic error:¤tError]; + +#if TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST + if (success) { + // When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen. + // + // But in case if app is able to launch from background we need to have an ability to open log file any time we + // want (even if device is locked). Thats why that attribute have to be changed to + // NSFileProtectionCompleteUntilFirstUserAuthentication. + NSDictionary *attributes = @{NSFileProtectionKey: [self logFileProtection]}; + success = [[NSFileManager defaultManager] setAttributes:attributes + ofItemAtPath:filePath + error:¤tError]; + } +#endif + + if (success) { + NSLogVerbose(@"DDLogFileManagerDefault: Created new log file: %@", actualFileName); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + // Since we just created a new log file, we may need to delete some old log files + // Note that we don't on errors here! The new log file was created, so this method technically succeeded! + [self deleteOldLogFilesWithError:nil]; + }); + return filePath; + } else if (currentError.code == NSFileWriteFileExistsError) { + attempt++; + } else { + NSLogError(@"DDLogFileManagerDefault: Critical error while creating log file: %@", currentError); + criticalErrors++; + lastCriticalError = currentError; + } + } while (YES); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Utility +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSString *)applicationName { + static NSString *_appName; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + _appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; + + if (_appName.length == 0) { + _appName = [[NSProcessInfo processInfo] processName]; + } + + if (_appName.length == 0) { + _appName = @""; + } + }); + + return _appName; +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface DDLogFileFormatterDefault () { + NSDateFormatter *_dateFormatter; +} + +@end + +@implementation DDLogFileFormatterDefault + +- (instancetype)init { + return [self initWithDateFormatter:nil]; +} + +- (instancetype)initWithDateFormatter:(nullable NSDateFormatter *)aDateFormatter { + if ((self = [super init])) { + if (aDateFormatter) { + _dateFormatter = aDateFormatter; + } else { + _dateFormatter = [[NSDateFormatter alloc] init]; + [_dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; // 10.4+ style + [_dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]]; + [_dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + [_dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss:SSS"]; + } + } + + return self; +} + +- (NSString *)formatLogMessage:(DDLogMessage *)logMessage { + __auto_type dateAndTime = [_dateFormatter stringFromDate:logMessage->_timestamp]; + // Note: There are two spaces between the date and the message. + return [NSString stringWithFormat:@"%@ %@", dateAndTime, logMessage->_message]; +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface DDFileLogger () { + id _logFileManager; + + DDLogFileInfo *_currentLogFileInfo; + NSFileHandle *_currentLogFileHandle; + + dispatch_source_t _currentLogFileVnode; + + NSTimeInterval _rollingFrequency; + dispatch_source_t _rollingTimer; + + unsigned long long _maximumFileSize; + + dispatch_queue_t _completionQueue; +} + +@end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincomplete-implementation" +@implementation DDFileLogger +#pragma clang diagnostic pop + +- (instancetype)init { + return [self initWithLogFileManager:[[DDLogFileManagerDefault alloc] init] + completionQueue:nil]; +} + +- (instancetype)initWithLogFileManager:(id)logFileManager { + return [self initWithLogFileManager:logFileManager completionQueue:nil]; +} + +- (instancetype)initWithLogFileManager:(id )aLogFileManager + completionQueue:(nullable dispatch_queue_t)dispatchQueue { + if ((self = [super init])) { + _completionQueue = dispatchQueue ?: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + _maximumFileSize = kDDDefaultLogMaxFileSize; + _rollingFrequency = kDDDefaultLogRollingFrequency; + _automaticallyAppendNewlineForCustomFormatters = YES; + + _logFileManager = aLogFileManager; + _logFormatter = [DDLogFileFormatterDefault new]; + + if ([_logFileManager respondsToSelector:@selector(didAddToFileLogger:)]) { + [_logFileManager didAddToFileLogger:self]; + } + } + + return self; +} + +- (void)lt_cleanup { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + if (_currentLogFileHandle != nil) { + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)) { + __autoreleasing NSError *error = nil; + __auto_type success = [_currentLogFileHandle synchronizeAndReturnError:&error]; + if (!success) { + NSLogError(@"DDFileLogger: Failed to synchronize file: %@", error); + } + success = [_currentLogFileHandle closeAndReturnError:&error]; + if (!success) { + NSLogError(@"DDFileLogger: Failed to close file: %@", error); + } + } else { + @try { + [_currentLogFileHandle synchronizeFile]; + } + @catch (NSException *exception) { + NSLogError(@"DDFileLogger: Failed to synchronize file: %@", exception); + } + [_currentLogFileHandle closeFile]; + } + _currentLogFileHandle = nil; + } + + if (_currentLogFileVnode) { + dispatch_source_cancel(_currentLogFileVnode); + _currentLogFileVnode = NULL; + } + + if (_rollingTimer) { + dispatch_source_cancel(_rollingTimer); + _rollingTimer = NULL; + } +} + +- (void)dealloc { + if (self.isOnInternalLoggerQueue) { + [self lt_cleanup]; + } else { + dispatch_sync(self.loggerQueue, ^{ + [self lt_cleanup]; + }); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Properties +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (unsigned long long)maximumFileSize { + __block unsigned long long result; + + __auto_type block = ^{ + result = self->_maximumFileSize; + }; + + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation MUST access the maximumFileSize variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, block); + }); + + return result; +} + +- (void)setMaximumFileSize:(unsigned long long)newMaximumFileSize { + __auto_type block = ^{ + @autoreleasepool { + self->_maximumFileSize = newMaximumFileSize; + if (self->_currentLogFileHandle != nil) { + [self lt_maybeRollLogFileDueToSize]; + } + } + }; + + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation MUST access the maximumFileSize variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); +} + +- (NSTimeInterval)rollingFrequency { + __block NSTimeInterval result; + + __auto_type block = ^{ + result = self->_rollingFrequency; + }; + + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation should access the rollingFrequency variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, block); + }); + + return result; +} + +- (void)setRollingFrequency:(NSTimeInterval)newRollingFrequency { + __auto_type block = ^{ + @autoreleasepool { + self->_rollingFrequency = newRollingFrequency; + if (self->_currentLogFileHandle != nil) { + [self lt_maybeRollLogFileDueToAge]; + } + } + }; + + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation should access the rollingFrequency variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark File Rolling +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)lt_scheduleTimerToRollLogFileDueToAge { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + if (_rollingTimer) { + dispatch_source_cancel(_rollingTimer); + _rollingTimer = NULL; + } + + if (_currentLogFileInfo == nil || _rollingFrequency <= 0.0) { + return; + } + + __auto_type logFileCreationDate = [_currentLogFileInfo creationDate]; + __auto_type frequency = MIN(_rollingFrequency, DBL_MAX - [logFileCreationDate timeIntervalSinceReferenceDate]); + __auto_type logFileRollingDate = [logFileCreationDate dateByAddingTimeInterval:frequency]; + + NSLogVerbose(@"DDFileLogger: scheduleTimerToRollLogFileDueToAge"); + NSLogVerbose(@"DDFileLogger: logFileCreationDate : %@", logFileCreationDate); + NSLogVerbose(@"DDFileLogger: actual rollingFrequency: %f", frequency); + NSLogVerbose(@"DDFileLogger: logFileRollingDate : %@", logFileRollingDate); + + _rollingTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _loggerQueue); + + __weak __auto_type weakSelf = self; + dispatch_source_set_event_handler(_rollingTimer, ^{ @autoreleasepool { + [weakSelf lt_maybeRollLogFileDueToAge]; + } }); + +#if !OS_OBJECT_USE_OBJC + dispatch_source_t theRollingTimer = _rollingTimer; + dispatch_source_set_cancel_handler(_rollingTimer, ^{ + dispatch_release(theRollingTimer); + }); +#endif + + static NSTimeInterval const kDDMaxTimerDelay = LLONG_MAX / NSEC_PER_SEC; + __auto_type delay = (int64_t)(MIN([logFileRollingDate timeIntervalSinceNow], kDDMaxTimerDelay) * (NSTimeInterval)NSEC_PER_SEC); + __auto_type fireTime = dispatch_walltime(NULL, delay); // `NULL` uses `gettimeofday` internally + + dispatch_source_set_timer(_rollingTimer, fireTime, DISPATCH_TIME_FOREVER, (uint64_t)kDDRollingLeeway * NSEC_PER_SEC); + dispatch_activate(_rollingTimer); +} + +- (void)rollLogFile { + [self rollLogFileWithCompletionBlock:nil]; +} + +- (void)rollLogFileWithCompletionBlock:(nullable void (^)(void))completionBlock { + // This method is public. + // We need to execute the rolling on our logging thread/queue. + + __auto_type block = ^{ + @autoreleasepool { + [self lt_rollLogFileNow]; + + if (completionBlock) { + dispatch_async(self->_completionQueue, ^{ + completionBlock(); + }); + } + } + }; + + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (void)lt_rollLogFileNow { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + NSLogVerbose(@"DDFileLogger: %@", NSStringFromSelector(_cmd)); + + if (_currentLogFileHandle == nil) { + return; + } + + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)) { + __autoreleasing NSError *error = nil; + __auto_type success = [_currentLogFileHandle synchronizeAndReturnError:&error]; + if (!success) { + NSLogError(@"DDFileLogger: Failed to synchronize file: %@", error); + } + success = [_currentLogFileHandle closeAndReturnError:&error]; + if (!success) { + NSLogError(@"DDFileLogger: Failed to close file: %@", error); + } + } else { + @try { + [_currentLogFileHandle synchronizeFile]; + } + @catch (NSException *exception) { + NSLogError(@"DDFileLogger: Failed to synchronize file: %@", exception); + } + [_currentLogFileHandle closeFile]; + } + _currentLogFileHandle = nil; + + _currentLogFileInfo.isArchived = YES; + + const __auto_type logFileManagerRespondsToNewArchiveSelector = [_logFileManager respondsToSelector:@selector(didArchiveLogFile:wasRolled:)]; + const __auto_type logFileManagerRespondsToSelector = (logFileManagerRespondsToNewArchiveSelector + || [_logFileManager respondsToSelector:@selector(didRollAndArchiveLogFile:)]); + NSString *archivedFilePath = (logFileManagerRespondsToSelector) ? [_currentLogFileInfo.filePath copy] : nil; + _currentLogFileInfo = nil; + + if (logFileManagerRespondsToSelector) { + dispatch_block_t block; + if (logFileManagerRespondsToNewArchiveSelector) { + block = ^{ + [self->_logFileManager didArchiveLogFile:archivedFilePath wasRolled:YES]; + }; + } else { + block = ^{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [self->_logFileManager didRollAndArchiveLogFile:archivedFilePath]; +#pragma clang diagnostic pop + }; + } + dispatch_async(_completionQueue, block); + } + + if (_currentLogFileVnode) { + dispatch_source_cancel(_currentLogFileVnode); + _currentLogFileVnode = nil; + } + + if (_rollingTimer) { + dispatch_source_cancel(_rollingTimer); + _rollingTimer = nil; + } +} + +- (void)lt_maybeRollLogFileDueToAge { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + if (_rollingFrequency > 0.0 && (_currentLogFileInfo.age + kDDRollingLeeway) >= _rollingFrequency) { + NSLogVerbose(@"DDFileLogger: Rolling log file due to age..."); + [self lt_rollLogFileNow]; + } else { + [self lt_scheduleTimerToRollLogFileDueToAge]; + } +} + +- (void)lt_maybeRollLogFileDueToSize { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + // This method is called from logMessage. + // Keep it FAST. + + // Note: Use direct access to maximumFileSize variable. + // We specifically wrote our own getter/setter method to allow us to do this (for performance reasons). + + if (_currentLogFileHandle != nil && _maximumFileSize > 0) { + unsigned long long fileSize; + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)) { + __autoreleasing NSError *error = nil; + __auto_type success = [_currentLogFileHandle getOffset:&fileSize error:&error]; + if (!success) { + NSLogError(@"DDFileLogger: Failed to get offset: %@", error); + return; + } + } else { + fileSize = [_currentLogFileHandle offsetInFile]; + } + + if (fileSize >= _maximumFileSize) { + NSLogVerbose(@"DDFileLogger: Rolling log file due to size (%qu)...", fileSize); + + [self lt_rollLogFileNow]; + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark File Logging +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)lt_shouldLogFileBeArchived:(DDLogFileInfo *)mostRecentLogFileInfo { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + if ([self shouldArchiveRecentLogFileInfo:mostRecentLogFileInfo]) { + return YES; + } else if (_maximumFileSize > 0 && mostRecentLogFileInfo.fileSize >= _maximumFileSize) { + return YES; + } else if (_rollingFrequency > 0.0 && mostRecentLogFileInfo.age >= _rollingFrequency) { + return YES; + } + +#if TARGET_OS_IPHONE + // When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen. + // + // But in case if app is able to launch from background we need to have an ability to open log file any time we + // want (even if device is locked). Thats why that attribute have to be changed to + // NSFileProtectionCompleteUntilFirstUserAuthentication. + // + // If previous log was created when app wasn't running in background, but now it is - we archive it and create + // a new one. + // + // If user has overwritten to NSFileProtectionNone there is no need to create a new one. + if (doesAppRunInBackground()) { + NSFileProtectionType key = mostRecentLogFileInfo.fileAttributes[NSFileProtectionKey]; + __auto_type isUntilFirstAuth = [key isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication]; + __auto_type isNone = [key isEqualToString:NSFileProtectionNone]; + + if (key != nil && !isUntilFirstAuth && !isNone) { + return YES; + } + } +#endif + + return NO; +} + +/** + * Returns the log file that should be used. + * If there is an existing log file that is suitable, within the + * constraints of maximumFileSize and rollingFrequency, then it is returned. + * + * Otherwise a new file is created and returned. + **/ +- (DDLogFileInfo *)currentLogFileInfo { + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + // Do not access this method on any Lumberjack queue, will deadlock. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + __block DDLogFileInfo *info = nil; + __auto_type block = ^{ + info = [self lt_currentLogFileInfo]; + }; + + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self->_loggerQueue, block); + }); + + return info; +} + +- (DDLogFileInfo *)lt_currentLogFileInfo { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + // Get the current log file info ivar (might be nil). + __auto_type newCurrentLogFile = _currentLogFileInfo; + + // Check if we're resuming and if so, get the first of the sorted log file infos. + __auto_type isResuming = newCurrentLogFile == nil; + if (isResuming) { + NSArray *sortedLogFileInfos = [_logFileManager sortedLogFileInfos]; + newCurrentLogFile = sortedLogFileInfos.firstObject; + } + + // Check if the file we've found is still valid. Otherwise create a new one. + if (newCurrentLogFile != nil && [self lt_shouldUseLogFile:newCurrentLogFile isResuming:isResuming]) { + if (isResuming) { + NSLogVerbose(@"DDFileLogger: Resuming logging with file %@", newCurrentLogFile.fileName); + } + _currentLogFileInfo = newCurrentLogFile; + } else { + NSString *currentLogFilePath; + if ([_logFileManager respondsToSelector:@selector(createNewLogFileWithError:)]) { + __autoreleasing NSError *error; // Don't initialize error to nil since it will be done in -createNewLogFileWithError: + currentLogFilePath = [_logFileManager createNewLogFileWithError:&error]; + if (!currentLogFilePath) { + NSLogError(@"DDFileLogger: Failed to create new log file: %@", error); + } + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSAssert([_logFileManager respondsToSelector:@selector(createNewLogFile)], + @"Invalid log file manager! Responds neither to `-createNewLogFileWithError:` nor `-createNewLogFile`!"); + currentLogFilePath = [_logFileManager createNewLogFile]; +#pragma clang diagnostic pop + if (!currentLogFilePath) { + NSLogError(@"DDFileLogger: Failed to create new log file"); + } + } + // Use static factory method here, since it checks for nil (and is unavailable to Swift). + _currentLogFileInfo = [DDLogFileInfo logFileWithPath:currentLogFilePath]; + } + + return _currentLogFileInfo; +} + +- (BOOL)lt_shouldUseLogFile:(nonnull DDLogFileInfo *)logFileInfo isResuming:(BOOL)isResuming { + NSParameterAssert(logFileInfo); + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + // Check if the log file is archived. We must not use archived log files. + if (logFileInfo.isArchived) { + return NO; + } + + // Don't follow symlink + if (logFileInfo.isSymlink) { + return NO; + } + + // If we're resuming, we need to check if the log file is allowed for reuse or needs to be archived. + if (isResuming && (_doNotReuseLogFiles || [self lt_shouldLogFileBeArchived:logFileInfo])) { + logFileInfo.isArchived = YES; + + const __auto_type logFileManagerRespondsToNewArchiveSelector = [_logFileManager respondsToSelector:@selector(didArchiveLogFile:wasRolled:)]; + if (logFileManagerRespondsToNewArchiveSelector || [_logFileManager respondsToSelector:@selector(didArchiveLogFile:)]) { + NSString *archivedFilePath = [logFileInfo.filePath copy]; + dispatch_block_t block; + if (logFileManagerRespondsToNewArchiveSelector) { + block = ^{ + [self->_logFileManager didArchiveLogFile:archivedFilePath wasRolled:NO]; + }; + } else { + block = ^{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [self->_logFileManager didArchiveLogFile:archivedFilePath]; +#pragma clang diagnostic pop + }; + } + dispatch_async(_completionQueue, block); + } + + return NO; + } + + // All checks have passed. It's valid. + return YES; +} + +- (void)lt_monitorCurrentLogFileForExternalChanges { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + NSAssert(_currentLogFileHandle, @"Can not monitor without handle."); + + // This seems to work around crashes when an active source is replaced / released. + // See https://github.com/CocoaLumberjack/CocoaLumberjack/issues/1341 + // And https://stackoverflow.com/questions/36296528/what-does-this-dispatch-xref-dispose-error-mean + if (_currentLogFileVnode) { + dispatch_source_cancel(_currentLogFileVnode); + } + + _currentLogFileVnode = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, + (uintptr_t)[_currentLogFileHandle fileDescriptor], + DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE, + _loggerQueue); + + __weak __auto_type weakSelf = self; + dispatch_source_set_event_handler(_currentLogFileVnode, ^{ @autoreleasepool { + NSLogInfo(@"DDFileLogger: Current logfile was moved. Rolling it and creating a new one"); + [weakSelf lt_rollLogFileNow]; + } }); + +#if !OS_OBJECT_USE_OBJC + dispatch_source_t vnode = _currentLogFileVnode; + dispatch_source_set_cancel_handler(_currentLogFileVnode, ^{ + dispatch_release(vnode); + }); +#endif + + dispatch_activate(_currentLogFileVnode); +} + +- (NSFileHandle *)lt_currentLogFileHandle { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + if (_currentLogFileHandle == nil) { + __auto_type logFilePath = [[self lt_currentLogFileInfo] filePath]; + _currentLogFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath]; + if (_currentLogFileHandle != nil) { + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)) { + __autoreleasing NSError *error = nil; + __auto_type success = [_currentLogFileHandle seekToEndReturningOffset:nil error:&error]; + if (!success) { + NSLogError(@"DDFileLogger: Failed to seek to end of file: %@", error); + } + } else { + [_currentLogFileHandle seekToEndOfFile]; + } + + [self lt_scheduleTimerToRollLogFileDueToAge]; + [self lt_monitorCurrentLogFileForExternalChanges]; + } + } + + return _currentLogFileHandle; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark DDLogger Protocol +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static int exception_count = 0; + +- (void)logMessage:(DDLogMessage *)logMessage { + // Don't need to check for isOnInternalLoggerQueue, -lt_dataForMessage: will do it for us. + NSData *data = [self lt_dataForMessage:logMessage]; + if (data.length == 0) { + return; + } + + [self lt_logData:data]; +} + +- (void)willLogMessage:(DDLogFileInfo *)logFileInfo {} + +- (void)didLogMessage:(DDLogFileInfo *)logFileInfo { + [self lt_maybeRollLogFileDueToSize]; +} + +- (BOOL)shouldArchiveRecentLogFileInfo:(__unused DDLogFileInfo *)recentLogFileInfo { + return NO; +} + +- (void)willRemoveLogger { + [self lt_rollLogFileNow]; +} + +- (void)flush { + // This method is public. + // We need to execute the rolling on our logging thread/queue. + + dispatch_block_t block = ^{ + @autoreleasepool { + [self lt_flush]; + } + }; + + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, block); + }); + } +} + +- (void)lt_flush { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + if (_currentLogFileHandle != nil) { + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)) { + __autoreleasing NSError *error = nil; + __auto_type success = [_currentLogFileHandle synchronizeAndReturnError:&error]; + if (!success) { + NSLogError(@"DDFileLogger: Failed to synchronize file: %@", error); + } + } else { + @try { + [_currentLogFileHandle synchronizeFile]; + } @catch (NSException *exception) { + NSLogError(@"DDFileLogger: Failed to synchronize file: %@", exception); + } + } + } +} + +- (DDLoggerName)loggerName { + return DDLoggerNameFile; +} + +@end + +@implementation DDFileLogger (Internal) + +- (void)logData:(NSData *)data { + // This method is public. + // We need to execute the rolling on our logging thread/queue. + + __auto_type block = ^{ + @autoreleasepool { + [self lt_logData:data]; + } + }; + + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, block); + }); + } +} + +- (void)lt_deprecationCatchAll {} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { + if (aSelector == @selector(willLogMessage) || aSelector == @selector(didLogMessage)) { + // Ignore calls to deprecated methods. + return [self methodSignatureForSelector:@selector(lt_deprecationCatchAll)]; + } + + return [super methodSignatureForSelector:aSelector]; +} + +- (void)forwardInvocation:(NSInvocation *)anInvocation { + if (anInvocation.selector != @selector(lt_deprecationCatchAll)) { + [super forwardInvocation:anInvocation]; + } +} + +- (void)lt_logData:(NSData *)data { + static __auto_type implementsDeprecatedWillLog = NO; + static __auto_type implementsDeprecatedDidLog = NO; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + implementsDeprecatedWillLog = [self respondsToSelector:@selector(willLogMessage)]; + implementsDeprecatedDidLog = [self respondsToSelector:@selector(didLogMessage)]; + }); + + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + if (data.length == 0) { + return; + } + + @try { + // Make sure that _currentLogFileInfo is initialised before being used. + __auto_type handle = [self lt_currentLogFileHandle]; + + if (implementsDeprecatedWillLog) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [self willLogMessage]; +#pragma clang diagnostic pop + } else { + [self willLogMessage:_currentLogFileInfo]; + } + + // use an advisory lock to coordinate write with other processes + __auto_type fd = [handle fileDescriptor]; + while(flock(fd, LOCK_EX) != 0) { + NSLogError(@"DDFileLogger: Could not lock logfile, retrying in 1ms: %s (%d)", strerror(errno), errno); + usleep(1000); + } + if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)) { + __autoreleasing NSError *error = nil; + __auto_type success = [handle seekToEndReturningOffset:nil error:&error]; + if (!success) { + NSLogError(@"DDFileLogger: Failed to seek to end of file: %@", error); + } + success = [handle writeData:data error:&error]; + if (!success) { + NSLogError(@"DDFileLogger: Failed to write data: %@", error); + } + } else { + [handle seekToEndOfFile]; + [handle writeData:data]; + } + flock(fd, LOCK_UN); + + if (implementsDeprecatedDidLog) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [self didLogMessage]; +#pragma clang diagnostic pop + } else { + [self didLogMessage:_currentLogFileInfo]; + } + + } + @catch (NSException *exception) { + exception_count++; + + if (exception_count <= 10) { + NSLogError(@"DDFileLogger.logMessage: %@", exception); + + if (exception_count == 10) { + NSLogError(@"DDFileLogger.logMessage: Too many exceptions -- will not log any more of them."); + } + } + } +} + +- (id )lt_logFileSerializer { + if ([_logFileManager respondsToSelector:@selector(logMessageSerializer)]) { + return _logFileManager.logMessageSerializer; + } else { + return [[DDFileLogPlainTextMessageSerializer alloc] init]; + } +} + +- (NSData *)lt_dataForMessage:(DDLogMessage *)logMessage { + DDAbstractLoggerAssertOnInternalLoggerQueue(); + + __auto_type messageString = logMessage->_message; + __auto_type isFormatted = NO; + + if (_logFormatter != nil) { + messageString = [_logFormatter formatLogMessage:logMessage]; + isFormatted = messageString != logMessage->_message; + } + + if (messageString.length == 0) { + return nil; + } + + __auto_type shouldFormat = !isFormatted || _automaticallyAppendNewlineForCustomFormatters; + if (shouldFormat && ![messageString hasSuffix:@"\n"]) { + messageString = [messageString stringByAppendingString:@"\n"]; + } + + return [[self lt_logFileSerializer] dataForString:messageString originatingFromMessage:logMessage]; +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static NSString * const kDDXAttrArchivedName = @"lumberjack.log.archived"; + +@interface DDLogFileInfo () { + __strong NSString *_filePath; + __strong NSString *_fileName; + + __strong NSDictionary *_fileAttributes; + + __strong NSDate *_creationDate; + __strong NSDate *_modificationDate; + + unsigned long long _fileSize; +} + +#if TARGET_IPHONE_SIMULATOR +// Old implementation of extended attributes on the simulator. +- (BOOL)_hasExtensionAttributeWithName:(NSString *)attrName; +- (void)_removeExtensionAttributeWithName:(NSString *)attrName; +#endif + +@end + + +@implementation DDLogFileInfo + +@synthesize filePath; + +@dynamic fileName; +@dynamic fileAttributes; +@dynamic creationDate; +@dynamic modificationDate; +@dynamic fileSize; +@dynamic age; + +@dynamic isArchived; + +#pragma mark Lifecycle + ++ (instancetype)logFileWithPath:(NSString *)aFilePath { + if (!aFilePath) return nil; + return [[self alloc] initWithFilePath:aFilePath]; +} + +- (instancetype)initWithFilePath:(NSString *)aFilePath { + NSParameterAssert(aFilePath); + if ((self = [super init])) { + filePath = [aFilePath copy]; + } + + return self; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Standard Info +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSDictionary *)fileAttributes { + if (_fileAttributes == nil && filePath != nil) { + __autoreleasing NSError *error = nil; + _fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error]; + if (!_fileAttributes) { + NSLogError(@"DDLogFileInfo: Failed to read file attributes: %@", error); + } + } + + return _fileAttributes ?: @{}; +} + +- (NSString *)fileName { + if (_fileName == nil) { + _fileName = [filePath lastPathComponent]; + } + + return _fileName; +} + +- (NSDate *)modificationDate { + if (_modificationDate == nil) { + _modificationDate = self.fileAttributes[NSFileModificationDate]; + } + + return _modificationDate; +} + +- (NSDate *)creationDate { + if (_creationDate == nil) { + _creationDate = self.fileAttributes[NSFileCreationDate]; + } + + return _creationDate; +} + +- (unsigned long long)fileSize { + if (_fileSize == 0) { + _fileSize = [self.fileAttributes[NSFileSize] unsignedLongLongValue]; + } + + return _fileSize; +} + +- (NSTimeInterval)age { + return -[[self creationDate] timeIntervalSinceNow]; +} + +- (BOOL)isSymlink { + return self.fileAttributes[NSFileType] == NSFileTypeSymbolicLink; +} + +- (NSString *)description { + return [@{ @"filePath": self.filePath ? : @"", + @"fileName": self.fileName ? : @"", + @"fileAttributes": self.fileAttributes ? : @"", + @"creationDate": self.creationDate ? : @"", + @"modificationDate": self.modificationDate ? : @"", + @"fileSize": @(self.fileSize), + @"age": @(self.age), + @"isArchived": @(self.isArchived) } description]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Archiving +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)isArchived { + return [self hasExtendedAttributeWithName:kDDXAttrArchivedName]; +} + +- (void)setIsArchived:(BOOL)flag { + if (flag) { + [self addExtendedAttributeWithName:kDDXAttrArchivedName]; + } else { + [self removeExtendedAttributeWithName:kDDXAttrArchivedName]; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Changes +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)reset { + _fileName = nil; + _fileAttributes = nil; + _creationDate = nil; + _modificationDate = nil; +} + +- (void)renameFile:(NSString *)newFileName { + // This method is only used on the iPhone simulator, where normal extended attributes are broken. + // See full explanation in the header file. + + if (![newFileName isEqualToString:[self fileName]]) { + __auto_type fileManager = [NSFileManager defaultManager]; + __auto_type fileDir = [filePath stringByDeletingLastPathComponent]; + __auto_type newFilePath = [fileDir stringByAppendingPathComponent:newFileName]; + + // We only want to assert when we're not using the simulator, as we're "archiving" a log file with this method in the sim + // (in which case the file might not exist anymore and neither does it parent folder). +#if defined(DEBUG) && (!defined(TARGET_IPHONE_SIMULATOR) || !TARGET_IPHONE_SIMULATOR) + __auto_type directory = NO; + [fileManager fileExistsAtPath:fileDir isDirectory:&directory]; + NSAssert(directory, @"Containing directory must exist."); +#endif + + __autoreleasing NSError *error = nil; + __auto_type success = [fileManager removeItemAtPath:newFilePath error:&error]; + if (!success && error.code != NSFileNoSuchFileError) { + NSLogError(@"DDLogFileInfo: Error deleting archive (%@): %@", self.fileName, error); + } + + success = [fileManager moveItemAtPath:filePath toPath:newFilePath error:&error]; + + // When a log file is deleted, moved or renamed on the simulator, we attempt to rename it as a + // result of "archiving" it, but since the file doesn't exist anymore, needless error logs are printed + // We therefore ignore this error, and assert that the directory we are copying into exists (which + // is the only other case where this error code can come up). +#if TARGET_IPHONE_SIMULATOR + if (!success && error.code != NSFileNoSuchFileError) +#else + if (!success) +#endif + { + NSLogError(@"DDLogFileInfo: Error renaming file (%@): %@", self.fileName, error); + } + + filePath = newFilePath; + [self reset]; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Attribute Management +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if TARGET_IPHONE_SIMULATOR + +// Old implementation of extended attributes on the simulator. + +// Extended attributes were not working properly on the simulator +// due to misuse of setxattr() function. +// Now that this is fixed in the new implementation, we want to keep +// backward compatibility with previous simulator installations. + +static NSString * const kDDExtensionSeparator = @"."; + +static NSString *_xattrToExtensionName(NSString *attrName) { + static NSDictionary* _xattrToExtensionNameMap; + static dispatch_once_t _token; + dispatch_once(&_token, ^{ + _xattrToExtensionNameMap = @{ kDDXAttrArchivedName: @"archived" }; + }); + return [_xattrToExtensionNameMap objectForKey:attrName]; +} + +- (BOOL)_hasExtensionAttributeWithName:(NSString *)attrName { + // This method is only used on the iPhone simulator for backward compatibility reason. + + // Split the file name into components. File name may have various format, but generally + // structure is same: + // + // . and .archived. + // or + // and .archived + // + // So we want to search for the attrName in the components (ignoring the first array index). + + __auto_type components = [[self fileName] componentsSeparatedByString:kDDExtensionSeparator]; + + // Watch out for file names without an extension + + for (NSUInteger i = 1; i < components.count; i++) { + if ([attrName isEqualToString:components[i]]) { + return YES; + } + } + + return NO; +} + +- (void)_removeExtensionAttributeWithName:(NSString *)attrName { + // This method is only used on the iPhone simulator for backward compatibility reason. + + if ([attrName length] == 0) { + return; + } + + // Example: + // attrName = "archived" + // + // "mylog.archived.txt" -> "mylog.txt" + // "mylog.archived" -> "mylog" + + __auto_type components = [[self fileName] componentsSeparatedByString:kDDExtensionSeparator]; + + __auto_type count = [components count]; + + __auto_type estimatedNewLength = [[self fileName] length]; + __auto_type newFileName = [NSMutableString stringWithCapacity:estimatedNewLength]; + + if (count > 0) { + [newFileName appendString:components[0]]; + } + + __auto_type found = NO; + + NSUInteger i; + + for (i = 1; i < count; i++) { + __auto_type attr = components[i]; + + if ([attrName isEqualToString:attr]) { + found = YES; + } else { + [newFileName appendString:kDDExtensionSeparator]; + [newFileName appendString:attr]; + } + } + + if (found) { + [self renameFile:newFileName]; + } +} + +#endif /* if TARGET_IPHONE_SIMULATOR */ + +- (BOOL)hasExtendedAttributeWithName:(NSString *)attrName { + __auto_type path = [filePath fileSystemRepresentation]; + __auto_type name = [attrName UTF8String]; + __auto_type hasExtendedAttribute = NO; + char buffer[1]; + + __auto_type result = getxattr(path, name, buffer, 1, 0, 0); + + // Fast path + if (result > 0 && buffer[0] == '\1') { + hasExtendedAttribute = YES; + } + // Maintain backward compatibility, but fix it for future checks + else if (result >= 0) { + hasExtendedAttribute = YES; + + [self addExtendedAttributeWithName:attrName]; + } +#if TARGET_IPHONE_SIMULATOR + else if ([self _hasExtensionAttributeWithName:_xattrToExtensionName(attrName)]) { + hasExtendedAttribute = YES; + + [self addExtendedAttributeWithName:attrName]; + } +#endif + + return hasExtendedAttribute; +} + +- (void)addExtendedAttributeWithName:(NSString *)attrName { + __auto_type path = [filePath fileSystemRepresentation]; + __auto_type name = [attrName UTF8String]; + + __auto_type result = setxattr(path, name, "\1", 1, 0, 0); + + if (result < 0) { + if (errno != ENOENT) { + NSLogError(@"DDLogFileInfo: setxattr(%@, %@): error = %@", + attrName, + filePath, + @(strerror(errno))); + } else { + NSLogDebug(@"DDLogFileInfo: File does not exist in setxattr(%@, %@): error = %@", + attrName, + filePath, + @(strerror(errno))); + } + } +#if TARGET_IPHONE_SIMULATOR + else { + [self _removeExtensionAttributeWithName:_xattrToExtensionName(attrName)]; + } +#endif +} + +- (void)removeExtendedAttributeWithName:(NSString *)attrName { + __auto_type path = [filePath fileSystemRepresentation]; + __auto_type name = [attrName UTF8String]; + + __auto_type result = removexattr(path, name, 0); + + if (result < 0 && errno != ENOATTR) { + NSLogError(@"DDLogFileInfo: removexattr(%@, %@): error = %@", + attrName, + self.fileName, + @(strerror(errno))); + } + +#if TARGET_IPHONE_SIMULATOR + [self _removeExtensionAttributeWithName:_xattrToExtensionName(attrName)]; +#endif +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Comparisons +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)isEqual:(id)object { + if ([object isKindOfClass:[self class]]) { + __auto_type another = (DDLogFileInfo *)object; + + return [filePath isEqualToString:[another filePath]]; + } + + return NO; +} + +- (NSUInteger)hash { + return [filePath hash]; +} + +- (NSComparisonResult)reverseCompareDatesUs:(NSDate *_Nullable)us them:(NSDate *_Nullable)them { + if (us != nil && them != nil) { + return [them compare:(NSDate * _Nonnull)us]; + } else if (us == nil && them == nil) { + return NSOrderedSame; + } + return them == nil ? NSOrderedAscending : NSOrderedDescending; +} + +- (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another { + return [self reverseCompareDatesUs:[self creationDate] them:[another creationDate]]; +} + +- (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another { + return [self reverseCompareDatesUs:[self modificationDate] them:[another modificationDate]]; +} + +@end + +#if TARGET_OS_IPHONE +/** + * When creating log file on iOS we're setting NSFileProtectionKey attribute to NSFileProtectionCompleteUnlessOpen. + * + * But in case if app is able to launch from background we need to have an ability to open log file any time we + * want (even if device is locked). Thats why that attribute have to be changed to + * NSFileProtectionCompleteUntilFirstUserAuthentication. + */ +BOOL doesAppRunInBackground(void) { + if ([[[NSBundle mainBundle] executablePath] containsString:@".appex/"]) { + return YES; + } + + __auto_type answer = NO; + NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"]; + for (NSString *mode in backgroundModes) { + if (mode.length > 0) { + answer = YES; + break; + } + } + + return answer; +} +#endif diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDLog.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDLog.m new file mode 100644 index 0000000..6c09772 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDLog.m @@ -0,0 +1,1321 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +#import +#import +#import + +#if TARGET_OS_IOS + #import + #import +#elif !defined(DD_CLI) && __has_include() + #import +#endif + +// Disable legacy macros +#ifndef DD_LEGACY_MACROS + #define DD_LEGACY_MACROS 0 +#endif + +#import + +// We probably shouldn't be using DDLog() statements within the DDLog implementation. +// But we still want to leave our log statements for any future debugging, +// and to allow other developers to trace the implementation (which is a great learning tool). +// +// So we use a primitive logging macro around NSLog. +// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog. + +#ifndef DD_DEBUG + #define DD_DEBUG 0 +#endif + +#define NSLogDebug(frmt, ...) do{ if(DD_DEBUG) NSLog((frmt), ##__VA_ARGS__); } while(0) + +#define DDLogAssertOnGlobalLoggingQueue() \ +NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey), @"This method must be called on the logging thread/queue!") +#define DDLogAssertNotOnGlobalLoggingQueue() \ +NSAssert(!dispatch_get_specific(GlobalLoggingQueueIdentityKey), @"This method must not be called on the logging thread/queue!") + +// The "global logging queue" refers to [DDLog loggingQueue]. +// It is the queue that all log statements go through. +// +// The logging queue sets a flag via dispatch_queue_set_specific using this key. +// We can check for this key via dispatch_get_specific() to see if we're on the "global logging queue". + +static void *const GlobalLoggingQueueIdentityKey = (void *)&GlobalLoggingQueueIdentityKey; + +@interface DDLoggerNode : NSObject +{ + // Direct accessors to be used only for performance + @public + id _logger; + DDLogLevel _level; + dispatch_queue_t _loggerQueue; +} + +@property (nonatomic, readonly) id logger; +@property (nonatomic, readonly) DDLogLevel level; +@property (nonatomic, readonly) dispatch_queue_t loggerQueue; + ++ (instancetype)nodeWithLogger:(id )logger + loggerQueue:(dispatch_queue_t)loggerQueue + level:(DDLogLevel)level; + +@end + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface DDLog () + +// An array used to manage all the individual loggers. +// The array is only modified on the loggingQueue/loggingThread. +@property (nonatomic, strong) NSMutableArray *_loggers; + +@end + +@implementation DDLog + +// All logging statements are added to the same queue to ensure FIFO operation. +static dispatch_queue_t _loggingQueue; + +// Individual loggers are executed concurrently per log statement. +// Each logger has it's own associated queue, and a dispatch group is used for synchronization. +static dispatch_group_t _loggingGroup; + +// Minor optimization for uniprocessor machines +static NSUInteger _numProcessors; + +/** + * Returns the singleton `DDLog`. + * The instance is used by `DDLog` class methods. + * + * @return The singleton `DDLog`. + */ ++ (instancetype)sharedInstance { + static DDLog *sharedInstance = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + + return sharedInstance; +} + +/** + * The runtime sends initialize to each class in a program exactly one time just before the class, + * or any class that inherits from it, is sent its first message from within the program. (Thus the + * method may never be invoked if the class is not used.) The runtime sends the initialize message to + * classes in a thread-safe manner. Superclasses receive this message before their subclasses. + * + * This method may also be called directly, hence the safety mechanism. + **/ ++ (void)initialize { + static dispatch_once_t DDLogOnceToken; + + dispatch_once(&DDLogOnceToken, ^{ + NSLogDebug(@"DDLog: Using grand central dispatch"); + + _loggingQueue = dispatch_queue_create("cocoa.lumberjack", NULL); + _loggingGroup = dispatch_group_create(); + + void *nonNullValue = GlobalLoggingQueueIdentityKey; // Whatever, just not null + dispatch_queue_set_specific(_loggingQueue, GlobalLoggingQueueIdentityKey, nonNullValue, NULL); + + // Figure out how many processors are available. + // This may be used later for an optimization on uniprocessor machines. + + _numProcessors = MAX([NSProcessInfo processInfo].processorCount, (NSUInteger) 1); + + NSLogDebug(@"DDLog: numProcessors = %@", @(_numProcessors)); + }); +} + +/** + * The `DDLog` initializer. + * Static variables are set only once. + * + * @return An initialized `DDLog` instance. + */ +- (instancetype)init { + self = [super init]; + + if (self) { + self._loggers = [[NSMutableArray alloc] initWithCapacity:4]; + +#if TARGET_OS_IOS + __auto_type notificationName = UIApplicationWillTerminateNotification; +#else + NSString *notificationName = nil; + + // On Command Line Tool apps AppKit may not be available +#if !defined(DD_CLI) && __has_include() + if (NSApp) { + notificationName = NSApplicationWillTerminateNotification; + } +#endif + + if (!notificationName) { + // If there is no NSApp -> we are running Command Line Tool app. + // In this case terminate notification wouldn't be fired, so we use workaround. + __weak __auto_type weakSelf = self; + atexit_b (^{ + [weakSelf applicationWillTerminate:nil]; + }); + } + +#endif /* if TARGET_OS_IOS */ + + if (notificationName) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationWillTerminate:) + name:notificationName + object:nil]; + } + } + + return self; +} + +/** + * Provides access to the logging queue. + **/ ++ (dispatch_queue_t)loggingQueue { + return _loggingQueue; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Notifications +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)applicationWillTerminate:(NSNotification * __attribute__((unused)))notification { + [self flushLog]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Logger Management +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ++ (void)addLogger:(id )logger { + [self.sharedInstance addLogger:logger]; +} + +- (void)addLogger:(id )logger { + [self addLogger:logger withLevel:DDLogLevelAll]; // DDLogLevelAll has all bits set +} + ++ (void)addLogger:(id )logger withLevel:(DDLogLevel)level { + [self.sharedInstance addLogger:logger withLevel:level]; +} + +- (void)addLogger:(id )logger withLevel:(DDLogLevel)level { + if (!logger) { + return; + } + + dispatch_async(_loggingQueue, ^{ @autoreleasepool { + [self lt_addLogger:logger level:level]; + } }); +} + ++ (void)removeLogger:(id )logger { + [self.sharedInstance removeLogger:logger]; +} + +- (void)removeLogger:(id )logger { + if (!logger) { + return; + } + + dispatch_async(_loggingQueue, ^{ @autoreleasepool { + [self lt_removeLogger:logger]; + } }); +} + ++ (void)removeAllLoggers { + [self.sharedInstance removeAllLoggers]; +} + +- (void)removeAllLoggers { + dispatch_async(_loggingQueue, ^{ @autoreleasepool { + [self lt_removeAllLoggers]; + } }); +} + ++ (NSArray> *)allLoggers { + return [self.sharedInstance allLoggers]; +} + +- (NSArray> *)allLoggers { + __block NSArray *theLoggers; + + dispatch_sync(_loggingQueue, ^{ @autoreleasepool { + theLoggers = [self lt_allLoggers]; + } }); + + return theLoggers; +} + ++ (NSArray *)allLoggersWithLevel { + return [self.sharedInstance allLoggersWithLevel]; +} + +- (NSArray *)allLoggersWithLevel { + __block NSArray *theLoggersWithLevel; + + dispatch_sync(_loggingQueue, ^{ @autoreleasepool { + theLoggersWithLevel = [self lt_allLoggersWithLevel]; + } }); + + return theLoggersWithLevel; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Master Logging +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)queueLogMessage:(DDLogMessage *)logMessage asynchronously:(BOOL)asyncFlag { + // We have a tricky situation here... + // + // In the common case, when the queueSize is below the maximumQueueSize, + // we want to simply enqueue the logMessage. And we want to do this as fast as possible, + // which means we don't want to block and we don't want to use any locks. + // + // However, if the queueSize gets too big, we want to block. + // But we have very strict requirements as to when we block, and how long we block. + // + // The following example should help illustrate our requirements: + // + // Imagine that the maximum queue size is configured to be 5, + // and that there are already 5 log messages queued. + // Let us call these 5 queued log messages A, B, C, D, and E. (A is next to be executed) + // + // Now if our thread issues a log statement (let us call the log message F), + // it should block before the message is added to the queue. + // Furthermore, it should be unblocked immediately after A has been unqueued. + // + // The requirements are strict in this manner so that we block only as long as necessary, + // and so that blocked threads are unblocked in the order in which they were blocked. + // + // Returning to our previous example, let us assume that log messages A through E are still queued. + // Our aforementioned thread is blocked attempting to queue log message F. + // Now assume we have another separate thread that attempts to issue log message G. + // It should block until log messages A and B have been unqueued. + + __auto_type logBlock = ^{ + // We're now sure we won't overflow the queue. + // It is time to queue our log message. + @autoreleasepool { + [self lt_log:logMessage]; + } + }; + + if (asyncFlag) { + dispatch_async(_loggingQueue, logBlock); + } else if (dispatch_get_specific(GlobalLoggingQueueIdentityKey)) { + // We've logged an error message while on the logging queue... + logBlock(); + } else { + dispatch_sync(_loggingQueue, logBlock); + } +} + ++ (void)log:(BOOL)asynchronous + level:(DDLogLevel)level + flag:(DDLogFlag)flag + context:(NSInteger)context + file:(const char *)file + function:(const char *)function + line:(NSUInteger)line + tag:(id)tag + format:(NSString *)format, ... { + va_list args; + + if (format) { + va_start(args, format); + + [self log:asynchronous + level:level + flag:flag + context:context + file:file + function:function + line:line + tag:tag + format:format + args:args]; + + va_end(args); + } +} + +- (void)log:(BOOL)asynchronous + level:(DDLogLevel)level + flag:(DDLogFlag)flag + context:(NSInteger)context + file:(const char *)file + function:(const char *)function + line:(NSUInteger)line + tag:(id)tag + format:(NSString *)format, ... { + va_list args; + + if (format) { + va_start(args, format); + + [self log:asynchronous + level:level + flag:flag + context:context + file:file + function:function + line:line + tag:tag + format:format + args:args]; + + va_end(args); + } +} + ++ (void)log:(BOOL)asynchronous + level:(DDLogLevel)level + flag:(DDLogFlag)flag + context:(NSInteger)context + file:(const char *)file + function:(const char *)function + line:(NSUInteger)line + tag:(id)tag + format:(NSString *)format + args:(va_list)args { + [self.sharedInstance log:asynchronous level:level flag:flag context:context file:file function:function line:line tag:tag format:format args:args]; +} + +- (void)log:(BOOL)asynchronous + level:(DDLogLevel)level + flag:(DDLogFlag)flag + context:(NSInteger)context + file:(const char *)file + function:(const char *)function + line:(NSUInteger)line + tag:(id)tag + format:(NSString *)format + args:(va_list)args { + if (format) { + // Null checks are handled by -initWithMessage: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullable-to-nonnull-conversion" + __auto_type logMessage = [[DDLogMessage alloc] initWithFormat:format + args:args + level:level + flag:flag + context:context + file:@(file) + function:@(function) + line:line + tag:tag + options:(DDLogMessageOptions)0 + timestamp:nil]; +#pragma clang diagnostic pop + + [self queueLogMessage:logMessage asynchronously:asynchronous]; + } +} + ++ (void)log:(BOOL)asynchronous message:(DDLogMessage *)logMessage { + [self.sharedInstance log:asynchronous message:logMessage]; +} + +- (void)log:(BOOL)asynchronous message:(DDLogMessage *)logMessage { + [self queueLogMessage:logMessage asynchronously:asynchronous]; +} + ++ (void)flushLog { + [self.sharedInstance flushLog]; +} + +- (void)flushLog { + DDLogAssertNotOnGlobalLoggingQueue(); + dispatch_sync(_loggingQueue, ^{ + @autoreleasepool { + [self lt_flush]; + } + }); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Registered Dynamic Logging +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ++ (BOOL)isRegisteredClass:(Class)class { + __auto_type getterSel = @selector(ddLogLevel); + __auto_type setterSel = @selector(ddSetLogLevel:); + + // Issue #6 (GoogleCode) - Crashes on iOS 4.2.1 and iPhone 4 + // Crash caused by class_getClassMethod(2). + // "It's a bug with UIAccessibilitySafeCategory__NSObject so it didn't pop up until + // users had VoiceOver enabled [...]. I was able to work around it by searching the + // result of class_copyMethodList() instead of calling class_getClassMethod()" + // + // Issue #24 (GitHub) - Crashing in in ARC+Simulator + // The method +[DDLog isRegisteredClass] will crash a project when using it with ARC + Simulator. + // For running in the Simulator, it needs to execute the non-iOS code. Unless we're running on iOS 17+. + +#if TARGET_OS_IPHONE +#if TARGET_OS_SIMULATOR + if (@available(iOS 17, tvOS 17, *)) { +#endif + __auto_type result = NO; + unsigned int methodCount, i; + __auto_type methodList = class_copyMethodList(object_getClass(class), &methodCount); + + if (methodList != NULL) { + __auto_type getterFound = NO; + __auto_type setterFound = NO; + + for (i = 0; i < methodCount; ++i) { + __auto_type currentSel = method_getName(methodList[i]); + + if (currentSel == getterSel) { + getterFound = YES; + } else if (currentSel == setterSel) { + setterFound = YES; + } + + if (getterFound && setterFound) { + result = YES; + break; + } + } + + free(methodList); + } + + return result; +#if TARGET_OS_SIMULATOR + } else { +#endif /* TARGET_OS_SIMULATOR */ +#endif /* TARGET_OS_IPHONE */ +#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR + __auto_type getter = class_getClassMethod(class, getterSel); + __auto_type setter = class_getClassMethod(class, setterSel); + return (getter != NULL) && (setter != NULL); +#endif /* !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR */ +#if TARGET_OS_IPHONE && TARGET_OS_SIMULATOR + } +#endif /* TARGET_OS_IPHONE && TARGET_OS_SIMULATOR */ +} + ++ (NSArray *)registeredClasses { + // We're going to get the list of all registered classes. + // The Objective-C runtime library automatically registers all the classes defined in your source code. + // + // To do this we use the following method (documented in the Objective-C Runtime Reference): + // + // int objc_getClassList(Class *buffer, int bufferLen) + // + // We can pass (NULL, 0) to obtain the total number of + // registered class definitions without actually retrieving any class definitions. + // This allows us to allocate the minimum amount of memory needed for the application. + + NSUInteger numClasses = 0; + Class *classes = NULL; + + while (numClasses == 0) { + numClasses = (NSUInteger)MAX(objc_getClassList(NULL, 0), 0); + + // numClasses now tells us how many classes we have (but it might change) + // So we can allocate our buffer, and get pointers to all the class definitions. + __auto_type bufferSize = numClasses; + classes = numClasses ? (Class *)calloc(bufferSize, sizeof(Class)) : NULL; + if (classes == NULL) { + return @[]; // no memory or classes? + } + + numClasses = (NSUInteger)MAX(objc_getClassList(classes, (int)bufferSize),0); + if (numClasses > bufferSize || numClasses == 0) { + // apparently more classes added between calls (or a problem); try again + free(classes); + classes = NULL; + numClasses = 0; + } + } + + // We can now loop through the classes, and test each one to see if it is a DDLogging class. + __auto_type result = [NSMutableArray arrayWithCapacity:numClasses]; + for (NSUInteger i = 0; i < numClasses; i++) { + // Cannot use `__auto_type` here, since this will lead to crashes when deallocating! + Class class = classes[i]; + + if ([self isRegisteredClass:class]) { + [result addObject:class]; + } + } + + free(classes); + + return result; +} + ++ (NSArray *)registeredClassNames { + __auto_type registeredClasses = [self registeredClasses]; + __auto_type result = [NSMutableArray arrayWithCapacity:[registeredClasses count]]; + + for (Class class in registeredClasses) { + [result addObject:NSStringFromClass(class)]; + } + return result; +} + ++ (DDLogLevel)levelForClass:(Class)aClass { + if ([self isRegisteredClass:aClass]) { + return [aClass ddLogLevel]; + } + return (DDLogLevel)-1; +} + ++ (DDLogLevel)levelForClassWithName:(NSString *)aClassName { + Class clazz = NSClassFromString(aClassName); + if (clazz == nil) return (DDLogLevel)-1; + return [self levelForClass:clazz]; +} + ++ (void)setLevel:(DDLogLevel)level forClass:(Class)aClass { + if ([self isRegisteredClass:aClass]) { + [aClass ddSetLogLevel:level]; + } +} + ++ (void)setLevel:(DDLogLevel)level forClassWithName:(NSString *)aClassName { + Class clazz = NSClassFromString(aClassName); + if (clazz == nil) return; + [self setLevel:level forClass:clazz]; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Logging Thread +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)lt_addLogger:(id )logger level:(DDLogLevel)level { + // Add to loggers array. + // Need to create loggerQueue if loggerNode doesn't provide one. + + for (DDLoggerNode *node in self._loggers) { + if (node->_logger == logger && node->_level == level) { + // Exactly same logger already added, exit + return; + } + } + + DDLogAssertOnGlobalLoggingQueue(); + + dispatch_queue_t loggerQueue = NULL; + if ([logger respondsToSelector:@selector(loggerQueue)]) { + // Logger may be providing its own queue + loggerQueue = logger.loggerQueue; + } + + if (loggerQueue == nil) { + // Automatically create queue for the logger. + // Use the logger name as the queue name if possible. + const char *loggerQueueName = NULL; + + if ([logger respondsToSelector:@selector(loggerName)]) { + loggerQueueName = logger.loggerName.UTF8String; + } + + loggerQueue = dispatch_queue_create(loggerQueueName, NULL); + } + + __auto_type loggerNode = [DDLoggerNode nodeWithLogger:logger loggerQueue:loggerQueue level:level]; + [self._loggers addObject:loggerNode]; + + if ([logger respondsToSelector:@selector(didAddLoggerInQueue:)]) { + dispatch_async(loggerNode->_loggerQueue, ^{ @autoreleasepool { + [logger didAddLoggerInQueue:loggerNode->_loggerQueue]; + } }); + } else if ([logger respondsToSelector:@selector(didAddLogger)]) { + dispatch_async(loggerNode->_loggerQueue, ^{ @autoreleasepool { + [logger didAddLogger]; + } }); + } +} + +- (void)lt_removeLogger:(id )logger { + // Find associated loggerNode in list of added loggers + + DDLogAssertOnGlobalLoggingQueue(); + + DDLoggerNode *loggerNode = nil; + + for (DDLoggerNode *node in self._loggers) { + if (node->_logger == logger) { + loggerNode = node; + break; + } + } + + if (loggerNode == nil) { + NSLogDebug(@"DDLog: Request to remove logger which wasn't added"); + return; + } + + // Notify logger + if ([logger respondsToSelector:@selector(willRemoveLogger)]) { + dispatch_async(loggerNode->_loggerQueue, ^{ @autoreleasepool { + [logger willRemoveLogger]; + } }); + } + + // Remove from loggers array + [self._loggers removeObject:loggerNode]; +} + +- (void)lt_removeAllLoggers { + DDLogAssertOnGlobalLoggingQueue(); + + // Notify all loggers + for (DDLoggerNode *loggerNode in self._loggers) { + if ([loggerNode->_logger respondsToSelector:@selector(willRemoveLogger)]) { + dispatch_async(loggerNode->_loggerQueue, ^{ @autoreleasepool { + [loggerNode->_logger willRemoveLogger]; + } }); + } + } + + // Remove all loggers from array + [self._loggers removeAllObjects]; +} + +- (NSArray *)lt_allLoggers { + DDLogAssertOnGlobalLoggingQueue(); + + __auto_type loggerNodes = self._loggers; + __auto_type theLoggers = [NSMutableArray arrayWithCapacity:loggerNodes.count]; + + for (DDLoggerNode *loggerNode in loggerNodes) { + [theLoggers addObject:loggerNode->_logger]; + } + + return [theLoggers copy]; +} + +- (NSArray *)lt_allLoggersWithLevel { + DDLogAssertOnGlobalLoggingQueue(); + + + __auto_type loggerNodes = self._loggers; + __auto_type theLoggersWithLevel = [NSMutableArray arrayWithCapacity:loggerNodes.count]; + + for (DDLoggerNode *loggerNode in loggerNodes) { + [theLoggersWithLevel addObject:[DDLoggerInformation informationWithLogger:loggerNode->_logger + andLevel:loggerNode->_level]]; + } + + return [theLoggersWithLevel copy]; +} + +- (void)lt_log:(DDLogMessage *)logMessage { + DDLogAssertOnGlobalLoggingQueue(); + + // Execute the given log message on each of our loggers. + + if (_numProcessors > 1) { + // Execute each logger concurrently, each within its own queue. + // All blocks are added to same group. + // After each block has been queued, wait on group. + // + // The waiting ensures that a slow logger doesn't end up with a large queue of pending log messages. + // This would defeat the purpose of the efforts we made earlier to restrict the max queue size. + + for (DDLoggerNode *loggerNode in self._loggers) { + // skip the loggers that shouldn't write this message based on the log level + + if (!(logMessage->_flag & loggerNode->_level)) { + continue; + } + + dispatch_group_async(_loggingGroup, loggerNode->_loggerQueue, ^{ @autoreleasepool { + [loggerNode->_logger logMessage:logMessage]; + } }); + } + + dispatch_group_wait(_loggingGroup, DISPATCH_TIME_FOREVER); + } else { + // Execute each logger serially, each within its own queue. + + for (DDLoggerNode *loggerNode in self._loggers) { + // skip the loggers that shouldn't write this message based on the log level + + if (!(logMessage->_flag & loggerNode->_level)) { + continue; + } + +#if DD_DEBUG + // we must assure that we aren not on loggerNode->_loggerQueue. + if (loggerNode->_loggerQueue == NULL) { + // tell that we can't dispatch logger node on queue that is NULL. + NSLogDebug(@"DDLog: current node has loggerQueue == NULL"); + } + else { + dispatch_async(loggerNode->_loggerQueue, ^{ + if (dispatch_get_specific(GlobalLoggingQueueIdentityKey)) { + // tell that we somehow on logging queue? + NSLogDebug(@"DDLog: current node has loggerQueue == globalLoggingQueue"); + } + }); + } +#endif + // next, we must check that node is OK. + dispatch_sync(loggerNode->_loggerQueue, ^{ @autoreleasepool { + [loggerNode->_logger logMessage:logMessage]; + } }); + } + } +} + +- (void)lt_flush { + // All log statements issued before the flush method was invoked have now been executed. + // + // Now we need to propagate the flush request to any loggers that implement the flush method. + // This is designed for loggers that buffer IO. + + DDLogAssertOnGlobalLoggingQueue(); + + for (DDLoggerNode *loggerNode in self._loggers) { + if ([loggerNode->_logger respondsToSelector:@selector(flush)]) { + dispatch_group_async(_loggingGroup, loggerNode->_loggerQueue, ^{ @autoreleasepool { + [loggerNode->_logger flush]; + } }); + } + } + + dispatch_group_wait(_loggingGroup, DISPATCH_TIME_FOREVER); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Utilities +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy) { + if (filePath == NULL) { + return nil; + } + + char *lastSlash = NULL; + char *lastDot = NULL; + + __auto_type p = (char *)filePath; + while (*p != '\0') { + if (*p == '/') { + lastSlash = p; + } else if (*p == '.') { + lastDot = p; + } + + p++; + } + + char *subStr; + NSUInteger subLen; + + if (lastSlash) { + if (lastDot) { + // lastSlash -> lastDot + subStr = lastSlash + 1; + subLen = (NSUInteger)(lastDot - subStr); + } else { + // lastSlash -> endOfString + subStr = lastSlash + 1; + subLen = (NSUInteger)(p - subStr); + } + } else { + if (lastDot) { + // startOfString -> lastDot + subStr = (char *)filePath; + subLen = (NSUInteger)(lastDot - subStr); + } else { + // startOfString -> endOfString + subStr = (char *)filePath; + subLen = (NSUInteger)(p - subStr); + } + } + + if (copy) { + return [[NSString alloc] initWithBytes:subStr + length:subLen + encoding:NSUTF8StringEncoding]; + } else { + // We can take advantage of the fact that __FILE__ is a string literal. + // Specifically, we don't need to waste time copying the string. + // We can just tell NSString to point to a range within the string literal. + + return [[NSString alloc] initWithBytesNoCopy:subStr + length:subLen + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + } +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation DDLoggerNode + +- (instancetype)initWithLogger:(id )logger loggerQueue:(dispatch_queue_t)loggerQueue level:(DDLogLevel)level { + if ((self = [super init])) { + _logger = logger; + + if (loggerQueue) { + _loggerQueue = loggerQueue; +#if !OS_OBJECT_USE_OBJC + dispatch_retain(loggerQueue); +#endif + } + + _level = level; + } + return self; +} + ++ (instancetype)nodeWithLogger:(id )logger loggerQueue:(dispatch_queue_t)loggerQueue level:(DDLogLevel)level { + return [[self alloc] initWithLogger:logger loggerQueue:loggerQueue level:level]; +} + +- (void)dealloc { +#if !OS_OBJECT_USE_OBJC + if (_loggerQueue) { + dispatch_release(_loggerQueue); + } +#endif +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation DDLogMessage + +- (instancetype)init { + self = [super init]; + return self; +} + +- (instancetype)initWithFormat:(NSString *)messageFormat + formatted:(NSString *)message + level:(DDLogLevel)level + flag:(DDLogFlag)flag + context:(NSInteger)context + file:(NSString *)file + function:(NSString *)function + line:(NSUInteger)line + tag:(id)tag + options:(DDLogMessageOptions)options + timestamp:(NSDate *)timestamp { + NSParameterAssert(messageFormat); + NSParameterAssert(message); + NSParameterAssert(file); + + if ((self = [super init])) { + __auto_type copyMessage = (options & DDLogMessageDontCopyMessage) == 0; + _messageFormat = copyMessage ? [messageFormat copy] : messageFormat; + _message = copyMessage ? [message copy] : message; + _level = level; + _flag = flag; + _context = context; + + __auto_type copyFile = (options & DDLogMessageCopyFile) != 0; + _file = copyFile ? [file copy] : file; + + __auto_type copyFunction = (options & DDLogMessageCopyFunction) != 0; + _function = copyFunction ? [function copy] : function; + + _line = line; + _representedObject = tag; +#if DD_LEGACY_MESSAGE_TAG +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + _tag = tag; +#pragma clang diagnostic pop +#endif + _options = options; + _timestamp = timestamp ?: [NSDate date]; + + __uint64_t tid; + if (pthread_threadid_np(NULL, &tid) == 0) { + _threadID = [[NSString alloc] initWithFormat:@"%llu", tid]; + } else { + _threadID = @"N/A"; + } + _threadName = NSThread.currentThread.name; + + // Get the file name without extension + _fileName = [_file lastPathComponent]; + __auto_type dotLocation = [_fileName rangeOfString:@"." options:NSBackwardsSearch].location; + if (dotLocation != NSNotFound) { + _fileName = [_fileName substringToIndex:dotLocation]; + } + + // Try to get the current queue's label + _queueLabel = @(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)); + _qos = (NSUInteger) qos_class_self(); + } + return self; +} + +- (instancetype)initWithFormat:(NSString *)messageFormat + args:(va_list)messageArgs + level:(DDLogLevel)level + flag:(DDLogFlag)flag + context:(NSInteger)context + file:(NSString *)file + function:(NSString *)function + line:(NSUInteger)line + tag:(id)tag + options:(DDLogMessageOptions)options + timestamp:(NSDate *)timestamp { + __auto_type copyMessage = (options & DDLogMessageDontCopyMessage) == 0; + NSString *format = copyMessage ? [messageFormat copy] : messageFormat; + self = [self initWithFormat:format + formatted:[[NSString alloc] initWithFormat:format arguments:messageArgs] + level:level + flag:flag + context:context + file:file + function:function + line:line + tag:tag + options:options | DDLogMessageDontCopyMessage // we already did the copying if needed. + timestamp:timestamp]; + return self; +} + +- (instancetype)initWithMessage:(NSString *)message + level:(DDLogLevel)level + flag:(DDLogFlag)flag + context:(NSInteger)context + file:(NSString *)file + function:(NSString *)function + line:(NSUInteger)line + tag:(id)tag + options:(DDLogMessageOptions)options + timestamp:(NSDate *)timestamp { + self = [self initWithFormat:message + formatted:message + level:level + flag:flag + context:context + file:file + function:function + line:line + tag:tag + options:options + timestamp:timestamp]; + return self; +} + +NS_INLINE BOOL _nullable_strings_equal(NSString* _Nullable lhs, NSString* _Nullable rhs) +{ + if (lhs == nil) { + if (rhs == nil) { + return YES; + } + } else if (rhs != nil && [lhs isEqualToString:(NSString* _Nonnull)rhs]) { + return YES; + } + return NO; +} + +- (BOOL)isEqual:(id)other { + // Subclasses of NSObject should not call [super isEqual:] here. + // See https://stackoverflow.com/questions/36593038/confused-about-the-default-isequal-and-hash-implements + if (other == self) { + return YES; + } else if (!other || ![other isKindOfClass:[DDLogMessage class]]) { + return NO; + } else { + __auto_type otherMsg = (DDLogMessage *)other; + return [otherMsg->_message isEqualToString:_message] + && [otherMsg->_messageFormat isEqualToString:_messageFormat] + && otherMsg->_level == _level + && otherMsg->_flag == _flag + && otherMsg->_context == _context + && [otherMsg->_file isEqualToString:_file] + && _nullable_strings_equal(otherMsg->_function, _function) + && otherMsg->_line == _line + && (([otherMsg->_representedObject respondsToSelector:@selector(isEqual:)] && [otherMsg->_representedObject isEqual:_representedObject]) || otherMsg->_representedObject == _representedObject) + && [otherMsg->_timestamp isEqualToDate:_timestamp] + && [otherMsg->_threadID isEqualToString:_threadID] // If the thread ID is the same, the name will likely be the same as well. + && [otherMsg->_queueLabel isEqualToString:_queueLabel] + && otherMsg->_qos == _qos; + } +} + +- (NSUInteger)hash { + // Subclasses of NSObject should not call [super hash] here. + // See https://stackoverflow.com/questions/36593038/confused-about-the-default-isequal-and-hash-implements + return _message.hash + ^ _messageFormat.hash + ^ _level + ^ _flag + ^ _context + ^ _file.hash + ^ _function.hash + ^ _line + ^ ([_representedObject respondsToSelector:@selector(hash)] ? [_representedObject hash] : (NSUInteger)_representedObject) + ^ _timestamp.hash + ^ _threadID.hash + ^ _queueLabel.hash + ^ _qos; +} + +- (id)copyWithZone:(NSZone * __attribute__((unused)))zone { + DDLogMessage *newMessage = [DDLogMessage new]; + + newMessage->_messageFormat = _messageFormat; + newMessage->_message = _message; + newMessage->_level = _level; + newMessage->_flag = _flag; + newMessage->_context = _context; + newMessage->_file = _file; + newMessage->_fileName = _fileName; + newMessage->_function = _function; + newMessage->_line = _line; + newMessage->_representedObject = _representedObject; +#if DD_LEGACY_MESSAGE_TAG +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + newMessage->_tag = _tag; +#pragma clang diagnostic pop +#endif + newMessage->_options = _options; + newMessage->_timestamp = _timestamp; + newMessage->_threadID = _threadID; + newMessage->_threadName = _threadName; + newMessage->_queueLabel = _queueLabel; + newMessage->_qos = _qos; + + return newMessage; +} + +// ensure compatibility even when built with DD_LEGACY_MESSAGE_TAG to 0. +- (id)tag { + return _representedObject; +} + +@end + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation DDAbstractLogger + +- (instancetype)init { + if ((self = [super init])) { + const char *loggerQueueName = NULL; + + if ([self respondsToSelector:@selector(loggerName)]) { + loggerQueueName = self.loggerName.UTF8String; + } + + _loggerQueue = dispatch_queue_create(loggerQueueName, NULL); + + // We're going to use dispatch_queue_set_specific() to "mark" our loggerQueue. + // Later we can use dispatch_get_specific() to determine if we're executing on our loggerQueue. + // The documentation states: + // + // > Keys are only compared as pointers and are never dereferenced. + // > Thus, you can use a pointer to a static variable for a specific subsystem or + // > any other value that allows you to identify the value uniquely. + // > Specifying a pointer to a string constant is not recommended. + // + // So we're going to use the very convenient key of "self", + // which also works when multiple logger classes extend this class, as each will have a different "self" key. + // + // This is used primarily for thread-safety assertions (via the isOnInternalLoggerQueue method below). + + __auto_type key = (__bridge void *)self; + __auto_type nonNullValue = (__bridge void *)self; + + dispatch_queue_set_specific(_loggerQueue, key, nonNullValue, NULL); + } + + return self; +} + +- (void)dealloc { +#if !OS_OBJECT_USE_OBJC + if (_loggerQueue) { + dispatch_release(_loggerQueue); + } +#endif +} + +- (void)logMessage:(DDLogMessage * __attribute__((unused)))logMessage { + // Override me +} + +- (id )logFormatter { + // This method must be thread safe and intuitive. + // Therefore if somebody executes the following code: + // + // [logger setLogFormatter:myFormatter]; + // formatter = [logger logFormatter]; + // + // They would expect formatter to equal myFormatter. + // This functionality must be ensured by the getter and setter method. + // + // The thread safety must not come at a cost to the performance of the logMessage method. + // This method is likely called sporadically, while the logMessage method is called repeatedly. + // This means, the implementation of this method: + // - Must NOT require the logMessage method to acquire a lock. + // - Must NOT require the logMessage method to access an atomic property (also a lock of sorts). + // + // Thread safety is ensured by executing access to the formatter variable on the loggerQueue. + // This is the same queue that the logMessage method operates on. + // + // Note: The last time I benchmarked the performance of direct access vs atomic property access, + // direct access was over twice as fast on the desktop and over 6 times as fast on the iPhone. + // + // Furthermore, consider the following code: + // + // DDLogVerbose(@"log msg 1"); + // DDLogVerbose(@"log msg 2"); + // [logger setFormatter:myFormatter]; + // DDLogVerbose(@"log msg 3"); + // + // Our intuitive requirement means that the new formatter will only apply to the 3rd log message. + // This must remain true even when using asynchronous logging. + // We must keep in mind the various queue's that are in play here: + // + // loggerQueue : Our own private internal queue that the logMessage method runs on. + // Operations are added to this queue from the global loggingQueue. + // + // globalLoggingQueue : The queue that all log messages go through before they arrive in our loggerQueue. + // + // All log statements go through the serial globalLoggingQueue before they arrive at our loggerQueue. + // Thus this method also goes through the serial globalLoggingQueue to ensure intuitive operation. + + // IMPORTANT NOTE: + // + // Methods within the DDLogger implementation MUST access the formatter ivar directly. + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + + __block id result; + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self->_loggerQueue, ^{ + result = self->_logFormatter; + }); + }); + + return result; +} + +- (void)setLogFormatter:(id )logFormatter { + // The design of this method is documented extensively in the logFormatter message (above in code). + + DDAbstractLoggerAssertLockedPropertyAccess(); + + __auto_type block = ^{ + @autoreleasepool { + if (self->_logFormatter != logFormatter) { + if ([self->_logFormatter respondsToSelector:@selector(willRemoveFromLogger:)]) { + [self->_logFormatter willRemoveFromLogger:self]; + } + + self->_logFormatter = logFormatter; + + if ([self->_logFormatter respondsToSelector:@selector(didAddToLogger:inQueue:)]) { + [self->_logFormatter didAddToLogger:self inQueue:self->_loggerQueue]; + } else if ([self->_logFormatter respondsToSelector:@selector(didAddToLogger:)]) { + [self->_logFormatter didAddToLogger:self]; + } + } + } + }; + + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self->_loggerQueue, block); + }); +} + +- (dispatch_queue_t)loggerQueue { + return _loggerQueue; +} + +- (NSString *)loggerName { + return NSStringFromClass([self class]); +} + +- (BOOL)isOnGlobalLoggingQueue { + return (dispatch_get_specific(GlobalLoggingQueueIdentityKey) != NULL); +} + +- (BOOL)isOnInternalLoggerQueue { + return dispatch_get_specific((__bridge void *)self) != NULL; +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface DDLoggerInformation() +{ + // Direct accessors to be used only for performance + @public + id _logger; + DDLogLevel _level; +} + +@end + +@implementation DDLoggerInformation + +- (instancetype)initWithLogger:(id )logger andLevel:(DDLogLevel)level { + if ((self = [super init])) { + _logger = logger; + _level = level; + } + return self; +} + ++ (instancetype)informationWithLogger:(id )logger andLevel:(DDLogLevel)level { + return [[self alloc] initWithLogger:logger andLevel:level]; +} + +@end diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDLoggerNames.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDLoggerNames.m new file mode 100644 index 0000000..ffe6e33 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDLoggerNames.m @@ -0,0 +1,21 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +DDLoggerName const DDLoggerNameASL = @"cocoa.lumberjack.aslLogger"; +DDLoggerName const DDLoggerNameTTY = @"cocoa.lumberjack.ttyLogger"; +DDLoggerName const DDLoggerNameOS = @"cocoa.lumberjack.osLogger"; +DDLoggerName const DDLoggerNameFile = @"cocoa.lumberjack.fileLogger"; diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDOSLogger.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDOSLogger.m new file mode 100644 index 0000000..3ee583c --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDOSLogger.m @@ -0,0 +1,158 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import +#import + +#import + +@implementation DDOSLogLevelMapperDefault + +- (instancetype)init { + self = [super init]; + return self; +} + +- (os_log_type_t)osLogTypeForLogFlag:(DDLogFlag)logFlag { + switch (logFlag) { + case DDLogFlagError: + case DDLogFlagWarning: + return OS_LOG_TYPE_ERROR; + case DDLogFlagInfo: + return OS_LOG_TYPE_INFO; + case DDLogFlagDebug: + case DDLogFlagVerbose: + return OS_LOG_TYPE_DEBUG; + default: + return OS_LOG_TYPE_DEFAULT; + } +} + +@end + +#if TARGET_OS_SIMULATOR +@implementation DDOSLogLevelMapperSimulatorConsoleAppWorkaround + +- (os_log_type_t)osLogTypeForLogFlag:(DDLogFlag)logFlag { + __auto_type defaultMapping = [super osLogTypeForLogFlag:logFlag]; + return (defaultMapping == OS_LOG_TYPE_DEBUG) ? OS_LOG_TYPE_DEFAULT : defaultMapping; +} + +@end +#endif + +@interface DDOSLogger () + +@property (nonatomic, copy, readonly, nullable) NSString *subsystem; +@property (nonatomic, copy, readonly, nullable) NSString *category; +@property (nonatomic, strong, readonly, nonnull) os_log_t logger; + +@end + +@implementation DDOSLogger + +@synthesize subsystem = _subsystem; +@synthesize category = _category; +@synthesize logLevelMapper = _logLevelMapper; +@synthesize logger = _logger; + +#pragma mark - Shared Instance + +API_AVAILABLE(macos(10.12), ios(10.0), watchos(3.0), tvos(10.0)) +static DDOSLogger *sharedInstance; + ++ (instancetype)sharedInstance { + static dispatch_once_t DDOSLoggerOnceToken; + + dispatch_once(&DDOSLoggerOnceToken, ^{ + sharedInstance = [[[self class] alloc] init]; + }); + + return sharedInstance; +} + +#pragma mark - Initialization +- (instancetype)initWithSubsystem:(NSString *)subsystem category:(NSString *)category { + NSAssert((subsystem == nil) == (category == nil), + @"Either both subsystem and category or neither should be nil."); + if (self = [super init]) { + _subsystem = [subsystem copy]; + _category = [category copy]; + _logLevelMapper = [[DDOSLogLevelMapperDefault alloc] init]; + } + return self; +} + +- (instancetype)init { + return [self initWithSubsystem:nil category:nil]; +} + +- (instancetype)initWithSubsystem:(NSString *)subsystem + category:(NSString *)category + logLevelMapper:(id)logLevelMapper { + if (self = [self initWithSubsystem:subsystem category:category]) { + NSParameterAssert(logLevelMapper); + _logLevelMapper = logLevelMapper; + } + return self; +} + +- (instancetype)initWithLogLevelMapper:(id)logLevelMapper { + return [self initWithSubsystem:nil category:nil logLevelMapper:logLevelMapper]; +} + +#pragma mark - Mapper +- (id)logLevelMapper { + if (_logLevelMapper == nil) { + _logLevelMapper = [[DDOSLogLevelMapperDefault alloc] init]; + } + return _logLevelMapper; +} + +#pragma mark - os_log +- (os_log_t)logger { + if (_logger == nil) { + if (self.subsystem == nil || self.category == nil) { + _logger = OS_LOG_DEFAULT; + } else { + _logger = os_log_create(self.subsystem.UTF8String, self.category.UTF8String); + } + } + return _logger; +} + +#pragma mark - DDLogger +- (DDLoggerName)loggerName { + return DDLoggerNameOS; +} + +- (void)logMessage:(DDLogMessage *)logMessage { +#if !TARGET_OS_WATCH // See DDASLLogCapture.m -> Was never supported on watchOS. + // Skip captured log messages. + if ([logMessage->_fileName isEqualToString:@"DDASLLogCapture"]) { + return; + } +#endif + + if (@available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)) { + __auto_type message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message; + if (message != nil) { + __auto_type logType = [self.logLevelMapper osLogTypeForLogFlag:logMessage->_flag]; + os_log_with_type(self.logger, logType, "%{public}s", message.UTF8String); + } + } +} + +@end diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDTTYLogger.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDTTYLogger.m new file mode 100644 index 0000000..20d08b7 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/DDTTYLogger.m @@ -0,0 +1,1446 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +#import + +#import + +// We probably shouldn't be using DDLog() statements within the DDLog implementation. +// But we still want to leave our log statements for any future debugging, +// and to allow other developers to trace the implementation (which is a great learning tool). +// +// So we use primitive logging macros around NSLog. +// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog. + +#ifndef DD_NSLOG_LEVEL + #define DD_NSLOG_LEVEL 2 +#endif + +#define NSLogError(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0) +#define NSLogWarn(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0) +#define NSLogInfo(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0) +#define NSLogDebug(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0) +#define NSLogVerbose(frmt, ...) do{ if(DD_NSLOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0) + +// Xcode does NOT natively support colors in the Xcode debugging console. +// You'll need to install the XcodeColors plugin to see colors in the Xcode console. +// https://github.com/robbiehanson/XcodeColors +// +// The following is documentation from the XcodeColors project: +// +// +// How to apply color formatting to your log statements: +// +// To set the foreground color: +// Insert the ESCAPE_SEQ into your string, followed by "fg124,12,255;" where r=124, g=12, b=255. +// +// To set the background color: +// Insert the ESCAPE_SEQ into your string, followed by "bg12,24,36;" where r=12, g=24, b=36. +// +// To reset the foreground color (to default value): +// Insert the ESCAPE_SEQ into your string, followed by "fg;" +// +// To reset the background color (to default value): +// Insert the ESCAPE_SEQ into your string, followed by "bg;" +// +// To reset the foreground and background color (to default values) in one operation: +// Insert the ESCAPE_SEQ into your string, followed by ";" + +#define XCODE_COLORS_ESCAPE_SEQ "\033[" + +#define XCODE_COLORS_RESET_FG XCODE_COLORS_ESCAPE_SEQ "fg;" // Clear any foreground color +#define XCODE_COLORS_RESET_BG XCODE_COLORS_ESCAPE_SEQ "bg;" // Clear any background color +#define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE_SEQ ";" // Clear any foreground or background color + +// If running in a shell, not all RGB colors will be supported. +// In this case we automatically map to the closest available color. +// In order to provide this mapping, we have a hard-coded set of the standard RGB values available in the shell. +// However, not every shell is the same, and Apple likes to think different even when it comes to shell colors. +// +// Map to standard Terminal.app colors (1), or +// map to standard xterm colors (0). + +#define MAP_TO_TERMINAL_APP_COLORS 1 + +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} DDRGBColor; + +@interface DDTTYLoggerColorProfile : NSObject { +@public + DDLogFlag mask; + NSInteger context; + + DDRGBColor fg; + DDRGBColor bg; + + NSUInteger fgCodeIndex; + NSString *fgCodeRaw; + + NSUInteger bgCodeIndex; + NSString *bgCodeRaw; + + char fgCode[24]; + size_t fgCodeLen; + + char bgCode[24]; + size_t bgCodeLen; + + char resetCode[8]; + size_t resetCodeLen; +} + +- (nullable instancetype)initWithForegroundColor:(nullable DDColor *)fgColor backgroundColor:(nullable DDColor *)bgColor flag:(DDLogFlag)mask context:(NSInteger)ctxt; + +@end + +@interface DDTTYLogger () { + NSString *_appName; + char *_app; + size_t _appLen; + + NSString *_processID; + char *_pid; + size_t _pidLen; + + BOOL _colorsEnabled; + NSMutableArray *_colorProfilesArray; + NSMutableDictionary *_colorProfilesDict; +} + +@end + +#pragma mark - + +@implementation DDTTYLogger + +static BOOL isaColorTTY; +static BOOL isaColor256TTY; +static BOOL isaXcodeColorTTY; + +static NSArray *codesFg = nil; +static NSArray *codesBg = nil; +static NSArray *colors = nil; + +static DDTTYLogger *sharedInstance; + +/** + * Initializes the colors array, as well as the `codesFg` and `codesBg` arrays, for 16 color mode. + * + * This method is used when the application is running from within a shell that only supports 16 color mode. + * This method is not invoked if the application is running within Xcode, or via normal UI app launch. + **/ ++ (void)initializeColors16 { + if (codesFg || codesBg || colors) { + return; + } + + __auto_type mColors = [NSMutableArray arrayWithCapacity:16]; + + // In a standard shell only 16 colors are supported. + // + // More information about ansi escape codes can be found online. + // http://en.wikipedia.org/wiki/ANSI_escape_code + codesFg = @[ + @"30m", // normal - black + @"31m", // normal - red + @"32m", // normal - green + @"33m", // normal - yellow + @"34m", // normal - blue + @"35m", // normal - magenta + @"36m", // normal - cyan + @"37m", // normal - gray + @"1;30m", // bright - darkgray + @"1;31m", // bright - red + @"1;32m", // bright - green + @"1;33m", // bright - yellow + @"1;34m", // bright - blue + @"1;35m", // bright - magenta + @"1;36m", // bright - cyan + @"1;37m", // bright - white + ]; + + codesBg = @[ + @"40m", // normal - black + @"41m", // normal - red + @"42m", // normal - green + @"43m", // normal - yellow + @"44m", // normal - blue + @"45m", // normal - magenta + @"46m", // normal - cyan + @"47m", // normal - gray + @"1;40m", // bright - darkgray + @"1;41m", // bright - red + @"1;42m", // bright - green + @"1;43m", // bright - yellow + @"1;44m", // bright - blue + @"1;45m", // bright - magenta + @"1;46m", // bright - cyan + @"1;47m", // bright - white + ]; + +#if MAP_TO_TERMINAL_APP_COLORS + + // Standard Terminal.app colors: + // + // These are the default colors used by Apple's Terminal.app. + const DDRGBColor rgbColors[] = { + { 0, 0, 0}, // normal - black + {194, 54, 33}, // normal - red + { 37, 188, 36}, // normal - green + {173, 173, 39}, // normal - yellow + { 73, 46, 225}, // normal - blue + {211, 56, 211}, // normal - magenta + { 51, 187, 200}, // normal - cyan + {203, 204, 205}, // normal - gray + {129, 131, 131}, // bright - darkgray + {252, 57, 31}, // bright - red + { 49, 231, 34}, // bright - green + {234, 236, 35}, // bright - yellow + { 88, 51, 255}, // bright - blue + {249, 53, 248}, // bright - magenta + { 20, 240, 240}, // bright - cyan + {233, 235, 235}, // bright - white + }; + +#else /* if MAP_TO_TERMINAL_APP_COLORS */ + + // Standard xterm colors: + // + // These are the default colors used by most xterm shells. + const DDRGBColor rgbColors[] = { + { 0, 0, 0}, // normal - black + {205, 0, 0}, // normal - red + { 0, 205, 0}, // normal - green + {205, 205, 0}, // normal - yellow + { 0, 0, 238}, // normal - blue + {205, 0, 205}, // normal - magenta + { 0, 205, 205}, // normal - cyan + {229, 229, 229}, // normal - gray + {127, 127, 127}, // bright - darkgray + {255, 0, 0}, // bright - red + { 0, 255, 0}, // bright - green + {255, 255, 0}, // bright - yellow + { 92, 92, 255}, // bright - blue + {255, 0, 255}, // bright - magenta + { 0, 255, 255}, // bright - cyan + {255, 255, 255}, // bright - white + }; +#endif /* if MAP_TO_TERMINAL_APP_COLORS */ + + for (size_t i = 0; i < sizeof(rgbColors) / sizeof(rgbColors[0]); ++i) { + [mColors addObject:DDMakeColor(rgbColors[i].r, rgbColors[i].g, rgbColors[i].b)]; + } + colors = [mColors copy]; + + NSAssert([codesFg count] == [codesBg count], @"Invalid colors/codes array(s)"); + NSAssert([codesFg count] == [colors count], @"Invalid colors/codes array(s)"); +} + +/** + * Initializes the colors array, as well as the `codesFg` and `codesBg` arrays, for 256 color mode. + * + * This method is used when the application is running from within a shell that supports 256 color mode. + * This method is not invoked if the application is running within Xcode, or via normal UI app launch. + **/ ++ (void)initializeColors256 { + if (codesFg || codesBg || colors) { + return; + } + + __auto_type mCodesFg = [NSMutableArray arrayWithCapacity:(256 - 16)]; + __auto_type mCodesBg = [NSMutableArray arrayWithCapacity:(256 - 16)]; + __auto_type mColors = [NSMutableArray arrayWithCapacity:(256 - 16)]; + +#if MAP_TO_TERMINAL_APP_COLORS + + // Standard Terminal.app colors: + // + // These are the colors the Terminal.app uses in xterm-256color mode. + // In this mode, the terminal supports 256 different colors, specified by 256 color codes. + // + // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode. + // These are actually configurable, and thus we ignore them for the purposes of mapping, + // as we can't rely on them being constant. They are largely duplicated anyway. + // + // The next 216 color codes are designed to run the spectrum, with several shades of every color. + // While the color codes are standardized, the actual RGB values for each color code is not. + // Apple's Terminal.app uses different RGB values from that of a standard xterm. + // Apple's choices in colors are designed to be a little nicer on the eyes. + // + // The last 24 color codes represent a grayscale. + // + // Unfortunately, unlike the standard xterm color chart, + // Apple's RGB values cannot be calculated using a simple formula (at least not that I know of). + // Also, I don't know of any ways to programmatically query the shell for the RGB values. + // So this big giant color chart had to be made by hand. + // + // More information about ansi escape codes can be found online. + // http://en.wikipedia.org/wiki/ANSI_escape_code + + // Colors + const DDRGBColor rgbColors[] = { + { 47, 49, 49}, + { 60, 42, 144}, + { 66, 44, 183}, + { 73, 46, 222}, + { 81, 50, 253}, + { 88, 51, 255}, + + { 42, 128, 37}, + { 42, 127, 128}, + { 44, 126, 169}, + { 56, 125, 209}, + { 59, 124, 245}, + { 66, 123, 255}, + + { 51, 163, 41}, + { 39, 162, 121}, + { 42, 161, 162}, + { 53, 160, 202}, + { 45, 159, 240}, + { 58, 158, 255}, + + { 31, 196, 37}, + { 48, 196, 115}, + { 39, 195, 155}, + { 49, 195, 195}, + { 32, 194, 235}, + { 53, 193, 255}, + + { 50, 229, 35}, + { 40, 229, 109}, + { 27, 229, 149}, + { 49, 228, 189}, + { 33, 228, 228}, + { 53, 227, 255}, + + { 27, 254, 30}, + { 30, 254, 103}, + { 45, 254, 143}, + { 38, 253, 182}, + { 38, 253, 222}, + { 42, 253, 252}, + + {140, 48, 40}, + {136, 51, 136}, + {135, 52, 177}, + {134, 52, 217}, + {135, 56, 248}, + {134, 53, 255}, + + {125, 125, 38}, + {124, 125, 125}, + {122, 124, 166}, + {123, 124, 207}, + {123, 122, 247}, + {124, 121, 255}, + + {119, 160, 35}, + {117, 160, 120}, + {117, 160, 160}, + {115, 159, 201}, + {116, 158, 240}, + {117, 157, 255}, + + {113, 195, 39}, + {110, 194, 114}, + {111, 194, 154}, + {108, 194, 194}, + {109, 193, 234}, + {108, 192, 255}, + + {105, 228, 30}, + {103, 228, 109}, + {105, 228, 148}, + {100, 227, 188}, + { 99, 227, 227}, + { 99, 226, 253}, + + { 92, 253, 34}, + { 96, 253, 103}, + { 97, 253, 142}, + { 88, 253, 182}, + { 93, 253, 221}, + { 88, 254, 251}, + + {177, 53, 34}, + {174, 54, 131}, + {172, 55, 172}, + {171, 57, 213}, + {170, 55, 249}, + {170, 57, 255}, + + {165, 123, 37}, + {163, 123, 123}, + {162, 123, 164}, + {161, 122, 205}, + {161, 121, 241}, + {161, 121, 255}, + + {158, 159, 33}, + {157, 158, 118}, + {157, 158, 159}, + {155, 157, 199}, + {155, 157, 239}, + {154, 156, 255}, + + {152, 193, 40}, + {151, 193, 113}, + {150, 193, 153}, + {150, 192, 193}, + {148, 192, 232}, + {149, 191, 253}, + + {146, 227, 28}, + {144, 227, 108}, + {144, 227, 147}, + {144, 227, 187}, + {142, 226, 227}, + {142, 225, 252}, + + {138, 253, 36}, + {137, 253, 102}, + {136, 253, 141}, + {138, 254, 181}, + {135, 255, 220}, + {133, 255, 250}, + + {214, 57, 30}, + {211, 59, 126}, + {209, 57, 168}, + {208, 55, 208}, + {207, 58, 247}, + {206, 61, 255}, + + {204, 121, 32}, + {202, 121, 121}, + {201, 121, 161}, + {200, 120, 202}, + {200, 120, 241}, + {198, 119, 255}, + + {198, 157, 37}, + {196, 157, 116}, + {195, 156, 157}, + {195, 156, 197}, + {194, 155, 236}, + {193, 155, 255}, + + {191, 192, 36}, + {190, 191, 112}, + {189, 191, 152}, + {189, 191, 191}, + {188, 190, 230}, + {187, 190, 253}, + + {185, 226, 28}, + {184, 226, 106}, + {183, 225, 146}, + {183, 225, 186}, + {182, 225, 225}, + {181, 224, 252}, + + {178, 255, 35}, + {178, 255, 101}, + {177, 254, 141}, + {176, 254, 180}, + {176, 254, 220}, + {175, 253, 249}, + + {247, 56, 30}, + {245, 57, 122}, + {243, 59, 163}, + {244, 60, 204}, + {242, 59, 241}, + {240, 55, 255}, + + {241, 119, 36}, + {240, 120, 118}, + {238, 119, 158}, + {237, 119, 199}, + {237, 118, 238}, + {236, 118, 255}, + + {235, 154, 36}, + {235, 154, 114}, + {234, 154, 154}, + {232, 154, 194}, + {232, 153, 234}, + {232, 153, 255}, + + {230, 190, 30}, + {229, 189, 110}, + {228, 189, 150}, + {227, 189, 190}, + {227, 189, 229}, + {226, 188, 255}, + + {224, 224, 35}, + {223, 224, 105}, + {222, 224, 144}, + {222, 223, 184}, + {222, 223, 224}, + {220, 223, 253}, + + {217, 253, 28}, + {217, 253, 99}, + {216, 252, 139}, + {216, 252, 179}, + {215, 252, 218}, + {215, 251, 250}, + + {255, 61, 30}, + {255, 60, 118}, + {255, 58, 159}, + {255, 56, 199}, + {255, 55, 238}, + {255, 59, 255}, + + {255, 117, 29}, + {255, 117, 115}, + {255, 117, 155}, + {255, 117, 195}, + {255, 116, 235}, + {254, 116, 255}, + + {255, 152, 27}, + {255, 152, 111}, + {254, 152, 152}, + {255, 152, 192}, + {254, 151, 231}, + {253, 151, 253}, + + {255, 187, 33}, + {253, 187, 107}, + {252, 187, 148}, + {253, 187, 187}, + {254, 187, 227}, + {252, 186, 252}, + + {252, 222, 34}, + {251, 222, 103}, + {251, 222, 143}, + {250, 222, 182}, + {251, 221, 222}, + {252, 221, 252}, + + {251, 252, 15}, + {251, 252, 97}, + {249, 252, 137}, + {247, 252, 177}, + {247, 253, 217}, + {254, 255, 255}, + + // Grayscale + + { 52, 53, 53}, + { 57, 58, 59}, + { 66, 67, 67}, + { 75, 76, 76}, + { 83, 85, 85}, + { 92, 93, 94}, + + {101, 102, 102}, + {109, 111, 111}, + {118, 119, 119}, + {126, 127, 128}, + {134, 136, 136}, + {143, 144, 145}, + + {151, 152, 153}, + {159, 161, 161}, + {167, 169, 169}, + {176, 177, 177}, + {184, 185, 186}, + {192, 193, 194}, + + {200, 201, 202}, + {208, 209, 210}, + {216, 218, 218}, + {224, 226, 226}, + {232, 234, 234}, + {240, 242, 242}, + }; + + for (size_t i = 0; i < sizeof(rgbColors) / sizeof(rgbColors[0]); ++i) { + [mColors addObject:DDMakeColor(rgbColors[i].r, rgbColors[i].g, rgbColors[i].b)]; + } + + // Color codes + int index = 16; + while (index < 256) { + [mCodesFg addObject:[NSString stringWithFormat:@"38;5;%dm", index]]; + [mCodesBg addObject:[NSString stringWithFormat:@"48;5;%dm", index]]; + + index++; + } + +#else /* if MAP_TO_TERMINAL_APP_COLORS */ + + // Standard xterm colors: + // + // These are the colors xterm shells use in xterm-256color mode. + // In this mode, the shell supports 256 different colors, specified by 256 color codes. + // + // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode. + // These are generally configurable, and thus we ignore them for the purposes of mapping, + // as we can't rely on them being constant. They are largely duplicated anyway. + // + // The next 216 color codes are designed to run the spectrum, with several shades of every color. + // The last 24 color codes represent a grayscale. + // + // While the color codes are standardized, the actual RGB values for each color code is not. + // However most standard xterms follow a well known color chart, + // which can easily be calculated using the simple formula below. + // + // More information about ansi escape codes can be found online. + // http://en.wikipedia.org/wiki/ANSI_escape_code + + int index = 16; + + int r; // red + int g; // green + int b; // blue + + int ri; // r increment + int gi; // g increment + int bi; // b increment + + // Calculate xterm colors (using standard algorithm) + + int r = 0; + int g = 0; + int b = 0; + + for (ri = 0; ri < 6; ri++) { + r = (ri == 0) ? 0 : 95 + (40 * (ri - 1)); + + for (gi = 0; gi < 6; gi++) { + g = (gi == 0) ? 0 : 95 + (40 * (gi - 1)); + + for (bi = 0; bi < 6; bi++) { + b = (bi == 0) ? 0 : 95 + (40 * (bi - 1)); + + [mCodesFg addObject:[NSString stringWithFormat:@"38;5;%dm", index]]; + [mCodesBg addObject:[NSString stringWithFormat:@"48;5;%dm", index]]; + [mColors addObject:DDMakeColor(r, g, b)]; + + index++; + } + } + } + + // Calculate xterm grayscale (using standard algorithm) + + r = 8; + g = 8; + b = 8; + + while (index < 256) { + [mCodesFg addObject:[NSString stringWithFormat:@"38;5;%dm", index]]; + [mCodesBg addObject:[NSString stringWithFormat:@"48;5;%dm", index]]; + [mColor s addObject:DDMakeColor(r, g, b)]; + + r += 10; + g += 10; + b += 10; + + index++; + } + +#endif /* if MAP_TO_TERMINAL_APP_COLORS */ + + codesFg = [mCodesFg copy]; + codesBg = [mCodesBg copy]; + colors = [mColors copy]; + + NSAssert([codesFg count] == [codesBg count], @"Invalid colors/codes array(s)"); + NSAssert([codesFg count] == [colors count], @"Invalid colors/codes array(s)"); +} + ++ (void)getRed:(CGFloat *)rPtr green:(CGFloat *)gPtr blue:(CGFloat *)bPtr fromColor:(DDColor *)color { +#if TARGET_OS_IPHONE + + // iOS + __auto_type done = NO; + + if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)]) { + done = [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL]; + } + + if (!done) { + // The method getRed:green:blue:alpha: was only available starting iOS 5. + // So in iOS 4 and earlier, we have to jump through hoops. + + __auto_type rgbColorSpace = CGColorSpaceCreateDeviceRGB(); + + unsigned char pixel[4]; + __auto_type context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, rgbColorSpace, (CGBitmapInfo)(kCGBitmapAlphaInfoMask & kCGImageAlphaNoneSkipLast)); + + CGContextSetFillColorWithColor(context, [color CGColor]); + CGContextFillRect(context, CGRectMake(0, 0, 1, 1)); + + if (rPtr) { + *rPtr = pixel[0] / 255.0; + } + if (gPtr) { + *gPtr = pixel[1] / 255.0; + } + if (bPtr) { + *bPtr = pixel[2] / 255.0; + } + + CGContextRelease(context); + CGColorSpaceRelease(rgbColorSpace); + } + +#elif defined(DD_CLI) || !__has_include() + + // OS X without AppKit + [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL]; + +#else /* if TARGET_OS_IPHONE */ + + // OS X with AppKit + NSColor *safeColor; + if (@available(macOS 10.14,*)) { + safeColor = [color colorUsingColorSpace:NSColorSpace.deviceRGBColorSpace]; + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + safeColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; +#pragma clang diagnostic pop + } + + [safeColor getRed:rPtr green:gPtr blue:bPtr alpha:NULL]; + +#endif /* if TARGET_OS_IPHONE */ +} + +/** + * Maps the given color to the closest available color supported by the shell. + * The shell may support 256 colors, or only 16. + * + * This method loops through the known supported color set, and calculates the closest color. + * The array index of that color, within the colors array, is then returned. + * This array index may also be used as the index within the `codesFg` and `codesBg` arrays. + **/ ++ (NSUInteger)codeIndexForColor:(DDColor *)inColor { + CGFloat inR, inG, inB; + + [self getRed:&inR green:&inG blue:&inB fromColor:inColor]; + + NSUInteger bestIndex = 0; + CGFloat lowestDistance = 100.0; + + NSUInteger i = 0; + + for (DDColor *color in colors) { + // Calculate Euclidean distance (lower value means closer to given color) + + CGFloat r, g, b; + [self getRed:&r green:&g blue:&b fromColor:color]; + +#if CGFLOAT_IS_DOUBLE + __auto_type distance = sqrt(pow(r - inR, 2.0) + pow(g - inG, 2.0) + pow(b - inB, 2.0)); +#else + __auto_type distance = sqrtf(powf(r - inR, 2.0f) + powf(g - inG, 2.0f) + powf(b - inB, 2.0f)); +#endif + + NSLogVerbose(@"DDTTYLogger: %3lu : %.3f,%.3f,%.3f & %.3f,%.3f,%.3f = %.6f", + (unsigned long)i, (double)inR, (double)inG, (double)inB, (double)r, (double)g, (double)b, (double)distance); + + if (distance < lowestDistance) { + bestIndex = i; + lowestDistance = distance; + + NSLogVerbose(@"DDTTYLogger: New best index = %lu", (unsigned long)bestIndex); + } + + i++; + } + + return bestIndex; +} + ++ (instancetype)sharedInstance { + static dispatch_once_t DDTTYLoggerOnceToken; + + dispatch_once(&DDTTYLoggerOnceToken, ^{ + // Xcode does NOT natively support colors in the Xcode debugging console. + // You'll need to install the XcodeColors plugin to see colors in the Xcode console. + // + // PS - Please read the header file before diving into the source code. + + __auto_type xcodeColors = getenv("XcodeColors"); + __auto_type term = getenv("TERM"); + + if (xcodeColors && (strcmp(xcodeColors, "YES") == 0)) { + isaXcodeColorTTY = YES; + } else if (term) { + if (strcasestr(term, "color") != NULL) { + isaColorTTY = YES; + isaColor256TTY = (strcasestr(term, "256") != NULL); + + if (isaColor256TTY) { + [self initializeColors256]; + } else { + [self initializeColors16]; + } + } + } + + NSLogInfo(@"DDTTYLogger: isaColorTTY = %@", (isaColorTTY ? @"YES" : @"NO")); + NSLogInfo(@"DDTTYLogger: isaColor256TTY: %@", (isaColor256TTY ? @"YES" : @"NO")); + NSLogInfo(@"DDTTYLogger: isaXcodeColorTTY: %@", (isaXcodeColorTTY ? @"YES" : @"NO")); + + sharedInstance = [[self alloc] init]; + }); + + return sharedInstance; +} + +- (instancetype)init { + if (sharedInstance != nil) { + return nil; + } + +#if !defined(DD_CLI) || __has_include() + if (@available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)) { + NSLogWarn(@"CocoaLumberjack: Warning: Usage of DDTTYLogger detected when DDOSLogger is available and can be used! Please consider migrating to DDOSLogger."); + } +#endif + + if ((self = [super init])) { + // Initialize 'app' variable (char *) + _appName = [[NSProcessInfo processInfo] processName]; + _appLen = [_appName lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + + if (_appLen == 0) { + _appName = @""; + _appLen = [_appName lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + } + + _app = (char *)calloc(_appLen + 1, sizeof(char)); + if (_app == NULL) { + return nil; + } + + BOOL processedAppName = [_appName getCString:_app maxLength:(_appLen + 1) encoding:NSUTF8StringEncoding]; + if (!processedAppName) { + free(_app); + return nil; + } + + // Initialize 'pid' variable (char *) + + _processID = [NSString stringWithFormat:@"%i", (int)getpid()]; + + _pidLen = [_processID lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + _pid = (char *)calloc(_pidLen + 1, sizeof(char)); + + if (_pid == NULL) { + free(_app); + return nil; + } + + BOOL processedID = [_processID getCString:_pid maxLength:(_pidLen + 1) encoding:NSUTF8StringEncoding]; + if (!processedID) { + free(_app); + free(_pid); + return nil; + } + + // Initialize color stuff + + _colorsEnabled = NO; + _colorProfilesArray = [[NSMutableArray alloc] initWithCapacity:8]; + _colorProfilesDict = [[NSMutableDictionary alloc] initWithCapacity:8]; + + _automaticallyAppendNewlineForCustomFormatters = YES; + } + + return self; +} + +- (DDLoggerName)loggerName { + return DDLoggerNameTTY; +} + +- (void)loadDefaultColorProfiles { + [self setForegroundColor:DDMakeColor(214, 57, 30) backgroundColor:nil forFlag:DDLogFlagError]; + [self setForegroundColor:DDMakeColor(204, 121, 32) backgroundColor:nil forFlag:DDLogFlagWarning]; +} + +- (BOOL)colorsEnabled { + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + __block BOOL result; + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.loggerQueue, ^{ + result = self->_colorsEnabled; + }); + }); + + return result; +} + +- (void)setColorsEnabled:(BOOL)newColorsEnabled { + __auto_type block = ^{ + @autoreleasepool { + self->_colorsEnabled = newColorsEnabled; + + if ([self->_colorProfilesArray count] == 0) { + [self loadDefaultColorProfiles]; + } + } + }; + + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + // Note: The internal implementation MUST access the colorsEnabled variable directly, + // This method is designed explicitly for external access. + // + // Using "self." syntax to go through this method will cause immediate deadlock. + // This is the intended result. Fix it by accessing the ivar directly. + // Great strides have been take to ensure this is safe to do. Plus it's MUCH faster. + + DDAbstractLoggerAssertLockedPropertyAccess(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); +} + +- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forFlag:(DDLogFlag)mask { + [self setForegroundColor:txtColor backgroundColor:bgColor forFlag:mask context:LOG_CONTEXT_ALL]; +} + +- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forFlag:(DDLogFlag)mask context:(NSInteger)ctxt { + dispatch_block_t block = ^{ + @autoreleasepool { + DDTTYLoggerColorProfile *newColorProfile = [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor + backgroundColor:bgColor + flag:mask + context:ctxt]; + if (!newColorProfile) return; + + NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile); + + NSUInteger i = 0; + + for (DDTTYLoggerColorProfile *colorProfile in self->_colorProfilesArray) { + if ((colorProfile->mask == mask) && (colorProfile->context == ctxt)) { + break; + } + + i++; + } + + if (i < [self->_colorProfilesArray count]) { + self->_colorProfilesArray[i] = newColorProfile; + } else { + [self->_colorProfilesArray addObject:newColorProfile]; + } + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forTag:(id )tag { + NSAssert([(id )tag conformsToProtocol: @protocol(NSCopying)], @"Invalid tag"); + + __auto_type block = ^{ + @autoreleasepool { + __auto_type newColorProfile = [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor + backgroundColor:bgColor + flag:(DDLogFlag)0 + context:0]; + + NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile); + + self->_colorProfilesDict[tag] = newColorProfile; + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (void)clearColorsForFlag:(DDLogFlag)mask { + [self clearColorsForFlag:mask context:0]; +} + +- (void)clearColorsForFlag:(DDLogFlag)mask context:(NSInteger)context { + __auto_type block = ^{ + @autoreleasepool { + NSUInteger i = 0; + + for (DDTTYLoggerColorProfile *colorProfile in self->_colorProfilesArray) { + if ((colorProfile->mask == mask) && (colorProfile->context == context)) { + break; + } + + i++; + } + + if (i < [self->_colorProfilesArray count]) { + [self->_colorProfilesArray removeObjectAtIndex:i]; + } + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (void)clearColorsForTag:(id )tag { + NSAssert([(id ) tag conformsToProtocol: @protocol(NSCopying)], @"Invalid tag"); + + __auto_type block = ^{ + @autoreleasepool { + [self->_colorProfilesDict removeObjectForKey:tag]; + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (void)clearColorsForAllFlags { + __auto_type block = ^{ + @autoreleasepool { + [self->_colorProfilesArray removeAllObjects]; + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (void)clearColorsForAllTags { + __auto_type block = ^{ + @autoreleasepool { + [self->_colorProfilesDict removeAllObjects]; + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (void)clearAllColors { + __auto_type block = ^{ + @autoreleasepool { + [self->_colorProfilesArray removeAllObjects]; + [self->_colorProfilesDict removeAllObjects]; + } + }; + + // The design of the setter logic below is taken from the DDAbstractLogger implementation. + // For documentation please refer to the DDAbstractLogger implementation. + + if ([self isOnInternalLoggerQueue]) { + block(); + } else { + DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); + dispatch_async(DDLog.loggingQueue, ^{ + dispatch_async(self.loggerQueue, block); + }); + } +} + +- (void)logMessage:(DDLogMessage *)logMessage { + __auto_type logMsg = logMessage->_message; + __auto_type isFormatted = NO; + + if (_logFormatter) { + logMsg = [_logFormatter formatLogMessage:logMessage]; + isFormatted = logMsg != logMessage->_message; + } + + if (logMsg) { + // Search for a color profile associated with the log message + + DDTTYLoggerColorProfile *colorProfile = nil; + + if (_colorsEnabled) { + if (logMessage->_representedObject) { + colorProfile = _colorProfilesDict[logMessage->_representedObject]; + } + + if (colorProfile == nil) { + for (DDTTYLoggerColorProfile *cp in _colorProfilesArray) { + if (logMessage->_flag & cp->mask) { + // Color profile set for this context? + if (logMessage->_context == cp->context) { + colorProfile = cp; + + // Stop searching + break; + } + + // Check if LOG_CONTEXT_ALL was specified as a default color for this flag + if (cp->context == LOG_CONTEXT_ALL) { + colorProfile = cp; + + // We don't break to keep searching for more specific color profiles for the context + } + } + } + } + } + + // Convert log message to C string. + // + // We use the stack instead of the heap for speed if possible. + // But we're extra cautious to avoid a stack overflow. + + __auto_type msgLen = [logMsg lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + const __auto_type useStack = msgLen < (1024 * 4); + + char *msg; + if (useStack) { + msg = (char *)alloca(msgLen + 1); + } else { + msg = (char *)calloc(msgLen + 1, sizeof(char)); + } + if (msg == NULL) { + return; + } + + BOOL logMsgEnc = [logMsg getCString:msg maxLength:(msgLen + 1) encoding:NSUTF8StringEncoding]; + if (!logMsgEnc) { + if (!useStack) { + free(msg); + } + return; + } + + // Write the log message to STDERR + + if (isFormatted) { + // The log message has already been formatted. + const size_t maxIovecLen = 5; + size_t iovecLen = _automaticallyAppendNewlineForCustomFormatters ? 5 : 4; + struct iovec v[maxIovecLen] = { 0 }; + + if (colorProfile) { + v[0].iov_base = colorProfile->fgCode; + v[0].iov_len = colorProfile->fgCodeLen; + + v[1].iov_base = colorProfile->bgCode; + v[1].iov_len = colorProfile->bgCodeLen; + + v[maxIovecLen - 1].iov_base = colorProfile->resetCode; + v[maxIovecLen - 1].iov_len = colorProfile->resetCodeLen; + } + + v[2].iov_base = msg; + v[2].iov_len = (msgLen > SIZE_MAX - 1) ? SIZE_MAX - 1 : msgLen; + + if (_automaticallyAppendNewlineForCustomFormatters && (v[2].iov_len == 0 || msg[v[2].iov_len - 1] != '\n')) { + v[3].iov_base = "\n"; + v[3].iov_len = 1; + iovecLen = 5; + } + + writev(STDERR_FILENO, v, (int)iovecLen); + } else { + // The log message is unformatted, so apply standard NSLog style formatting. + + int len; + char ts[24] = ""; + size_t tsLen = 0; + + // Calculate timestamp. + // The technique below is faster than using NSDateFormatter. + if (logMessage->_timestamp) { + __auto_type epoch = [logMessage->_timestamp timeIntervalSince1970]; + double integral; + __auto_type fract = modf(epoch, &integral); + struct tm tm; + __auto_type time = (time_t)integral; + (void)localtime_r(&time, &tm); + __auto_type milliseconds = (long)(fract * 1000.0); + + len = snprintf(ts, 24, "%04d-%02d-%02d %02d:%02d:%02d:%03ld", // yyyy-MM-dd HH:mm:ss:SSS + tm.tm_year + 1900, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec, milliseconds); + + tsLen = (NSUInteger)MAX(MIN(24 - 1, len), 0); + } + + // Calculate thread ID + // + // How many characters do we need for the thread id? + // logMessage->machThreadID is of type mach_port_t, which is an unsigned int. + // + // 1 hex char = 4 bits + // 8 hex chars for 32 bit, plus ending '\0' = 9 + + char tid[9]; + len = snprintf(tid, 9, "%s", [logMessage->_threadID cStringUsingEncoding:NSUTF8StringEncoding]); + + __auto_type tidLen = (NSUInteger)MAX(MIN(9 - 1, len), 0); + + // Here is our format: "%s %s[%i:%s] %s", timestamp, appName, processID, threadID, logMsg + + struct iovec v[13]; + + if (colorProfile) { + v[0].iov_base = colorProfile->fgCode; + v[0].iov_len = colorProfile->fgCodeLen; + + v[1].iov_base = colorProfile->bgCode; + v[1].iov_len = colorProfile->bgCodeLen; + + v[12].iov_base = colorProfile->resetCode; + v[12].iov_len = colorProfile->resetCodeLen; + } else { + v[0].iov_base = ""; + v[0].iov_len = 0; + + v[1].iov_base = ""; + v[1].iov_len = 0; + + v[12].iov_base = ""; + v[12].iov_len = 0; + } + + v[2].iov_base = ts; + v[2].iov_len = tsLen; + + v[3].iov_base = " "; + v[3].iov_len = 1; + + v[4].iov_base = _app; + v[4].iov_len = _appLen; + + v[5].iov_base = "["; + v[5].iov_len = 1; + + v[6].iov_base = _pid; + v[6].iov_len = _pidLen; + + v[7].iov_base = ":"; + v[7].iov_len = 1; + + v[8].iov_base = tid; + v[8].iov_len = MIN((size_t)8, tidLen); // snprintf doesn't return what you might think + + v[9].iov_base = "] "; + v[9].iov_len = 2; + + v[10].iov_base = (char *)msg; + v[10].iov_len = msgLen; + + v[11].iov_base = "\n"; + v[11].iov_len = (msg[msgLen] == '\n') ? 0 : 1; + + writev(STDERR_FILENO, v, 13); + } + + if (!useStack) { + free(msg); + } + } +} + +@end + +#pragma mark - + +@implementation DDTTYLoggerColorProfile + +- (instancetype)initWithForegroundColor:(DDColor *)fgColor backgroundColor:(DDColor *)bgColor flag:(DDLogFlag)aMask context:(NSInteger)ctxt { + if ((self = [super init])) { + mask = aMask; + context = ctxt; + + CGFloat r, g, b; + + if (fgColor) { + [DDTTYLogger getRed:&r green:&g blue:&b fromColor:fgColor]; + + fg.r = (uint8_t)(r * (CGFloat)255.0); + fg.g = (uint8_t)(g * (CGFloat)255.0); + fg.b = (uint8_t)(b * (CGFloat)255.0); + } + + if (bgColor) { + [DDTTYLogger getRed:&r green:&g blue:&b fromColor:bgColor]; + + bg.r = (uint8_t)(r * (CGFloat)255.0); + bg.g = (uint8_t)(g * (CGFloat)255.0); + bg.b = (uint8_t)(b * (CGFloat)255.0); + } + + if (fgColor && isaColorTTY) { + // Map foreground color to closest available shell color + + fgCodeIndex = [DDTTYLogger codeIndexForColor:fgColor]; + fgCodeRaw = codesFg[fgCodeIndex]; + + const __auto_type escapeSeq = @"\033["; + + __auto_type len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + __auto_type len2 = [fgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + + BOOL escapeSeqEnc = [escapeSeq getCString:(fgCode) maxLength:(len1 + 1) encoding:NSUTF8StringEncoding]; + BOOL fgCodeRawEsc = [fgCodeRaw getCString:(fgCode + len1) maxLength:(len2 + 1) encoding:NSUTF8StringEncoding]; + + if (!escapeSeqEnc || !fgCodeRawEsc) { + return nil; + } + + fgCodeLen = len1 + len2; + } else if (fgColor && isaXcodeColorTTY) { + // Convert foreground color to color code sequence + const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ; + __auto_type result = snprintf(fgCode, 24, "%sfg%u,%u,%u;", escapeSeq, fg.r, fg.g, fg.b); + fgCodeLen = (NSUInteger)MAX(MIN(result, (24 - 1)), 0); + } else { + // No foreground color or no color support + fgCode[0] = '\0'; + fgCodeLen = 0; + } + + if (bgColor && isaColorTTY) { + // Map background color to closest available shell color + + bgCodeIndex = [DDTTYLogger codeIndexForColor:bgColor]; + bgCodeRaw = codesBg[bgCodeIndex]; + + const __auto_type escapeSeq = @"\033["; + + __auto_type len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + __auto_type len2 = [bgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + + BOOL escapeSeqEnc = [escapeSeq getCString:(bgCode) maxLength:(len1 + 1) encoding:NSUTF8StringEncoding]; + BOOL bgCodeRawEsc = [bgCodeRaw getCString:(bgCode + len1) maxLength:(len2 + 1) encoding:NSUTF8StringEncoding]; + + if (!escapeSeqEnc || !bgCodeRawEsc) { + return nil; + } + + bgCodeLen = len1 + len2; + } else if (bgColor && isaXcodeColorTTY) { + // Convert background color to color code sequence + const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ; + __auto_type result = snprintf(bgCode, 24, "%sbg%u,%u,%u;", escapeSeq, bg.r, bg.g, bg.b); + bgCodeLen = (NSUInteger)MAX(MIN(result, (24 - 1)), 0); + } else { + // No background color or no color support + bgCode[0] = '\0'; + bgCodeLen = 0; + } + + if (isaColorTTY) { + resetCodeLen = (NSUInteger)MAX(snprintf(resetCode, 8, "\033[0m"), 0); + } else if (isaXcodeColorTTY) { + resetCodeLen = (NSUInteger)MAX(snprintf(resetCode, 8, XCODE_COLORS_RESET), 0); + } else { + resetCode[0] = '\0'; + resetCodeLen = 0; + } + } + + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat: + @"", + self, (int)mask, (long)context, fg.r, fg.g, fg.b, bg.r, bg.g, bg.b, fgCodeRaw, bgCodeRaw]; +} + +@end diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDContextFilterLogFormatter+Deprecated.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDContextFilterLogFormatter+Deprecated.m new file mode 100644 index 0000000..c05db19 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDContextFilterLogFormatter+Deprecated.m @@ -0,0 +1,57 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +@implementation DDContextAllowlistFilterLogFormatter (Deprecated) + +- (void)addToWhitelist:(NSInteger)loggingContext { + [self addToAllowlist:loggingContext]; +} + +- (void)removeFromWhitelist:(NSInteger)loggingContext { + [self removeFromAllowlist:loggingContext]; +} + +- (NSArray *)whitelist { + return [self allowlist]; +} + +- (BOOL)isOnWhitelist:(NSInteger)loggingContext { + return [self isOnAllowlist:loggingContext]; +} + +@end + + +@implementation DDContextDenylistFilterLogFormatter (Deprecated) + +- (void)addToBlacklist:(NSInteger)loggingContext { + [self addToDenylist:loggingContext]; +} + +- (void)removeFromBlacklist:(NSInteger)loggingContext { + [self removeFromDenylist:loggingContext]; +} + +- (NSArray *)blacklist { + return [self denylist]; +} + +- (BOOL)isOnBlacklist:(NSInteger)loggingContext { + return [self isOnDenylist:loggingContext]; +} + +@end diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDContextFilterLogFormatter.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDContextFilterLogFormatter.m new file mode 100755 index 0000000..271cd4b --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDContextFilterLogFormatter.m @@ -0,0 +1,185 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +#import + +#import + +@interface DDLoggingContextSet : NSObject + +@property (readonly, copy, nonnull) NSArray *currentSet; + +- (void)addToSet:(NSInteger)loggingContext; +- (void)removeFromSet:(NSInteger)loggingContext; + +- (BOOL)isInSet:(NSInteger)loggingContext; + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface DDContextAllowlistFilterLogFormatter () { + DDLoggingContextSet *_contextSet; +} +@end + +@implementation DDContextAllowlistFilterLogFormatter + +- (instancetype)init { + if ((self = [super init])) { + _contextSet = [[DDLoggingContextSet alloc] init]; + } + return self; +} + +- (void)addToAllowlist:(NSInteger)loggingContext { + [_contextSet addToSet:loggingContext]; +} + +- (void)removeFromAllowlist:(NSInteger)loggingContext { + [_contextSet removeFromSet:loggingContext]; +} + +- (NSArray *)allowlist { + return [_contextSet currentSet]; +} + +- (BOOL)isOnAllowlist:(NSInteger)loggingContext { + return [_contextSet isInSet:loggingContext]; +} + +- (NSString *)formatLogMessage:(DDLogMessage *)logMessage { + if ([self isOnAllowlist:logMessage->_context]) { + return logMessage->_message; + } else { + return nil; + } +} + +@end + + +@interface DDContextDenylistFilterLogFormatter () { + DDLoggingContextSet *_contextSet; +} +@end + +@implementation DDContextDenylistFilterLogFormatter + +- (instancetype)init { + if ((self = [super init])) { + _contextSet = [[DDLoggingContextSet alloc] init]; + } + return self; +} + +- (void)addToDenylist:(NSInteger)loggingContext { + [_contextSet addToSet:loggingContext]; +} + +- (void)removeFromDenylist:(NSInteger)loggingContext { + [_contextSet removeFromSet:loggingContext]; +} + +- (NSArray *)denylist { + return [_contextSet currentSet]; +} + +- (BOOL)isOnDenylist:(NSInteger)loggingContext { + return [_contextSet isInSet:loggingContext]; +} + +- (NSString *)formatLogMessage:(DDLogMessage *)logMessage { + if ([self isOnDenylist:logMessage->_context]) { + return nil; + } else { + return logMessage->_message; + } +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface DDLoggingContextSet () { + pthread_mutex_t _mutex; + NSMutableSet *_set; +} +@end + +@implementation DDLoggingContextSet + +- (instancetype)init { + if ((self = [super init])) { + _set = [[NSMutableSet alloc] init]; + pthread_mutex_init(&_mutex, NULL); + } + + return self; +} + +- (void)dealloc { + pthread_mutex_destroy(&_mutex); +} + +- (void)addToSet:(NSInteger)loggingContext { + pthread_mutex_lock(&_mutex); + { + [_set addObject:@(loggingContext)]; + } + pthread_mutex_unlock(&_mutex); +} + +- (void)removeFromSet:(NSInteger)loggingContext { + pthread_mutex_lock(&_mutex); + { + [_set removeObject:@(loggingContext)]; + } + pthread_mutex_unlock(&_mutex); +} + +- (NSArray *)currentSet { + NSArray *result = nil; + + pthread_mutex_lock(&_mutex); + { + result = [_set allObjects]; + } + pthread_mutex_unlock(&_mutex); + + return result; +} + +- (BOOL)isInSet:(NSInteger)loggingContext { + __auto_type result = NO; + + pthread_mutex_lock(&_mutex); + { + result = [_set containsObject:@(loggingContext)]; + } + pthread_mutex_unlock(&_mutex); + + return result; +} + +@end diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDDispatchQueueLogFormatter.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDDispatchQueueLogFormatter.m new file mode 100755 index 0000000..d348855 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDDispatchQueueLogFormatter.m @@ -0,0 +1,240 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +#import +#import +#import + +#import + +DDQualityOfServiceName const DDQualityOfServiceUserInteractive = @"UI"; +DDQualityOfServiceName const DDQualityOfServiceUserInitiated = @"IN"; +DDQualityOfServiceName const DDQualityOfServiceDefault = @"DF"; +DDQualityOfServiceName const DDQualityOfServiceUtility = @"UT"; +DDQualityOfServiceName const DDQualityOfServiceBackground = @"BG"; +DDQualityOfServiceName const DDQualityOfServiceUnspecified = @"UN"; + +static DDQualityOfServiceName _qos_name(NSUInteger qos) { + switch ((qos_class_t) qos) { + case QOS_CLASS_USER_INTERACTIVE: return DDQualityOfServiceUserInteractive; + case QOS_CLASS_USER_INITIATED: return DDQualityOfServiceUserInitiated; + case QOS_CLASS_DEFAULT: return DDQualityOfServiceDefault; + case QOS_CLASS_UTILITY: return DDQualityOfServiceUtility; + case QOS_CLASS_BACKGROUND: return DDQualityOfServiceBackground; + default: return DDQualityOfServiceUnspecified; + } +} + +#pragma mark - DDDispatchQueueLogFormatter + +@interface DDDispatchQueueLogFormatter () { + NSDateFormatter *_dateFormatter; // Use [self stringFromDate] + + pthread_mutex_t _mutex; + + NSUInteger _minQueueLength; // _prefix == Only access via atomic property + NSUInteger _maxQueueLength; // _prefix == Only access via atomic property + NSMutableDictionary *_replacements; // _prefix == Only access from within spinlock +} +@end + + +@implementation DDDispatchQueueLogFormatter + +- (instancetype)init { + if ((self = [super init])) { + _dateFormatter = [self createDateFormatter]; + + pthread_mutex_init(&_mutex, NULL); + _replacements = [[NSMutableDictionary alloc] init]; + + // Set default replacements: + _replacements[@"com.apple.main-thread"] = @"main"; + } + + return self; +} + +- (instancetype)initWithMode:(DDDispatchQueueLogFormatterMode)mode { + return [self init]; +} + +- (void)dealloc { + pthread_mutex_destroy(&_mutex); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Configuration +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@synthesize minQueueLength = _minQueueLength; +@synthesize maxQueueLength = _maxQueueLength; + +- (NSString *)replacementStringForQueueLabel:(NSString *)longLabel { + NSString *result = nil; + + pthread_mutex_lock(&_mutex); + { + result = _replacements[longLabel]; + } + pthread_mutex_unlock(&_mutex); + + return result; +} + +- (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel { + pthread_mutex_lock(&_mutex); + { + if (shortLabel) { + _replacements[longLabel] = shortLabel; + } else { + [_replacements removeObjectForKey:longLabel]; + } + } + pthread_mutex_unlock(&_mutex); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark DDLogFormatter +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSDateFormatter *)createDateFormatter { + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + [self configureDateFormatter:formatter]; + return formatter; +} + +- (void)configureDateFormatter:(NSDateFormatter *)dateFormatter { + [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss:SSS"]; + [dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]]; + [dateFormatter setCalendar:[[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]]; +} + +- (NSString *)stringFromDate:(NSDate *)date { + return [_dateFormatter stringFromDate:date]; +} + +- (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage { + // As per the DDLogFormatter contract, this method is always invoked on the same thread/dispatch_queue + + __auto_type useQueueLabel = NO; + if (logMessage->_queueLabel) { + useQueueLabel = YES; + + // If you manually create a thread, it's dispatch_queue will have one of the thread names below. + // Since all such threads have the same name, we'd prefer to use the threadName or the machThreadID. + const NSArray *names = @[ + @"com.apple.root.low-priority", + @"com.apple.root.default-priority", + @"com.apple.root.high-priority", + @"com.apple.root.low-overcommit-priority", + @"com.apple.root.default-overcommit-priority", + @"com.apple.root.high-overcommit-priority", + @"com.apple.root.default-qos.overcommit", + ]; + for (NSString *name in names) { + if ([logMessage->_queueLabel isEqualToString:name]) { + useQueueLabel = NO; + break; + } + } + } + + // Get the name of the queue, thread, or machID (whichever we are to use). + NSString *queueThreadLabel; + if (useQueueLabel || [logMessage->_threadName length] > 0) { + __auto_type fullLabel = useQueueLabel ? logMessage->_queueLabel : logMessage->_threadName; + + NSString *abrvLabel; + pthread_mutex_lock(&_mutex); + { + abrvLabel = _replacements[fullLabel]; + } + pthread_mutex_unlock(&_mutex); + + queueThreadLabel = abrvLabel ?: fullLabel; + } else { + queueThreadLabel = logMessage->_threadID; + } + + // Now use the thread label in the output + // labelLength > maxQueueLength : truncate + // labelLength < minQueueLength : padding + // : exact + __auto_type minQueueLength = self.minQueueLength; + __auto_type maxQueueLength = self.maxQueueLength; + __auto_type labelLength = [queueThreadLabel length]; + if (maxQueueLength > 0 && labelLength > maxQueueLength) { + // Truncate + return [queueThreadLabel substringToIndex:maxQueueLength]; + } else if (labelLength < minQueueLength) { + // Padding + return [queueThreadLabel stringByPaddingToLength:minQueueLength + withString:@" " + startingAtIndex:0]; + } else { + // Exact + return queueThreadLabel; + } +} + +- (NSString *)formatLogMessage:(DDLogMessage *)logMessage { + __auto_type timestamp = [self stringFromDate:logMessage->_timestamp]; + __auto_type queueThreadLabel = [self queueThreadLabelForLogMessage:logMessage]; + + return [NSString stringWithFormat:@"%@ [%@ (QOS:%@)] %@", timestamp, queueThreadLabel, _qos_name(logMessage->_qos), logMessage->_message]; +} + +@end + +#pragma mark - DDAtomicCounter + +@interface DDAtomicCounter() { + atomic_int_fast32_t _value; +} +@end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +@implementation DDAtomicCounter +#pragma clang diagnostic pop + +- (instancetype)initWithDefaultValue:(int32_t)defaultValue { + if ((self = [super init])) { + atomic_init(&_value, defaultValue); + } + return self; +} + +- (int32_t)value { + return atomic_load_explicit(&_value, memory_order_relaxed); +} + +- (int32_t)increment { + int32_t old = atomic_fetch_add_explicit(&_value, 1, memory_order_relaxed); + return (old + 1); +} + +- (int32_t)decrement { + int32_t old = atomic_fetch_sub_explicit(&_value, 1, memory_order_relaxed); + return (old - 1); +} + +@end diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDFileLogger+Buffering.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDFileLogger+Buffering.m new file mode 100644 index 0000000..a620a3e --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDFileLogger+Buffering.m @@ -0,0 +1,202 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +#import +#import "../DDFileLogger+Internal.h" + +static const NSUInteger kDDDefaultBufferSize = 4096; // 4 kB, block f_bsize on iphone7 +static const NSUInteger kDDMaxBufferSize = 1048576; // ~1 mB, f_iosize on iphone7 + +// Reads attributes from base file system to determine buffer size. +// see statfs in sys/mount.h for descriptions of f_iosize and f_bsize. +// f_bsize == "default", and f_iosize == "max" +static inline NSUInteger p_DDGetDefaultBufferSizeBytesMax(const BOOL max) { + struct statfs *mountedFileSystems = NULL; + __auto_type count = getmntinfo(&mountedFileSystems, 0); + + for (int i = 0; i < count; i++) { + __auto_type mounted = mountedFileSystems[i]; + __auto_type name = mounted.f_mntonname; + + // We can use 2 as max here, since any length > 1 will fail the if-statement. + if (strnlen(name, 2) == 1 && *name == '/') { + return max ? (NSUInteger)mounted.f_iosize : (NSUInteger)mounted.f_bsize; + } + } + + return max ? kDDMaxBufferSize : kDDDefaultBufferSize; +} + +static NSUInteger DDGetMaxBufferSizeBytes(void) { + static NSUInteger maxBufferSize = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + maxBufferSize = p_DDGetDefaultBufferSizeBytesMax(YES); + }); + return maxBufferSize; +} + +static NSUInteger DDGetDefaultBufferSizeBytes(void) { + static NSUInteger defaultBufferSize = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + defaultBufferSize = p_DDGetDefaultBufferSizeBytesMax(NO); + }); + return defaultBufferSize; +} + +@interface DDBufferedProxy : NSProxy + +@property (nonatomic) DDFileLogger *fileLogger; +@property (nonatomic) NSOutputStream *buffer; + +@property (nonatomic) NSUInteger maxBufferSizeBytes; +@property (nonatomic) NSUInteger currentBufferSizeBytes; + +@end + +@implementation DDBufferedProxy + +- (instancetype)initWithFileLogger:(DDFileLogger *)fileLogger { + _fileLogger = fileLogger; + _maxBufferSizeBytes = DDGetDefaultBufferSizeBytes(); + [self flushBuffer]; + + return self; +} + +- (void)dealloc { + __auto_type block = ^{ + [self lt_sendBufferedDataToFileLogger]; + self.fileLogger = nil; + }; + + if ([self->_fileLogger isOnInternalLoggerQueue]) { + block(); + } else { + dispatch_sync(self->_fileLogger.loggerQueue, block); + } +} + +#pragma mark - Buffering + +- (void)flushBuffer { + [_buffer close]; + _buffer = [NSOutputStream outputStreamToMemory]; + [_buffer open]; + _currentBufferSizeBytes = 0; +} + +- (void)lt_sendBufferedDataToFileLogger { + NSData *data = [_buffer propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + [_fileLogger lt_logData:data]; + [self flushBuffer]; +} + +#pragma mark - Logging + +- (void)logMessage:(DDLogMessage *)logMessage { + // Don't need to check for isOnInternalLoggerQueue, -lt_dataForMessage: will do it for us. + __auto_type data = [_fileLogger lt_dataForMessage:logMessage]; + + if (data.length == 0) { + return; + } + + [data enumerateByteRangesUsingBlock:^(const void * __nonnull bytes, NSRange byteRange, BOOL * __nonnull __unused stop) { + __auto_type bytesLength = byteRange.length; +#ifdef NS_BLOCK_ASSERTIONS + __unused +#endif + __auto_type written = [_buffer write:bytes maxLength:bytesLength]; + NSAssert(written > 0 && (NSUInteger)written == bytesLength, @"Failed to write to memory buffer."); + + _currentBufferSizeBytes += bytesLength; + + if (_currentBufferSizeBytes >= _maxBufferSizeBytes) { + [self lt_sendBufferedDataToFileLogger]; + } + }]; +} + +- (void)flush { + // This method is public. + // We need to execute the rolling on our logging thread/queue. + + __auto_type block = ^{ + @autoreleasepool { + [self lt_sendBufferedDataToFileLogger]; + [self.fileLogger flush]; + } + }; + + // The design of this method is taken from the DDAbstractLogger implementation. + // For extensive documentation please refer to the DDAbstractLogger implementation. + + if ([self.fileLogger isOnInternalLoggerQueue]) { + block(); + } else { + NSAssert(![self.fileLogger isOnGlobalLoggingQueue], @"Core architecture requirement failure"); + dispatch_sync(DDLog.loggingQueue, ^{ + dispatch_sync(self.fileLogger.loggerQueue, block); + }); + } +} + +#pragma mark - Properties + +- (void)setMaxBufferSizeBytes:(NSUInteger)newBufferSizeBytes { + _maxBufferSizeBytes = MIN(newBufferSizeBytes, DDGetMaxBufferSizeBytes()); +} + +#pragma mark - Wrapping + +- (DDFileLogger *)wrapWithBuffer { + return (DDFileLogger *)self; +} + +- (DDFileLogger *)unwrapFromBuffer { + return (DDFileLogger *)self.fileLogger; +} + +#pragma mark - NSProxy + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { + return [self.fileLogger methodSignatureForSelector:sel]; +} + +- (BOOL)respondsToSelector:(SEL)aSelector { + return [self.fileLogger respondsToSelector:aSelector]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + [invocation invokeWithTarget:self.fileLogger]; +} + +@end + +@implementation DDFileLogger (Buffering) + +- (instancetype)wrapWithBuffer { + return (DDFileLogger *)[[DDBufferedProxy alloc] initWithFileLogger:self]; +} + +- (instancetype)unwrapFromBuffer { + return self; +} + +@end diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDMultiFormatter.m b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDMultiFormatter.m new file mode 100644 index 0000000..0782652 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Extensions/DDMultiFormatter.m @@ -0,0 +1,110 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#if !__has_feature(objc_arc) +#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +#import + +@interface DDMultiFormatter () { + dispatch_queue_t _queue; + NSMutableArray *_formatters; +} + +- (DDLogMessage *)logMessageForLine:(NSString *)line originalMessage:(DDLogMessage *)message; + +@end + + +@implementation DDMultiFormatter + +- (instancetype)init { + self = [super init]; + + if (self) { + _queue = dispatch_queue_create("cocoa.lumberjack.multiformatter", DISPATCH_QUEUE_CONCURRENT); + _formatters = [NSMutableArray new]; + } + + return self; +} + +#pragma mark Processing + +- (NSString *)formatLogMessage:(DDLogMessage *)logMessage { + __block __auto_type line = logMessage->_message; + + dispatch_sync(_queue, ^{ + for (id formatter in self->_formatters) { + __auto_type message = [self logMessageForLine:line originalMessage:logMessage]; + line = [formatter formatLogMessage:message]; + + if (!line) { + break; + } + } + }); + + return line; +} + +- (DDLogMessage *)logMessageForLine:(NSString *)line originalMessage:(DDLogMessage *)message { + DDLogMessage *newMessage = [message copy]; + newMessage->_message = line; + return newMessage; +} + +#pragma mark Formatters + +- (NSArray *)formatters { + __block NSArray *formatters; + + dispatch_sync(_queue, ^{ + formatters = [self->_formatters copy]; + }); + + return formatters; +} + +- (void)addFormatter:(id)formatter { + dispatch_barrier_async(_queue, ^{ + [self->_formatters addObject:formatter]; + }); +} + +- (void)removeFormatter:(id)formatter { + dispatch_barrier_async(_queue, ^{ + [self->_formatters removeObject:formatter]; + }); +} + +- (void)removeAllFormatters { + dispatch_barrier_async(_queue, ^{ + [self->_formatters removeAllObjects]; + }); +} + +- (BOOL)isFormattingWithFormatter:(id)formatter { + __block BOOL hasFormatter; + + dispatch_sync(_queue, ^{ + hasFormatter = [self->_formatters containsObject:formatter]; + }); + + return hasFormatter; +} + +@end diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/PrivacyInfo.xcprivacy b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..ec783fe --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/PrivacyInfo.xcprivacy @@ -0,0 +1,30 @@ + + + + + NSPrivacyTracking + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + 0A2A.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryDiskSpace + NSPrivacyAccessedAPITypeReasons + + E174.1 + + + + + diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Supporting Files/CocoaLumberjack.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Supporting Files/CocoaLumberjack.h new file mode 100644 index 0000000..91b2408 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Supporting Files/CocoaLumberjack.h @@ -0,0 +1,104 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +/** + * Welcome to CocoaLumberjack! + * + * The project page has a wealth of documentation if you have any questions. + * https://github.com/CocoaLumberjack/CocoaLumberjack + * + * If you're new to the project you may wish to read "Getting Started" at: + * Documentation/GettingStarted.md + * + * Otherwise, here is a quick refresher. + * There are three steps to using the macros: + * + * Step 1: + * Import the header in your implementation or prefix file: + * + * #import + * + * Step 2: + * Define your logging level in your implementation file: + * + * // Log levels: off, error, warn, info, verbose + * static const DDLogLevel ddLogLevel = DDLogLevelVerbose; + * + * Step 2 [3rd party frameworks]: + * + * Define your LOG_LEVEL_DEF to a different variable/function than ddLogLevel: + * + * // #undef LOG_LEVEL_DEF // Undefine first only if needed + * #define LOG_LEVEL_DEF myLibLogLevel + * + * Define your logging level in your implementation file: + * + * // Log levels: off, error, warn, info, verbose + * static const DDLogLevel myLibLogLevel = DDLogLevelVerbose; + * + * Step 3: + * Replace your NSLog statements with DDLog statements according to the severity of the message. + * + * NSLog(@"Fatal error, no dohickey found!"); -> DDLogError(@"Fatal error, no dohickey found!"); + * + * DDLog works exactly the same as NSLog. + * This means you can pass it multiple variables just like NSLog. + **/ + +#import + +//! Project version number for CocoaLumberjack. +FOUNDATION_EXPORT double CocoaLumberjackVersionNumber; + +//! Project version string for CocoaLumberjack. +FOUNDATION_EXPORT const unsigned char CocoaLumberjackVersionString[]; + +// Disable legacy macros +#ifndef DD_LEGACY_MACROS + #define DD_LEGACY_MACROS 0 +#endif + +// Core +#import + +// Main macros +#import +#import + +// Capture ASL +#import + +// Loggers +#import + +#import +#import +#import +#import + +// Extensions +#import +#import +#import +#import +#import + +// CLI +#import + +// etc +#import +#import +#import diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Supporting Files/DDLegacyMacros.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Supporting Files/DDLegacyMacros.h new file mode 100644 index 0000000..5289f33 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/Supporting Files/DDLegacyMacros.h @@ -0,0 +1,75 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +/** + * Legacy macros used for 1.9.x backwards compatibility. + * + * Imported by default when importing a DDLog.h directly and DD_LEGACY_MACROS is not defined and set to 0. + **/ +#if DD_LEGACY_MACROS + +#warning CocoaLumberjack 1.9.x legacy macros enabled. \ +Disable legacy macros by importing CocoaLumberjack.h or DDLogMacros.h instead of DDLog.h or add `#define DD_LEGACY_MACROS 0` before importing DDLog.h. + +#ifndef LOG_LEVEL_DEF + #define LOG_LEVEL_DEF ddLogLevel +#endif + +#define LOG_FLAG_ERROR DDLogFlagError +#define LOG_FLAG_WARN DDLogFlagWarning +#define LOG_FLAG_INFO DDLogFlagInfo +#define LOG_FLAG_DEBUG DDLogFlagDebug +#define LOG_FLAG_VERBOSE DDLogFlagVerbose + +#define LOG_LEVEL_OFF DDLogLevelOff +#define LOG_LEVEL_ERROR DDLogLevelError +#define LOG_LEVEL_WARN DDLogLevelWarning +#define LOG_LEVEL_INFO DDLogLevelInfo +#define LOG_LEVEL_DEBUG DDLogLevelDebug +#define LOG_LEVEL_VERBOSE DDLogLevelVerbose +#define LOG_LEVEL_ALL DDLogLevelAll + +#define LOG_ASYNC_ENABLED YES + +#define LOG_ASYNC_ERROR ( NO && LOG_ASYNC_ENABLED) +#define LOG_ASYNC_WARN (YES && LOG_ASYNC_ENABLED) +#define LOG_ASYNC_INFO (YES && LOG_ASYNC_ENABLED) +#define LOG_ASYNC_DEBUG (YES && LOG_ASYNC_ENABLED) +#define LOG_ASYNC_VERBOSE (YES && LOG_ASYNC_ENABLED) + +#define LOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \ + [DDLog log : isAsynchronous \ + level : lvl \ + flag : flg \ + context : ctx \ + file : __FILE__ \ + function : fnct \ + line : __LINE__ \ + tag : atag \ + format : (frmt), ## __VA_ARGS__] + +#define LOG_MAYBE(async, lvl, flg, ctx, fnct, frmt, ...) \ + do { if((lvl & flg) != 0) LOG_MACRO(async, lvl, flg, ctx, nil, fnct, frmt, ##__VA_ARGS__); } while(0) + +#define LOG_OBJC_MAYBE(async, lvl, flg, ctx, frmt, ...) \ + LOG_MAYBE(async, lvl, flg, ctx, __PRETTY_FUNCTION__, frmt, ## __VA_ARGS__) + +#define DDLogError(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_ERROR, LOG_LEVEL_DEF, LOG_FLAG_ERROR, 0, frmt, ##__VA_ARGS__) +#define DDLogWarn(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_WARN, LOG_LEVEL_DEF, LOG_FLAG_WARN, 0, frmt, ##__VA_ARGS__) +#define DDLogInfo(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_INFO, LOG_LEVEL_DEF, LOG_FLAG_INFO, 0, frmt, ##__VA_ARGS__) +#define DDLogDebug(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_DEBUG, LOG_LEVEL_DEF, LOG_FLAG_DEBUG, 0, frmt, ##__VA_ARGS__) +#define DDLogVerbose(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_VERBOSE, LOG_LEVEL_DEF, LOG_FLAG_VERBOSE, 0, frmt, ##__VA_ARGS__) + +#endif diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/CLIColor.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/CLIColor.h new file mode 100644 index 0000000..d702e9c --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/CLIColor.h @@ -0,0 +1,54 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +#if TARGET_OS_OSX + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class represents an NSColor replacement for CLI projects that don't link with AppKit + **/ +@interface CLIColor : NSObject + +/** + * Convenience method for creating a `CLIColor` instance from RGBA params + * + * @param red red channel, between 0 and 1 + * @param green green channel, between 0 and 1 + * @param blue blue channel, between 0 and 1 + * @param alpha alpha channel, between 0 and 1 + */ ++ (instancetype)colorWithCalibratedRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha; + +/** + * Get the RGBA components from a `CLIColor` + * + * @param red red channel, between 0 and 1 + * @param green green channel, between 0 and 1 + * @param blue blue channel, between 0 and 1 + * @param alpha alpha channel, between 0 and 1 + */ +- (void)getRed:(nullable CGFloat *)red green:(nullable CGFloat *)green blue:(nullable CGFloat *)blue alpha:(nullable CGFloat *)alpha NS_SWIFT_NAME(get(red:green:blue:alpha:)); + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDASLLogCapture.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDASLLogCapture.h new file mode 100644 index 0000000..90226a6 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDASLLogCapture.h @@ -0,0 +1,46 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +@protocol DDLogger; + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class provides the ability to capture the ASL (Apple System Logs) + */ +API_DEPRECATED("Use DDOSLogger instead", macosx(10.4,10.12), ios(2.0,10.0), watchos(2.0,3.0), tvos(9.0,10.0)) +@interface DDASLLogCapture : NSObject + +/** + * Start capturing logs + */ ++ (void)start; + +/** + * Stop capturing logs + */ ++ (void)stop; + +/** + * The current capture level. + * @note Default log level: DDLogLevelVerbose (i.e. capture all ASL messages). + */ +@property (class) DDLogLevel captureLevel; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDASLLogger.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDASLLogger.h new file mode 100644 index 0000000..8951a8f --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDASLLogger.h @@ -0,0 +1,63 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +// Disable legacy macros +#ifndef DD_LEGACY_MACROS + #define DD_LEGACY_MACROS 0 +#endif + +#import + +NS_ASSUME_NONNULL_BEGIN + +// Custom key set on messages sent to ASL +extern const char* const kDDASLKeyDDLog; + +// Value set for kDDASLKeyDDLog +extern const char* const kDDASLDDLogValue; + +/** + * This class provides a logger for the Apple System Log facility. + * + * As described in the "Getting Started" page, + * the traditional NSLog() function directs its output to two places: + * + * - Apple System Log + * - StdErr (if stderr is a TTY) so log statements show up in Xcode console + * + * To duplicate NSLog() functionality you can simply add this logger and a tty logger. + * However, if you instead choose to use file logging (for faster performance), + * you may choose to use a file logger and a tty logger. + **/ +API_DEPRECATED("Use DDOSLogger instead", macosx(10.4,10.12), ios(2.0,10.0), watchos(2.0,3.0), tvos(9.0,10.0)) +@interface DDASLLogger : DDAbstractLogger + +/** + * Singleton method + * + * @return the shared instance + */ +@property (nonatomic, class, readonly, strong) DDASLLogger *sharedInstance; + +// Inherited from DDAbstractLogger + +// - (id )logFormatter; +// - (void)setLogFormatter:(id )formatter; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDAbstractDatabaseLogger.h similarity index 67% rename from Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h rename to Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDAbstractDatabaseLogger.h index 436234e..e7d0b8c 100644 --- a/Pods/CocoaLumberjack/Lumberjack/DDAbstractDatabaseLogger.h +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDAbstractDatabaseLogger.h @@ -1,102 +1,127 @@ -#import +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. -#import "DDLog.h" +// Disable legacy macros +#ifndef DD_LEGACY_MACROS + #define DD_LEGACY_MACROS 0 +#endif + +#import + +NS_ASSUME_NONNULL_BEGIN /** - * Welcome to Cocoa Lumberjack! - * - * The project page has a wealth of documentation if you have any questions. - * https://github.com/robbiehanson/CocoaLumberjack - * - * If you're new to the project you may wish to read the "Getting Started" wiki. - * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted - * - * * This class provides an abstract implementation of a database logger. - * + * * That is, it provides the base implementation for a database logger to build atop of. * All that is needed for a concrete database logger is to extend this class * and override the methods in the implementation file that are prefixed with "db_". -**/ - + **/ @interface DDAbstractDatabaseLogger : DDAbstractLogger { + @protected - NSUInteger saveThreshold; - NSTimeInterval saveInterval; - NSTimeInterval maxAge; - NSTimeInterval deleteInterval; - BOOL deleteOnEverySave; - - BOOL saveTimerSuspended; - NSUInteger unsavedCount; - dispatch_time_t unsavedTime; - dispatch_source_t saveTimer; - dispatch_time_t lastDeleteTime; - dispatch_source_t deleteTimer; + NSUInteger _saveThreshold; + NSTimeInterval _saveInterval; + NSTimeInterval _maxAge; + NSTimeInterval _deleteInterval; + BOOL _deleteOnEverySave; + + NSInteger _saveTimerSuspended; + NSUInteger _unsavedCount; + dispatch_time_t _unsavedTime; + dispatch_source_t _saveTimer; + dispatch_time_t _lastDeleteTime; + dispatch_source_t _deleteTimer; } /** * Specifies how often to save the data to disk. * Since saving is an expensive operation (disk io) it is not done after every log statement. * These properties allow you to configure how/when the logger saves to disk. - * + * * A save is done when either (whichever happens first): - * + * * - The number of unsaved log entries reaches saveThreshold * - The amount of time since the oldest unsaved log entry was created reaches saveInterval - * + * * You can optionally disable the saveThreshold by setting it to zero. * If you disable the saveThreshold you are entirely dependent on the saveInterval. - * + * * You can optionally disable the saveInterval by setting it to zero (or a negative value). * If you disable the saveInterval you are entirely dependent on the saveThreshold. - * + * * It's not wise to disable both saveThreshold and saveInterval. - * + * * The default saveThreshold is 500. * The default saveInterval is 60 seconds. -**/ + **/ @property (assign, readwrite) NSUInteger saveThreshold; + +/** + * See the description for the `saveThreshold` property + */ @property (assign, readwrite) NSTimeInterval saveInterval; /** * It is likely you don't want the log entries to persist forever. * Doing so would allow the database to grow infinitely large over time. - * + * * The maxAge property provides a way to specify how old a log statement can get * before it should get deleted from the database. - * + * * The deleteInterval specifies how often to sweep for old log entries. * Since deleting is an expensive operation (disk io) is is done on a fixed interval. - * + * * An alternative to the deleteInterval is the deleteOnEverySave option. * This specifies that old log entries should be deleted during every save operation. - * + * * You can optionally disable the maxAge by setting it to zero (or a negative value). * If you disable the maxAge then old log statements are not deleted. - * + * * You can optionally disable the deleteInterval by setting it to zero (or a negative value). - * + * * If you disable both deleteInterval and deleteOnEverySave then old log statements are not deleted. - * + * * It's not wise to enable both deleteInterval and deleteOnEverySave. - * + * * The default maxAge is 7 days. * The default deleteInterval is 5 minutes. * The default deleteOnEverySave is NO. -**/ + **/ @property (assign, readwrite) NSTimeInterval maxAge; + +/** + * See the description for the `maxAge` property + */ @property (assign, readwrite) NSTimeInterval deleteInterval; + +/** + * See the description for the `maxAge` property + */ @property (assign, readwrite) BOOL deleteOnEverySave; /** * Forces a save of any pending log entries (flushes log entries to disk). -**/ + **/ - (void)savePendingLogEntries; /** * Removes any log entries that are older than maxAge. -**/ + **/ - (void)deleteOldLogEntries; @end + +NS_ASSUME_NONNULL_END diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDAssertMacros.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDAssertMacros.h new file mode 100644 index 0000000..de8d8f1 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDAssertMacros.h @@ -0,0 +1,30 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +/** + * NSAssert replacement that will output a log message even when assertions are disabled. + **/ +#define DDAssert(condition, frmt, ...) \ + if (!(condition)) { \ + NSString *description = [NSString stringWithFormat:frmt, ## __VA_ARGS__]; \ + DDLogError(@"%@", description); \ + NSAssert(NO, @"%@", description); \ + } +#define DDAssertCondition(condition) DDAssert(condition, @"Condition not satisfied: %@", @(#condition)) + +/** + * Analog to `DDAssertionFailure` from DDAssert.swift for use in Objective C + */ +#define DDAssertionFailure(frmt, ...) DDAssert(NO, frmt, ##__VA_ARGS__) diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDContextFilterLogFormatter+Deprecated.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDContextFilterLogFormatter+Deprecated.h new file mode 100644 index 0000000..3ffc040 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDContextFilterLogFormatter+Deprecated.h @@ -0,0 +1,119 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class provides a log formatter that filters log statements from a logging context not on the whitelist. + * @deprecated Use DDContextAllowlistFilterLogFormatter instead. + * + * A log formatter can be added to any logger to format and/or filter its output. + * You can learn more about log formatters here: + * Documentation/CustomFormatters.md + * + * You can learn more about logging context's here: + * Documentation/CustomContext.md + * + * But here's a quick overview / refresher: + * + * Every log statement has a logging context. + * These come from the underlying logging macros defined in DDLog.h. + * The default logging context is zero. + * You can define multiple logging context's for use in your application. + * For example, logically separate parts of your app each have a different logging context. + * Also 3rd party frameworks that make use of Lumberjack generally use their own dedicated logging context. + **/ +__attribute__((deprecated("Use DDContextAllowlistFilterLogFormatter instead"))) +typedef DDContextAllowlistFilterLogFormatter DDContextWhitelistFilterLogFormatter; + +@interface DDContextAllowlistFilterLogFormatter (Deprecated) + +/** + * Add a context to the whitelist + * @deprecated Use -addToAllowlist: instead. + * + * @param loggingContext the context + */ +- (void)addToWhitelist:(NSInteger)loggingContext __attribute__((deprecated("Use -addToAllowlist: instead"))); + +/** + * Remove context from whitelist + * @deprecated Use -removeFromAllowlist: instead. + * + * @param loggingContext the context + */ +- (void)removeFromWhitelist:(NSInteger)loggingContext __attribute__((deprecated("Use -removeFromAllowlist: instead"))); + +/** + * Return the whitelist + * @deprecated Use allowlist instead. + */ +@property (nonatomic, readonly, copy) NSArray *whitelist __attribute__((deprecated("Use allowlist instead"))); + +/** + * Check if a context is on the whitelist + * @deprecated Use -isOnAllowlist: instead. + * + * @param loggingContext the context + */ +- (BOOL)isOnWhitelist:(NSInteger)loggingContext __attribute__((deprecated("Use -isOnAllowlist: instead"))); + +@end + + +/** + * This class provides a log formatter that filters log statements from a logging context on the blacklist. + * @deprecated Use DDContextDenylistFilterLogFormatter instead. + **/ +__attribute__((deprecated("Use DDContextDenylistFilterLogFormatter instead"))) +typedef DDContextDenylistFilterLogFormatter DDContextBlacklistFilterLogFormatter; + +@interface DDContextDenylistFilterLogFormatter (Deprecated) + +/** + * Add a context to the blacklist + * @deprecated Use -addToDenylist: instead. + * + * @param loggingContext the context + */ +- (void)addToBlacklist:(NSInteger)loggingContext __attribute__((deprecated("Use -addToDenylist: instead"))); + +/** + * Remove context from blacklist + * @deprecated Use -removeFromDenylist: instead. + * + * @param loggingContext the context + */ +- (void)removeFromBlacklist:(NSInteger)loggingContext __attribute__((deprecated("Use -removeFromDenylist: instead"))); + +/** + * Return the blacklist + * @deprecated Use denylist instead. + */ +@property (readonly, copy) NSArray *blacklist __attribute__((deprecated("Use denylist instead"))); + +/** + * Check if a context is on the blacklist + * @deprecated Use -isOnDenylist: instead. + * + * @param loggingContext the context + */ +- (BOOL)isOnBlacklist:(NSInteger)loggingContext __attribute__((deprecated("Use -isOnDenylist: instead"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDContextFilterLogFormatter.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDContextFilterLogFormatter.h new file mode 100644 index 0000000..c83a689 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDContextFilterLogFormatter.h @@ -0,0 +1,117 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +// Disable legacy macros +#ifndef DD_LEGACY_MACROS + #define DD_LEGACY_MACROS 0 +#endif + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class provides a log formatter that filters log statements from a logging context not on the allowlist. + * + * A log formatter can be added to any logger to format and/or filter its output. + * You can learn more about log formatters here: + * Documentation/CustomFormatters.md + * + * You can learn more about logging context's here: + * Documentation/CustomContext.md + * + * But here's a quick overview / refresher: + * + * Every log statement has a logging context. + * These come from the underlying logging macros defined in DDLog.h. + * The default logging context is zero. + * You can define multiple logging context's for use in your application. + * For example, logically separate parts of your app each have a different logging context. + * Also 3rd party frameworks that make use of Lumberjack generally use their own dedicated logging context. + **/ +@interface DDContextAllowlistFilterLogFormatter : NSObject + +/** + * Designated default initializer + */ +- (instancetype)init NS_DESIGNATED_INITIALIZER; + +/** + * Add a context to the allowlist + * + * @param loggingContext the context + */ +- (void)addToAllowlist:(NSInteger)loggingContext; + +/** + * Remove context from allowlist + * + * @param loggingContext the context + */ +- (void)removeFromAllowlist:(NSInteger)loggingContext; + +/** + * Return the allowlist + */ +@property (nonatomic, readonly, copy) NSArray *allowlist; + +/** + * Check if a context is on the allowlist + * + * @param loggingContext the context + */ +- (BOOL)isOnAllowlist:(NSInteger)loggingContext; + +@end + + +/** + * This class provides a log formatter that filters log statements from a logging context on the denylist. + **/ +@interface DDContextDenylistFilterLogFormatter : NSObject + +- (instancetype)init NS_DESIGNATED_INITIALIZER; + +/** + * Add a context to the denylist + * + * @param loggingContext the context + */ +- (void)addToDenylist:(NSInteger)loggingContext; + +/** + * Remove context from denylist + * + * @param loggingContext the context + */ +- (void)removeFromDenylist:(NSInteger)loggingContext; + +/** + * Return the denylist + */ +@property (readonly, copy) NSArray *denylist; + +/** + * Check if a context is on the denylist + * + * @param loggingContext the context + */ +- (BOOL)isOnDenylist:(NSInteger)loggingContext; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDDispatchQueueLogFormatter.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDDispatchQueueLogFormatter.h new file mode 100644 index 0000000..90d32d4 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDDispatchQueueLogFormatter.h @@ -0,0 +1,223 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +// Disable legacy macros +#ifndef DD_LEGACY_MACROS + #define DD_LEGACY_MACROS 0 +#endif + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Log formatter mode + */ +__attribute__((deprecated("DDDispatchQueueLogFormatter is always shareable"))) +typedef NS_ENUM(NSUInteger, DDDispatchQueueLogFormatterMode){ + /** + * This is the default option, means the formatter can be reused between multiple loggers and therefore is thread-safe. + * There is, of course, a performance cost for the thread-safety + */ + DDDispatchQueueLogFormatterModeShareble = 0, + /** + * If the formatter will only be used by a single logger, then the thread-safety can be removed + * @note: there is an assert checking if the formatter is added to multiple loggers and the mode is non-shareble + */ + DDDispatchQueueLogFormatterModeNonShareble, +}; + +/** + * Quality of Service names. + * + * Since macOS 10.10 and iOS 8.0, pthreads, dispatch queues and NSOperations express their + * scheduling priority by using an abstract classification called Quality of Service (QOS). + * + * This formatter will add a representation of this QOS in the log message by using those + * string constants. + * For example: + * + * `2011-10-17 20:21:45.435 AppName[19928:5207 (QOS:DF)] Your log message here` + * + * Where QOS is one of: + * `- UI = User Interactive` + * `- IN = User Initiated` + * `- DF = Default` + * `- UT = Utility` + * `- BG = Background` + * `- UN = Unspecified` + * + * Note: QOS will be absent in the log messages if running on OS versions that don't support it. + **/ +typedef NSString * DDQualityOfServiceName NS_STRING_ENUM; + +FOUNDATION_EXPORT DDQualityOfServiceName const DDQualityOfServiceUserInteractive NS_SWIFT_NAME(DDQualityOfServiceName.userInteractive) API_AVAILABLE(macos(10.10), ios(8.0)); +FOUNDATION_EXPORT DDQualityOfServiceName const DDQualityOfServiceUserInitiated NS_SWIFT_NAME(DDQualityOfServiceName.userInitiated) API_AVAILABLE(macos(10.10), ios(8.0)); +FOUNDATION_EXPORT DDQualityOfServiceName const DDQualityOfServiceDefault NS_SWIFT_NAME(DDQualityOfServiceName.default) API_AVAILABLE(macos(10.10), ios(8.0)); +FOUNDATION_EXPORT DDQualityOfServiceName const DDQualityOfServiceUtility NS_SWIFT_NAME(DDQualityOfServiceName.utility) API_AVAILABLE(macos(10.10), ios(8.0)); +FOUNDATION_EXPORT DDQualityOfServiceName const DDQualityOfServiceBackground NS_SWIFT_NAME(DDQualityOfServiceName.background) API_AVAILABLE(macos(10.10), ios(8.0)); +FOUNDATION_EXPORT DDQualityOfServiceName const DDQualityOfServiceUnspecified NS_SWIFT_NAME(DDQualityOfServiceName.unspecified) API_AVAILABLE(macos(10.10), ios(8.0)); + +/** + * This class provides a log formatter that prints the dispatch_queue label instead of the mach_thread_id. + * + * A log formatter can be added to any logger to format and/or filter its output. + * You can learn more about log formatters here: + * Documentation/CustomFormatters.md + * + * A typical `NSLog` (or `DDTTYLogger`) prints detailed info as `[:]`. + * For example: + * + * `2011-10-17 20:21:45.435 AppName[19928:5207] Your log message here` + * + * Where: + * `- 19928 = process id` + * `- 5207 = thread id (mach_thread_id printed in hex)` + * + * When using grand central dispatch (GCD), this information is less useful. + * This is because a single serial dispatch queue may be run on any thread from an internally managed thread pool. + * For example: + * + * `2011-10-17 20:32:31.111 AppName[19954:4d07] Message from my_serial_dispatch_queue` + * `2011-10-17 20:32:31.112 AppName[19954:5207] Message from my_serial_dispatch_queue` + * `2011-10-17 20:32:31.113 AppName[19954:2c55] Message from my_serial_dispatch_queue` + * + * This formatter allows you to replace the standard `[box:info]` with the dispatch_queue name. + * For example: + * + * `2011-10-17 20:32:31.111 AppName[img-scaling] Message from my_serial_dispatch_queue` + * `2011-10-17 20:32:31.112 AppName[img-scaling] Message from my_serial_dispatch_queue` + * `2011-10-17 20:32:31.113 AppName[img-scaling] Message from my_serial_dispatch_queue` + * + * If the dispatch_queue doesn't have a set name, then it falls back to the thread name. + * If the current thread doesn't have a set name, then it falls back to the mach_thread_id in hex (like normal). + * + * Note: If manually creating your own background threads (via `NSThread/alloc/init` or `NSThread/detachNeThread`), + * you can use `[[NSThread currentThread] setName:(NSString *)]`. + **/ +@interface DDDispatchQueueLogFormatter : NSObject + +/** + * Standard init method. + * Configure using properties as desired. + **/ +- (instancetype)init NS_DESIGNATED_INITIALIZER; + +/** + * Initializer with ability to set the queue mode + * + * @param mode choose between DDDispatchQueueLogFormatterModeShareble and DDDispatchQueueLogFormatterModeNonShareble, depending if the formatter is shared between several loggers or not + */ +- (instancetype)initWithMode:(DDDispatchQueueLogFormatterMode)mode __attribute__((deprecated("DDDispatchQueueLogFormatter is always shareable"))); + +/** + * The minQueueLength restricts the minimum size of the [detail box]. + * If the minQueueLength is set to 0, there is no restriction. + * + * For example, say a dispatch_queue has a label of "diskIO": + * + * If the minQueueLength is 0: [diskIO] + * If the minQueueLength is 4: [diskIO] + * If the minQueueLength is 5: [diskIO] + * If the minQueueLength is 6: [diskIO] + * If the minQueueLength is 7: [diskIO ] + * If the minQueueLength is 8: [diskIO ] + * + * The default minQueueLength is 0 (no minimum, so [detail box] won't be padded). + * + * If you want every [detail box] to have the exact same width, + * set both minQueueLength and maxQueueLength to the same value. + **/ +@property (assign, atomic) NSUInteger minQueueLength; + +/** + * The maxQueueLength restricts the number of characters that will be inside the [detail box]. + * If the maxQueueLength is 0, there is no restriction. + * + * For example, say a dispatch_queue has a label of "diskIO": + * + * If the maxQueueLength is 0: [diskIO] + * If the maxQueueLength is 4: [disk] + * If the maxQueueLength is 5: [diskI] + * If the maxQueueLength is 6: [diskIO] + * If the maxQueueLength is 7: [diskIO] + * If the maxQueueLength is 8: [diskIO] + * + * The default maxQueueLength is 0 (no maximum, so [detail box] won't be truncated). + * + * If you want every [detail box] to have the exact same width, + * set both minQueueLength and maxQueueLength to the same value. + **/ +@property (assign, atomic) NSUInteger maxQueueLength; + +/** + * Sometimes queue labels have long names like "com.apple.main-queue", + * but you'd prefer something shorter like simply "main". + * + * This method allows you to set such preferred replacements. + * The above example is set by default. + * + * To remove/undo a previous replacement, invoke this method with nil for the 'shortLabel' parameter. + **/ +- (nullable NSString *)replacementStringForQueueLabel:(NSString *)longLabel; + +/** + * See the `replacementStringForQueueLabel:` description + */ +- (void)setReplacementString:(nullable NSString *)shortLabel forQueueLabel:(NSString *)longLabel; + +@end + +/** + * Category on `DDDispatchQueueLogFormatter` to make method declarations easier to extend/modify + **/ +@interface DDDispatchQueueLogFormatter (OverridableMethods) + +/** + * Date formatter default configuration + */ +- (void)configureDateFormatter:(NSDateFormatter *)dateFormatter; + +/** + * Formatter method to transfrom from date to string + */ +- (NSString *)stringFromDate:(NSDate *)date; + +/** + * Method to compute the queue thread label + */ +- (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage; + +@end + +#pragma mark - DDAtomicCountable + +__attribute__((deprecated("DDAtomicCountable is useless since DDDispatchQueueLogFormatter is always shareable now"))) +@protocol DDAtomicCountable + +- (instancetype)initWithDefaultValue:(int32_t)defaultValue; +- (int32_t)increment; +- (int32_t)decrement; +- (int32_t)value; + +@end + +__attribute__((deprecated("DDAtomicCountable is deprecated"))) +@interface DDAtomicCounter: NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDFileLogger+Buffering.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDFileLogger+Buffering.h new file mode 100644 index 0000000..cbb90f0 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDFileLogger+Buffering.h @@ -0,0 +1,27 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DDFileLogger (Buffering) + +- (instancetype)wrapWithBuffer; +- (instancetype)unwrapFromBuffer; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDFileLogger.h b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDFileLogger.h new file mode 100644 index 0000000..ffd3936 --- /dev/null +++ b/Pods/CocoaLumberjack/Sources/CocoaLumberjack/include/CocoaLumberjack/DDFileLogger.h @@ -0,0 +1,571 @@ +// Software License Agreement (BSD License) +// +// Copyright (c) 2010-2024, Deusty, LLC +// All rights reserved. +// +// Redistribution and use of this software in source and binary forms, +// with or without modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Neither the name of Deusty nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission of Deusty, LLC. + +// Disable legacy macros +#ifndef DD_LEGACY_MACROS + #define DD_LEGACY_MACROS 0 +#endif + +#import + +@class DDLogFileInfo; + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class provides a logger to write log statements to a file. + **/ + + +// Default configuration and safety/sanity values. +// +// maximumFileSize -> kDDDefaultLogMaxFileSize +// rollingFrequency -> kDDDefaultLogRollingFrequency +// maximumNumberOfLogFiles -> kDDDefaultLogMaxNumLogFiles +// logFilesDiskQuota -> kDDDefaultLogFilesDiskQuota +// +// You should carefully consider the proper configuration values for your application. + +extern unsigned long long const kDDDefaultLogMaxFileSize; +extern NSTimeInterval const kDDDefaultLogRollingFrequency; +extern NSUInteger const kDDDefaultLogMaxNumLogFiles; +extern unsigned long long const kDDDefaultLogFilesDiskQuota; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +/// The serializer is responsible for turning a log message into binary for writing into a file. +/// It allows storing log messages in a non-text format. +/// The serialier should not be used for filtering or formatting messages! +/// Also, it must be fast! +@protocol DDFileLogMessageSerializer +@required + +/// Returns the binary representation of the message. +/// - Parameter message: The formatted log message to serialize. +// + +/// Returns the binary representation of the message. +/// - Parameters: +/// - string: The string to serialize. Usually, this is the formatted message, but it can also be e.g. a log file header. +/// - message: The message which represents the `string`. This is null, if `string` is e.g. a log file header. +/// - Note: The `message` parameter should not be used for formatting! It should simply be used to extract the necessary metadata for serializing. +- (NSData *)dataForString:(NSString *)string + originatingFromMessage:(nullable DDLogMessage *)message NS_SWIFT_NAME(dataForString(_:originatingFrom:)); + +@end + +/// The (default) plain text message serializer. +@interface DDFileLogPlainTextMessageSerializer : NSObject + +- (instancetype)init; + +@end + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@class DDFileLogger; +/** + * The LogFileManager protocol is designed to allow you to control all aspects of your log files. + * + * The primary purpose of this is to allow you to do something with the log files after they have been rolled. + * Perhaps you want to compress them to save disk space. + * Perhaps you want to upload them to an FTP server. + * Perhaps you want to run some analytics on the file. + * + * A default LogFileManager is, of course, provided. + * The default LogFileManager simply deletes old log files according to the maximumNumberOfLogFiles property. + * + * This protocol provides various methods to fetch the list of log files. + * + * There are two variants: sorted and unsorted. + * If sorting is not necessary, the unsorted variant is obviously faster. + * The sorted variant will return an array sorted by when the log files were created, + * with the most recently created log file at index 0, and the oldest log file at the end of the array. + * + * You can fetch only the log file paths (full path including name), log file names (name only), + * or an array of `DDLogFileInfo` objects. + * The `DDLogFileInfo` class is documented below, and provides a handy wrapper that + * gives you easy access to various file attributes such as the creation date or the file size. + */ +@protocol DDLogFileManager +@required + +// Public properties + +/** + * The maximum number of archived log files to keep on disk. + * For example, if this property is set to 3, + * then the LogFileManager will only keep 3 archived log files (plus the current active log file) on disk. + * Once the active log file is rolled/archived, then the oldest of the existing 3 rolled/archived log files is deleted. + * + * You may optionally disable this option by setting it to zero. + **/ +@property (readwrite, assign, atomic) NSUInteger maximumNumberOfLogFiles; + +/** + * The maximum space that logs can take. On rolling logfile all old log files that exceed logFilesDiskQuota will + * be deleted. + * + * You may optionally disable this option by setting it to zero. + **/ +@property (readwrite, assign, atomic) unsigned long long logFilesDiskQuota; + +// Public methods + +/** + * Returns the logs directory (path) + */ +@property (nonatomic, readonly, copy) NSString *logsDirectory; + +/** + * Returns an array of `NSString` objects, + * each of which is the filePath to an existing log file on disk. + **/ +@property (nonatomic, readonly, strong) NSArray *unsortedLogFilePaths; + +/** + * Returns an array of `NSString` objects, + * each of which is the fileName of an existing log file on disk. + **/ +@property (nonatomic, readonly, strong) NSArray *unsortedLogFileNames; + +/** + * Returns an array of `DDLogFileInfo` objects, + * each representing an existing log file on disk, + * and containing important information about the log file such as it's modification date and size. + **/ +@property (nonatomic, readonly, strong) NSArray *unsortedLogFileInfos; + +/** + * Just like the `unsortedLogFilePaths` method, but sorts the array. + * The items in the array are sorted by creation date. + * The first item in the array will be the most recently created log file. + **/ +@property (nonatomic, readonly, strong) NSArray *sortedLogFilePaths; + +/** + * Just like the `unsortedLogFileNames` method, but sorts the array. + * The items in the array are sorted by creation date. + * The first item in the array will be the most recently created log file. + **/ +@property (nonatomic, readonly, strong) NSArray *sortedLogFileNames; + +/** + * Just like the `unsortedLogFileInfos` method, but sorts the array. + * The items in the array are sorted by creation date. + * The first item in the array will be the most recently created log file. + **/ +@property (nonatomic, readonly, strong) NSArray *sortedLogFileInfos; + +// Private methods (only to be used by DDFileLogger) + +/** + * Generates a new unique log file path, and creates the corresponding log file. + * This method is executed directly on the file logger's internal queue. + * The file has to exist by the time the method returns. + **/ +- (nullable NSString *)createNewLogFileWithError:(NSError **)error; + +@optional + +/// The log message serializer. +@property (nonatomic, readonly, strong) id logMessageSerializer; + +/// Manually perform a cleanup of the log files managed by this manager. +/// This can be called from any queue! +- (BOOL)cleanupLogFilesWithError:(NSError **)error; + +// MARK: Private methods (only to be used by DDFileLogger) + +// MARK: Notifications from DDFileLogger +/// Called when the log file manager was added to a file logger. +/// This should be used to make the manager "active" - like starting internal timers etc. +/// Executed on global queue with default priority. +/// - Parameter fileLogger: The file logger this manager was added to. +/// - Important: The manager **must not** keep a strong reference to `fileLogger` or a retain cycle will be created! +- (void)didAddToFileLogger:(DDFileLogger *)fileLogger; + +/// Called when a log file was archived. Executed on global queue with default priority. +/// @param logFilePath The path to the log file that was archived. +/// @param wasRolled Whether or not the archiving happend after rolling the log file. +- (void)didArchiveLogFile:(NSString *)logFilePath wasRolled:(BOOL)wasRolled NS_SWIFT_NAME(didArchiveLogFile(atPath:wasRolled:)); + +// MARK: Deprecated APIs +/// Creates a new log file ignoring any errors. Deprecated in favor of `-createNewLogFileWithError:`. +/// Will only be called if `-createNewLogFileWithError:` is not implemented. +- (nullable NSString *)createNewLogFile __attribute__((deprecated("Use -createNewLogFileWithError:"))) NS_SWIFT_UNAVAILABLE("Use -createNewLogFileWithError:"); + +/// Called when a log file was archived. Executed on global queue with default priority. +- (void)didArchiveLogFile:(NSString *)logFilePath NS_SWIFT_NAME(didArchiveLogFile(atPath:)) __attribute__((deprecated("Use -didArchiveLogFile:wasRolled:"))); + +/// Called when the roll action was executed and the log was archived. Executed on global queue with default priority. +- (void)didRollAndArchiveLogFile:(NSString *)logFilePath NS_SWIFT_NAME(didRollAndArchiveLogFile(atPath:)) __attribute__((deprecated("Use -didArchiveLogFile:wasRolled:"))); + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Default log file manager. + * + * All log files are placed inside the logsDirectory. + * If a specific logsDirectory isn't specified, the default directory is used. + * On Mac, this is in `~/Library/Logs/`. + * On iPhone, this is in `~/Library/Caches/Logs`. + * + * Log files are named `"