diff --git a/SignalCoreKit.podspec b/SignalCoreKit.podspec index 740b8ba..786dc7e 100644 --- a/SignalCoreKit.podspec +++ b/SignalCoreKit.podspec @@ -28,7 +28,7 @@ Pod::Spec.new do |s| s.prefix_header_file = 'SignalCoreKit/SCKPrefix.h' s.xcconfig = { 'OTHER_CFLAGS' => '$(inherited) -DSQLITE_HAS_CODEC' } - s.dependency 'CocoaLumberjack' + s.dependency 'CocoaLumberjack', '~> 3.7.4' s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'SignalCoreKitTests/src/**/*.{h,m,swift}' diff --git a/SignalCoreKit/src/Error.swift b/SignalCoreKit/src/Error.swift index 4ac185e..f5b0275 100644 --- a/SignalCoreKit/src/Error.swift +++ b/SignalCoreKit/src/Error.swift @@ -10,10 +10,12 @@ public struct OWSAssertionError: Error { #endif public let description: String - public init(_ description: String, - file: String = #file, - function: String = #function, - line: Int = #line) { + public init( + _ description: String, + file: String = #fileID, + function: String = #function, + line: Int = #line + ) { #if TESTABLE_BUILD if Self.test_skipAssertions { Logger.warn("assertionError: \(description)") diff --git a/SignalCoreKit/src/Logger.swift b/SignalCoreKit/src/Logger.swift index 32ae2ca..e4d7d07 100644 --- a/SignalCoreKit/src/Logger.swift +++ b/SignalCoreKit/src/Logger.swift @@ -2,75 +2,90 @@ // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // +import CocoaLumberjack import Foundation -@inlinable -public func owsFormatLogMessage(_ logString: String, - file: String = #file, - function: String = #function, - line: Int = #line) -> String { - let filename = (file as NSString).lastPathComponent - // We format the filename & line number in a format compatible - // with XCode's "Open Quickly..." feature. - return "[\(filename):\(line) \(function)]: \(logString)" -} - -/** - * A minimal DDLog wrapper for swift. - */ -open class Logger: NSObject { - - open class func verbose(_ logString: @autoclosure () -> String, - file: String = #file, - function: String = #function, - line: Int = #line) { - guard ShouldLogVerbose() else { +public enum Logger { + /// Logs `logString()` if the level represented by `flag` is enabled. + public static func log( + _ logString: @autoclosure () -> String, + flag: DDLogFlag, + file: String, + function: String, + line: Int + ) { + guard ShouldLogFlag(flag) else { return } - OWSLogger.verbose(owsFormatLogMessage(logString(), file: file, function: function, line: line)) + DDLog.log(asynchronous: true, message: DDLogMessage( + message: logString(), + level: ddLogLevel, + flag: flag, + context: 0, + file: file, + function: function, + line: UInt(line), + tag: nil, + timestamp: nil + )) } - open class func debug(_ logString: @autoclosure () -> String, - file: String = #file, - function: String = #function, - line: Int = #line) { - guard ShouldLogDebug() else { - return - } - OWSLogger.debug(owsFormatLogMessage(logString(), file: file, function: function, line: line)) + private static func log( + _ logString: @autoclosure () -> String, + flag: DDLogFlag, + fileID: String, + function: String, + line: Int + ) { + log(logString(), flag: flag, file: (fileID as NSString).lastPathComponent, function: function, line: line) } - open class func info(_ logString: @autoclosure () -> String, - file: String = #file, - function: String = #function, - line: Int = #line) { - guard ShouldLogInfo() else { - return - } - OWSLogger.info(owsFormatLogMessage(logString(), file: file, function: function, line: line)) + public static func verbose( + _ logString: @autoclosure () -> String, + file: String = #fileID, + function: String = #function, + line: Int = #line + ) { + log(logString(), flag: .verbose, fileID: file, function: function, line: line) } - open class func warn(_ logString: @autoclosure () -> String, - file: String = #file, - function: String = #function, - line: Int = #line) { - guard ShouldLogWarning() else { - return - } - OWSLogger.warn(owsFormatLogMessage(logString(), file: file, function: function, line: line)) + public static func debug( + _ logString: @autoclosure () -> String, + file: String = #fileID, + function: String = #function, + line: Int = #line + ) { + log(logString(), flag: .debug, fileID: file, function: function, line: line) } - open class func error(_ logString: @autoclosure () -> String, - file: String = #file, - function: String = #function, - line: Int = #line) { - guard ShouldLogError() else { - return - } - OWSLogger.error(owsFormatLogMessage(logString(), file: file, function: function, line: line)) + public static func info( + _ logString: @autoclosure () -> String, + file: String = #fileID, + function: String = #function, + line: Int = #line + ) { + log(logString(), flag: .info, fileID: file, function: function, line: line) + } + + public static func warn( + _ logString: @autoclosure () -> String, + file: String = #fileID, + function: String = #function, + line: Int = #line + ) { + log(logString(), flag: .warning, fileID: file, function: function, line: line) + } + + public static func error( + _ logString: @autoclosure () -> String, + file: String = #fileID, + function: String = #function, + line: Int = #line + ) { + log(logString(), flag: .error, fileID: file, function: function, line: line) } - open class func flush() { - OWSLogger.flush() + public static func flush() { + DDLog.flushLog() } } diff --git a/SignalCoreKit/src/OWSAsserts.h b/SignalCoreKit/src/OWSAsserts.h index a026248..c1f2de8 100644 --- a/SignalCoreKit/src/OWSAsserts.h +++ b/SignalCoreKit/src/OWSAsserts.h @@ -110,14 +110,12 @@ NS_ASSUME_NONNULL_BEGIN #define OWSFailDebug(_messageFormat, ...) \ do { \ OWSLogError(_messageFormat, ##__VA_ARGS__); \ - OWSLogFlush(); \ OWSFailWithoutLogging(_messageFormat, ##__VA_ARGS__); \ } while (0) #define OWSCFailDebug(_messageFormat, ...) \ do { \ OWSLogError(_messageFormat, ##__VA_ARGS__); \ - OWSLogFlush(); \ OWSCFailWithoutLogging(_messageFormat, ##__VA_ARGS__); \ } while (NO) @@ -139,66 +137,19 @@ void SwiftExit(NSString *message, const char *file, const char *function, int li SwiftExit(_message, __FILE__, __PRETTY_FUNCTION__, __LINE__); \ } while (NO) -// Avoids Clang analyzer warning: -// Value stored to 'x' during it's initialization is never read -#define SUPPRESS_DEADSTORE_WARNING(x) \ - do { \ - (void)x; \ - } while (0) - __attribute__((annotate("returns_localized_nsstring"))) static inline NSString *LocalizationNotNeeded(NSString *s) { return s; } -#define OWSGuardWithException(X, ExceptionName) \ - do { \ - if (!(X)) { \ - OWSRaiseException(ExceptionName, @"Guard failed: %s", CONVERT_EXPR_TO_STRING(X)); \ - } \ - } while (NO) - #define OWSRaiseException(name, formatParam, ...) \ do { \ OWSLogWarn(@"Exception: %@ %@", name, [NSString stringWithFormat:formatParam, ##__VA_ARGS__]); \ - OWSLogFlush(); \ @throw [NSException exceptionWithName:name \ reason:[NSString stringWithFormat:formatParam, ##__VA_ARGS__] \ userInfo:nil]; \ } while (NO) -#define OWSRaiseExceptionWithUserInfo(name, userInfoParam, formatParam, ...) \ - do { \ - OWSLogWarn( \ - @"Exception: %@ %@ %@", name, userInfoParam, [NSString stringWithFormat:formatParam, ##__VA_ARGS__]); \ - OWSLogFlush(); \ - @throw [NSException exceptionWithName:name \ - reason:[NSString stringWithFormat:formatParam, ##__VA_ARGS__] \ - userInfo:userInfoParam]; \ - } while (NO) - - -// UI JANK -// -// In pursuit of smooth UI, we want to continue moving blocking operations off the main thread. -// Add `OWSJanksUI` in code paths that shouldn't be called on the main thread. -// Because we have pervasively broken this tenant, enabling it by default would be too disruptive -// but it's helpful while unjanking and maybe someday we can have it enabled by default. -//#define DEBUG_UI_JANK 1 - -#ifdef DEBUG -#ifdef DEBUG_UI_JANK -#define OWSJanksUI() \ - do { \ - OWSAssertDebug(![NSThread isMainThread]) \ - } while (NO) -#endif -#endif - -#ifndef OWSJanksUI -#define OWSJanksUI() -#endif - #pragma mark - Overflow Math #define ows_add_overflow(a, b, resultRef) \ diff --git a/SignalCoreKit/src/OWSAsserts.m b/SignalCoreKit/src/OWSAsserts.m index 513e166..fe5f805 100644 --- a/SignalCoreKit/src/OWSAsserts.m +++ b/SignalCoreKit/src/OWSAsserts.m @@ -11,7 +11,7 @@ void SwiftExit(NSString *message, const char *file, const char *function, int li { NSString *_file = [NSString stringWithFormat:@"%s", file]; NSString *_function = [NSString stringWithFormat:@"%s", function]; - [OWSSwiftUtils owsFail:message file:_file function:_function line:line]; + [OWSSwiftUtils owsFailObjC:message file:_file function:_function line:line]; } NS_ASSUME_NONNULL_END diff --git a/SignalCoreKit/src/OWSLogs.h b/SignalCoreKit/src/OWSLogs.h index 39224bd..9d3beed 100644 --- a/SignalCoreKit/src/OWSLogs.h +++ b/SignalCoreKit/src/OWSLogs.h @@ -7,11 +7,16 @@ NS_ASSUME_NONNULL_BEGIN #ifdef DEBUG -static const NSUInteger ddLogLevel = DDLogLevelAll; +static const DDLogLevel ddLogLevel = DDLogLevelAll; #else -static const NSUInteger ddLogLevel = DDLogLevelInfo; +static const DDLogLevel ddLogLevel = DDLogLevelInfo; #endif +static inline BOOL ShouldLogFlag(DDLogFlag flag) +{ + return (ddLogLevel & flag) != 0; +} + static inline BOOL ShouldLogVerbose(void) { return ddLogLevel >= DDLogLevelVerbose; @@ -37,67 +42,28 @@ static inline BOOL ShouldLogError(void) return ddLogLevel >= DDLogLevelError; } -/** - * A minimal DDLog wrapper for swift. - */ @interface OWSLogger : NSObject -/// When toggled, all subsequent logs at info or higher will be immediately flushed -@property (class, atomic, assign) BOOL aggressiveFlushing; ++ (void)verbose:(NSString *)logString __attribute__((deprecated)); ++ (void)debug:(NSString *)logString __attribute__((deprecated)); ++ (void)info:(NSString *)logString __attribute__((deprecated)); ++ (void)warn:(NSString *)logString __attribute__((deprecated)); ++ (void)error:(NSString *)logString __attribute__((deprecated)); -+ (void)verbose:(NSString *)logString; -+ (void)debug:(NSString *)logString; -+ (void)info:(NSString *)logString; -+ (void)warn:(NSString *)logString; -+ (void)error:(NSString *)logString; +@end -+ (void)flush; +/// A helper method for `OWSLogIfEnabled`, which checks if a level should be logged. +void OWSLogUnconditionally(DDLogFlag flag, const char *file, BOOL shouldTrimFilePath, NSUInteger line, const char *function, NSString *format, ...) NS_FORMAT_FUNCTION(6,7); -@end +#define OWSLogIfEnabled(flg, fmt, ...) \ + do { if (ShouldLogFlag(flg)) OWSLogUnconditionally(flg, __FILE__, YES, __LINE__, __PRETTY_FUNCTION__, (fmt), ## __VA_ARGS__); } while (0) + +#define OWSLogVerbose(fmt, ...) OWSLogIfEnabled(DDLogFlagVerbose, fmt, ##__VA_ARGS__) +#define OWSLogDebug(fmt, ...) OWSLogIfEnabled(DDLogFlagDebug, fmt, ##__VA_ARGS__) +#define OWSLogInfo(fmt, ...) OWSLogIfEnabled(DDLogFlagInfo, fmt, ##__VA_ARGS__) +#define OWSLogWarn(fmt, ...) OWSLogIfEnabled(DDLogFlagWarning, fmt, ##__VA_ARGS__) +#define OWSLogError(fmt, ...) OWSLogIfEnabled(DDLogFlagError, fmt, ##__VA_ARGS__) -#define OWSLogPrefix() \ - ([NSString stringWithFormat:@"[%@:%d %s]: ", \ - [[NSString stringWithUTF8String:__FILE__] lastPathComponent], \ - __LINE__, \ - __PRETTY_FUNCTION__]) - -#define OWSLogVerbose(_messageFormat, ...) \ - do { \ - DDLogVerbose(@"๐Ÿ’™ %@%@", OWSLogPrefix(), [NSString stringWithFormat:_messageFormat, ##__VA_ARGS__]); \ - } while (0) - -#define OWSLogDebug(_messageFormat, ...) \ - do { \ - DDLogDebug(@"๐Ÿ’š %@%@", OWSLogPrefix(), [NSString stringWithFormat:_messageFormat, ##__VA_ARGS__]); \ - } while (0) - -#define OWSLogInfo(_messageFormat, ...) \ - do { \ - DDLogInfo(@"๐Ÿ’› %@%@", OWSLogPrefix(), [NSString stringWithFormat:_messageFormat, ##__VA_ARGS__]); \ - if (OWSLogger.aggressiveFlushing) { \ - OWSLogFlush(); \ - } \ - } while (0) - -#define OWSLogWarn(_messageFormat, ...) \ - do { \ - DDLogWarn(@"๐Ÿงก %@%@", OWSLogPrefix(), [NSString stringWithFormat:_messageFormat, ##__VA_ARGS__]); \ - if (OWSLogger.aggressiveFlushing) { \ - OWSLogFlush(); \ - } \ - } while (0) - -#define OWSLogError(_messageFormat, ...) \ - do { \ - DDLogError(@"โค๏ธ %@%@", OWSLogPrefix(), [NSString stringWithFormat:_messageFormat, ##__VA_ARGS__]); \ - if (OWSLogger.aggressiveFlushing) { \ - OWSLogFlush(); \ - } \ - } while (0) - -#define OWSLogFlush() \ - do { \ - [DDLog flushLog]; \ - } while (0) +#define OWSLogFlush() do { [DDLog flushLog]; } while (0) NS_ASSUME_NONNULL_END diff --git a/SignalCoreKit/src/OWSLogs.m b/SignalCoreKit/src/OWSLogs.m index 82ddc8a..d6461f9 100644 --- a/SignalCoreKit/src/OWSLogs.m +++ b/SignalCoreKit/src/OWSLogs.m @@ -9,57 +9,63 @@ @implementation OWSLogger -+ (void)verbose:(NSString *)logString +static void logUnconditionally(DDLogFlag flag, const char *file, BOOL shouldTrimFilePath, NSUInteger line, const char *function, NSString *message) { - DDLogVerbose(@"๐Ÿ’™ %@", logString); + OWSCAssert(ShouldLogFlag(flag)); + NSString *fileObj = [NSString stringWithFormat:@"%s", file]; + fileObj = shouldTrimFilePath ? fileObj.lastPathComponent : fileObj; + DDLogMessage *logMessage = [[DDLogMessage alloc] initWithMessage:message + level:ddLogLevel + flag:flag + context:0 + file:fileObj + function:[NSString stringWithFormat:@"%s", function] + line:line + tag:nil + options:0 + timestamp:nil]; + [DDLog log:YES message:logMessage]; } -+ (void)debug:(NSString *)logString +void OWSLogUnconditionally(DDLogFlag flag, const char *file, BOOL shouldTrimFilePath, NSUInteger line, const char *function, NSString *format, ...) { - DDLogDebug(@"๐Ÿ’š %@", logString); + va_list args; + va_start(args, format); + NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + logUnconditionally(flag, file, shouldTrimFilePath, line, function, message); } -+ (void)info:(NSString *)logString -{ - DDLogInfo(@"๐Ÿ’› %@", logString); - if (self.aggressiveFlushing) { - [self flush]; +static void _logShim(DDLogFlag flag, NSString *logString) { + if (!ShouldLogFlag(flag)) { + return; } + logUnconditionally(flag, "", NO, 0, "", logString); } -+ (void)warn:(NSString *)logString ++ (void)verbose:(NSString *)logString { - DDLogWarn(@"๐Ÿงก %@", logString); - if (self.aggressiveFlushing) { - [self flush]; - } + _logShim(DDLogFlagVerbose, logString); } -+ (void)error:(NSString *)logString ++ (void)debug:(NSString *)logString { - DDLogError(@"โค๏ธ %@", logString); - if (self.aggressiveFlushing) { - [self flush]; - } + _logShim(DDLogFlagDebug, logString); } -+ (void)flush ++ (void)info:(NSString *)logString { - OWSLogFlush(); + _logShim(DDLogFlagInfo, logString); } -static _Atomic BOOL _aggressiveLogFlushingEnabled = ATOMIC_VAR_INIT(NO); - -+ (BOOL)aggressiveFlushing ++ (void)warn:(NSString *)logString { - return atomic_load(&_aggressiveLogFlushingEnabled); + _logShim(DDLogFlagWarning, logString); } -+ (void)setAggressiveFlushing:(BOOL)isEnabled ++ (void)error:(NSString *)logString { - if (atomic_exchange(&_aggressiveLogFlushingEnabled, isEnabled) != isEnabled) { - [self warn:[NSString stringWithFormat:@"%@ aggressive log flushing", isEnabled ? @"Enabled" : @"Disabled"]]; - } + _logShim(DDLogFlagError, logString); } @end diff --git a/SignalCoreKit/src/OWSSwiftUtils.swift b/SignalCoreKit/src/OWSSwiftUtils.swift index 83aeb2b..a2a75bb 100644 --- a/SignalCoreKit/src/OWSSwiftUtils.swift +++ b/SignalCoreKit/src/OWSSwiftUtils.swift @@ -12,72 +12,80 @@ public func assertOnQueue(_ queue: DispatchQueue) { } @inlinable -public func AssertIsOnMainThread(file: String = #file, - function: String = #function, - line: Int = #line) { +public func AssertIsOnMainThread( + file: String = #fileID, + function: String = #function, + line: Int = #line +) { if !Thread.isMainThread { owsFailDebug("Must be on main thread.", file: file, function: function, line: line) } } @inlinable -public func AssertNotOnMainThread(file: String = #file, - function: String = #function, - line: Int = #line) { +public func AssertNotOnMainThread( + file: String = #fileID, + function: String = #function, + line: Int = #line +) { if Thread.isMainThread { owsFailDebug("Must be off main thread.", file: file, function: function, line: line) } } @inlinable -public func owsFailDebug(_ logMessage: String, - file: String = #file, - function: String = #function, - line: Int = #line) { +public func owsFailDebug( + _ logMessage: String, + file: String = #fileID, + function: String = #function, + line: Int = #line +) { Logger.error(logMessage, file: file, function: function, line: line) - Logger.flush() - let formattedMessage = owsFormatLogMessage(logMessage, file: file, function: function, line: line) if IsDebuggerAttached() { TrapDebugger() } else { - assertionFailure(formattedMessage) + assertionFailure(logMessage) } } @inlinable -public func owsFail(_ logMessage: String, - file: String = #file, - function: String = #function, - line: Int = #line) -> Never { +public func owsFail( + _ logMessage: String, + file: String = #fileID, + function: String = #function, + line: Int = #line +) -> Never { logStackTrace() owsFailDebug(logMessage, file: file, function: function, line: line) - let formattedMessage = owsFormatLogMessage(logMessage, file: file, function: function, line: line) - fatalError(formattedMessage) + Logger.flush() + fatalError(logMessage) } @inlinable -public func owsAssertDebug(_ condition: Bool, - _ message: @autoclosure () -> String = String(), - file: String = #file, - function: String = #function, - line: Int = #line) { +public func owsAssertDebug( + _ condition: Bool, + _ message: @autoclosure () -> String = String(), + file: String = #fileID, + function: String = #function, + line: Int = #line +) { if !condition { let message: String = message() - owsFailDebug(message.isEmpty ? "Assertion failed." : message, - file: file, function: function, line: line) + owsFailDebug(message.isEmpty ? "Assertion failed." : message, file: file, function: function, line: line) } } @inlinable -public func owsAssert(_ condition: Bool, - _ message: @autoclosure () -> String = String(), - file: String = #file, - function: String = #function, - line: Int = #line) { +public func owsAssert( + _ condition: Bool, + _ message: @autoclosure () -> String = String(), + file: String = #fileID, + function: String = #function, + line: Int = #line +) { if !condition { let message: String = message() - owsFail(message.isEmpty ? "Assertion failed." : message, - file: file, function: function, line: line) + owsFail(message.isEmpty ? "Assertion failed." : message, file: file, function: function, line: line) } } @@ -85,17 +93,14 @@ public func owsAssert(_ condition: Bool, public class OWSSwiftUtils: NSObject { // This method can be invoked from Obj-C to exit the app. @objc - public class func owsFail(_ logMessage: String, - file: String = #file, - function: String = #function, - line: Int = #line) -> Never { - - logStackTrace() - owsFailDebug(logMessage, file: file, function: function, line: line) - let formattedMessage = owsFormatLogMessage(logMessage, file: file, function: function, line: line) - fatalError(formattedMessage) + public class func owsFailObjC( + _ logMessage: String, + file: String = #fileID, + function: String = #function, + line: Int = #line + ) -> Never { + owsFail(logMessage, file: file, function: function, line: line) } - } public func logStackTrace() {