优化RTMP播放器重连和稳定性
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2
Example/Pods/CocoaLumberjack/LICENSE
generated
2
Example/Pods/CocoaLumberjack/LICENSE
generated
@@ -1,6 +1,6 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2010-2021, Deusty, LLC
|
||||
Copyright (c) 2010-2026, 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:
|
||||
|
||||
74
Example/Pods/CocoaLumberjack/README.md
generated
74
Example/Pods/CocoaLumberjack/README.md
generated
@@ -4,26 +4,39 @@
|
||||
|
||||
CocoaLumberjack
|
||||
===============
|
||||

|
||||
[](http://cocoadocs.org/docsets/CocoaLumberjack/)
|
||||
[](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/latest)
|
||||
[](https://opensource.org/licenses/BSD-3-Clause)
|
||||
[](https://swiftpackageindex.com/CocoaLumberjack/CocoaLumberjack)
|
||||
[](https://swiftpackageindex.com/CocoaLumberjack/CocoaLumberjack)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](http://cocoadocs.org/docsets/CocoaLumberjack/)
|
||||
[](http://opensource.org/licenses/BSD-3-Clause)
|
||||

|
||||
[](https://codecov.io/gh/CocoaLumberjack/CocoaLumberjack)
|
||||
[](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.
|
||||
**CocoaLumberjack** is a fast & simple, yet powerful & flexible logging framework for macOS, iOS, tvOS, watchOS and visionOS.
|
||||
|
||||
## 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.
|
||||
First, install CocoaLumberjack via [Swift Package Manager](https://swift.org/package-manager/), [CocoaPods](https://cocoapods.org), [Carthage](https://github.com/Carthage/Carthage) or manually.
|
||||
Then use `DDOSLogger` for iOS 10 and later, or `DDTTYLogger` and `DDASLLogger` for earlier versions to begin logging messages.
|
||||
|
||||
|
||||
### 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", from: "3.9.0"),
|
||||
```
|
||||
|
||||
Note that you may need to add both products, `CocoaLumberjack` and `CocoaLumberjackSwift` to your target since SPM sometimes fails to detect that `CocoaLumberjackSwift` depends on `CocoaLumberjack`.
|
||||
|
||||
|
||||
### CocoaPods
|
||||
|
||||
```ruby
|
||||
platform :ios, '9.0'
|
||||
platform :ios, '11.0'
|
||||
|
||||
target 'SampleTarget' do
|
||||
use_frameworks!
|
||||
@@ -35,7 +48,7 @@ For more details about how to use Swift with Lumberjack, see [this conversation]
|
||||
|
||||
For Objective-C use the following:
|
||||
```ruby
|
||||
platform :ios, '9.0'
|
||||
platform :ios, '11.0'
|
||||
|
||||
target 'SampleTarget' do
|
||||
pod 'CocoaLumberjack'
|
||||
@@ -53,18 +66,6 @@ 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.7.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.
|
||||
@@ -126,6 +127,18 @@ You can then use `DDLogHandler` as backend for swift-log, which will forward all
|
||||
|
||||
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
|
||||
|
||||
@@ -184,14 +197,15 @@ Configure your logging however you want. Change log levels per file (perfect for
|
||||
|
||||
## Requirements
|
||||
The current version of Lumberjack requires:
|
||||
- Xcode 12 or later
|
||||
- Swift 5.3 or later
|
||||
- iOS 9 or later
|
||||
- macOS 10.10 or later
|
||||
- watchOS 3 or later
|
||||
- tvOS 9 or later
|
||||
- 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
|
||||
@@ -219,7 +233,7 @@ Per [App privacy details on the App Store](https://developer.apple.com/app-store
|
||||
|
||||
### Data collection by the framework
|
||||
|
||||
**By default, CocoaLumberjack does NOT collect any data on its own.**
|
||||
**By default, CocoaLumberjack does NOT collect any data on its own.**
|
||||
|
||||
[See our Data Collection Practices list.](https://cocoalumberjack.github.io/DataCollection/index.html)
|
||||
|
||||
@@ -257,7 +271,7 @@ _Example_: `DDLogInfo("User: \(myUser)")` will add the `myUser` info to the logs
|
||||
## Author
|
||||
|
||||
- [Robbie Hanson](https://github.com/robbiehanson)
|
||||
- Love the project? Wanna buy me a coffee? (or a beer :D) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UZRA26JPJB3DA)
|
||||
- Love the project? Wanna buy me a coffee? (or a beer :D) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UZRA26JPJB3DA)
|
||||
|
||||
## Collaborators
|
||||
- [Ernesto Rivera](https://github.com/rivera-ernesto)
|
||||
@@ -276,6 +290,8 @@ _Example_: `DDLogInfo("User: \(myUser)")` will add the `myUser` info to the logs
|
||||
- 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
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -29,7 +29,7 @@
|
||||
@implementation CLIColor
|
||||
|
||||
+ (instancetype)colorWithCalibratedRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha {
|
||||
CLIColor *color = [CLIColor new];
|
||||
__auto_type color = [CLIColor new];
|
||||
color->_red = red;
|
||||
color->_green = green;
|
||||
color->_blue = blue;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -29,8 +29,8 @@
|
||||
#define DD_LEGACY_MACROS 0
|
||||
#endif
|
||||
|
||||
static BOOL _cancel = YES;
|
||||
static DDLogLevel _captureLevel = DDLogLevelVerbose;
|
||||
static __auto_type _cancel = YES;
|
||||
static __auto_type _captureLevel = DDLogLevelVerbose;
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
@@ -73,7 +73,7 @@ static DDLogLevel _captureLevel = DDLogLevelVerbose;
|
||||
asl_set_query(query, kDDASLKeyDDLog, kDDASLDDLogValue, ASL_QUERY_OP_NOT_EQUAL);
|
||||
|
||||
#if !TARGET_OS_IPHONE || (defined(TARGET_SIMULATOR) && TARGET_SIMULATOR)
|
||||
int processId = [[NSProcessInfo processInfo] processIdentifier];
|
||||
__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);
|
||||
@@ -81,14 +81,14 @@ static DDLogLevel _captureLevel = DDLogLevelVerbose;
|
||||
}
|
||||
|
||||
+ (void)aslMessageReceived:(aslmsg)msg {
|
||||
const char* messageCString = asl_get( msg, ASL_KEY_MSG );
|
||||
if ( messageCString == NULL )
|
||||
__auto_type messageCString = asl_get(msg, ASL_KEY_MSG);
|
||||
if (messageCString == NULL)
|
||||
return;
|
||||
|
||||
DDLogFlag flag;
|
||||
BOOL async;
|
||||
|
||||
const char* levelCString = asl_get(msg, ASL_KEY_LEVEL);
|
||||
__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 :
|
||||
@@ -109,25 +109,25 @@ static DDLogLevel _captureLevel = DDLogLevelVerbose;
|
||||
// NSString * sender = [NSString stringWithCString:asl_get(msg, ASL_KEY_SENDER) encoding:NSUTF8StringEncoding];
|
||||
NSString *message = @(messageCString);
|
||||
|
||||
const char* secondsCString = asl_get( msg, ASL_KEY_TIME );
|
||||
const char* nanoCString = asl_get( msg, ASL_KEY_TIME_NSEC );
|
||||
NSTimeInterval seconds = secondsCString ? strtod(secondsCString, NULL) : [NSDate timeIntervalSinceReferenceDate] - NSTimeIntervalSince1970;
|
||||
double nanoSeconds = nanoCString? strtod(nanoCString, NULL) : 0;
|
||||
NSTimeInterval totalSeconds = seconds + (nanoSeconds / 1e9);
|
||||
__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);
|
||||
|
||||
NSDate *timeStamp = [NSDate dateWithTimeIntervalSince1970:totalSeconds];
|
||||
__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];
|
||||
|
||||
DDLogMessage *logMessage = [[DDLogMessage alloc] initWithMessage:message
|
||||
level:_captureLevel
|
||||
flag:flag
|
||||
context:0
|
||||
file:@"DDASLLogCapture"
|
||||
function:nil
|
||||
line:0
|
||||
tag:nil
|
||||
options:0
|
||||
timestamp:timeStamp];
|
||||
|
||||
[DDLog log:async message:logMessage];
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ static DDLogLevel _captureLevel = DDLogLevelVerbose;
|
||||
.tv_sec = 0
|
||||
};
|
||||
gettimeofday(&timeval, NULL);
|
||||
unsigned long long startTime = (unsigned long long)timeval.tv_sec;
|
||||
__auto_type startTime = (unsigned long long)timeval.tv_sec;
|
||||
__block unsigned long long lastSeenID = 0;
|
||||
|
||||
/*
|
||||
@@ -163,7 +163,7 @@ static DDLogLevel _captureLevel = DDLogLevelVerbose;
|
||||
// At least one message has been posted; build a search query.
|
||||
@autoreleasepool
|
||||
{
|
||||
aslmsg query = asl_new(ASL_TYPE_QUERY);
|
||||
__auto_type query = asl_new(ASL_TYPE_QUERY);
|
||||
char stringValue[64];
|
||||
|
||||
if (lastSeenID > 0) {
|
||||
@@ -178,8 +178,8 @@ static DDLogLevel _captureLevel = DDLogLevelVerbose;
|
||||
|
||||
// Iterate over new messages.
|
||||
aslmsg msg;
|
||||
aslresponse response = asl_search(NULL, query);
|
||||
|
||||
__auto_type response = asl_search(NULL, query);
|
||||
|
||||
while ((msg = asl_next(response)))
|
||||
{
|
||||
[self aslMessageReceived:msg];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -80,10 +80,10 @@ static DDASLLogger *sharedInstance;
|
||||
return;
|
||||
}
|
||||
|
||||
NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
|
||||
__auto_type message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
|
||||
|
||||
if (message) {
|
||||
const char *msg = [message UTF8String];
|
||||
__auto_type msg = [message UTF8String];
|
||||
|
||||
size_t aslLogLevel;
|
||||
switch (logMessage->_flag) {
|
||||
@@ -100,11 +100,11 @@ static DDASLLogger *sharedInstance;
|
||||
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.
|
||||
uid_t const readUID = geteuid();
|
||||
const __auto_type readUID = geteuid();
|
||||
|
||||
char readUIDString[16];
|
||||
#ifndef NS_BLOCK_ASSERTIONS
|
||||
size_t l = (size_t)snprintf(readUIDString, sizeof(readUIDString), "%d", readUID);
|
||||
__auto_type l = (size_t)snprintf(readUIDString, sizeof(readUIDString), "%d", readUID);
|
||||
#else
|
||||
snprintf(readUIDString, sizeof(readUIDString), "%d", readUID);
|
||||
#endif
|
||||
@@ -114,7 +114,7 @@ static DDASLLogger *sharedInstance;
|
||||
NSAssert(aslLogLevel < (sizeof(level_strings) / sizeof(level_strings[0])),
|
||||
@"Unhandled ASL log level.");
|
||||
|
||||
aslmsg m = asl_new(ASL_TYPE_MSG);
|
||||
__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 &&
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -114,21 +114,15 @@
|
||||
dispatch_source_cancel(_saveTimer);
|
||||
|
||||
// Must activate a timer before releasing it (or it will crash)
|
||||
if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)) {
|
||||
if (_saveTimerSuspended < 0) {
|
||||
dispatch_activate(_saveTimer);
|
||||
} else if (_saveTimerSuspended > 0) {
|
||||
dispatch_resume(_saveTimer);
|
||||
}
|
||||
} else {
|
||||
if (_saveTimerSuspended != 0) {
|
||||
dispatch_resume(_saveTimer);
|
||||
}
|
||||
if (_saveTimerSuspended < 0) {
|
||||
dispatch_activate(_saveTimer);
|
||||
} else if (_saveTimerSuspended > 0) {
|
||||
dispatch_resume(_saveTimer);
|
||||
}
|
||||
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
dispatch_release(_saveTimer);
|
||||
#endif
|
||||
#endif
|
||||
_saveTimer = NULL;
|
||||
_saveTimerSuspended = 0;
|
||||
}
|
||||
@@ -136,24 +130,17 @@
|
||||
|
||||
- (void)updateAndResumeSaveTimer {
|
||||
if ((_saveTimer != NULL) && (_saveInterval > 0.0) && (_unsavedTime > 0)) {
|
||||
uint64_t interval = (uint64_t)(_saveInterval * (NSTimeInterval) NSEC_PER_SEC);
|
||||
dispatch_time_t startTime = dispatch_time(_unsavedTime, (int64_t)interval);
|
||||
__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 (@available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)) {
|
||||
if (_saveTimerSuspended < 0) {
|
||||
dispatch_activate(_saveTimer);
|
||||
_saveTimerSuspended = 0;
|
||||
} else if (_saveTimerSuspended > 0) {
|
||||
dispatch_resume(_saveTimer);
|
||||
_saveTimerSuspended = 0;
|
||||
}
|
||||
} else {
|
||||
if (_saveTimerSuspended != 0) {
|
||||
dispatch_resume(_saveTimer);
|
||||
_saveTimerSuspended = 0;
|
||||
}
|
||||
if (_saveTimerSuspended < 0) {
|
||||
dispatch_activate(_saveTimer);
|
||||
_saveTimerSuspended = 0;
|
||||
} else if (_saveTimerSuspended > 0) {
|
||||
dispatch_resume(_saveTimer);
|
||||
_saveTimerSuspended = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,8 +150,8 @@
|
||||
_saveTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.loggerQueue);
|
||||
|
||||
dispatch_source_set_event_handler(_saveTimer, ^{ @autoreleasepool {
|
||||
[self performSaveAndSuspendSaveTimer];
|
||||
} });
|
||||
[self performSaveAndSuspendSaveTimer];
|
||||
} });
|
||||
|
||||
_saveTimerSuspended = -1;
|
||||
}
|
||||
@@ -173,16 +160,16 @@
|
||||
- (void)destroyDeleteTimer {
|
||||
if (_deleteTimer != NULL) {
|
||||
dispatch_source_cancel(_deleteTimer);
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
dispatch_release(_deleteTimer);
|
||||
#endif
|
||||
#endif
|
||||
_deleteTimer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateDeleteTimer {
|
||||
if ((_deleteTimer != NULL) && (_deleteInterval > 0.0) && (_maxAge > 0.0)) {
|
||||
int64_t interval = (int64_t)(_deleteInterval * (NSTimeInterval) NSEC_PER_SEC);
|
||||
__auto_type interval = (int64_t)(_deleteInterval * (NSTimeInterval) NSEC_PER_SEC);
|
||||
dispatch_time_t startTime;
|
||||
|
||||
if (_lastDeleteTime > 0) {
|
||||
@@ -201,17 +188,14 @@
|
||||
|
||||
if (_deleteTimer != NULL) {
|
||||
dispatch_source_set_event_handler(_deleteTimer, ^{ @autoreleasepool {
|
||||
[self performDelete];
|
||||
} });
|
||||
[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
|
||||
if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *))
|
||||
dispatch_activate(_deleteTimer);
|
||||
else
|
||||
dispatch_resume(_deleteTimer);
|
||||
dispatch_activate(_deleteTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,14 +215,10 @@
|
||||
// This is the intended result. Fix it by accessing the ivar directly.
|
||||
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
||||
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
||||
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
DDAbstractLoggerAssertLockedPropertyAccess();
|
||||
|
||||
__block NSUInteger result;
|
||||
|
||||
dispatch_sync(globalLoggingQueue, ^{
|
||||
dispatch_sync(DDLog.loggingQueue, ^{
|
||||
dispatch_sync(self.loggerQueue, ^{
|
||||
result = self->_saveThreshold;
|
||||
});
|
||||
@@ -271,10 +251,8 @@
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
@@ -291,14 +269,10 @@
|
||||
// This is the intended result. Fix it by accessing the ivar directly.
|
||||
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
||||
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
||||
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
DDAbstractLoggerAssertLockedPropertyAccess();
|
||||
|
||||
__block NSTimeInterval result;
|
||||
|
||||
dispatch_sync(globalLoggingQueue, ^{
|
||||
dispatch_sync(DDLog.loggingQueue, ^{
|
||||
dispatch_sync(self.loggerQueue, ^{
|
||||
result = self->_saveInterval;
|
||||
});
|
||||
@@ -308,7 +282,7 @@
|
||||
}
|
||||
|
||||
- (void)setSaveInterval:(NSTimeInterval)interval {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
// C99 recommended floating point comparison macro
|
||||
// Read: isLessThanOrGreaterThan(floatA, floatB)
|
||||
@@ -362,10 +336,8 @@
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
@@ -382,14 +354,11 @@
|
||||
// This is the intended result. Fix it by accessing the ivar directly.
|
||||
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
||||
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
||||
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
DDAbstractLoggerAssertLockedPropertyAccess();
|
||||
|
||||
__block NSTimeInterval result;
|
||||
|
||||
dispatch_sync(globalLoggingQueue, ^{
|
||||
dispatch_sync(DDLog.loggingQueue, ^{
|
||||
dispatch_sync(self.loggerQueue, ^{
|
||||
result = self->_maxAge;
|
||||
});
|
||||
@@ -399,14 +368,14 @@
|
||||
}
|
||||
|
||||
- (void)setMaxAge:(NSTimeInterval)interval {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
// C99 recommended floating point comparison macro
|
||||
// Read: isLessThanOrGreaterThan(floatA, floatB)
|
||||
|
||||
if (/* maxAge != interval */ islessgreater(self->_maxAge, interval)) {
|
||||
NSTimeInterval oldMaxAge = self->_maxAge;
|
||||
NSTimeInterval newMaxAge = interval;
|
||||
__auto_type oldMaxAge = self->_maxAge;
|
||||
__auto_type newMaxAge = interval;
|
||||
|
||||
self->_maxAge = interval;
|
||||
|
||||
@@ -424,7 +393,7 @@
|
||||
// 4. If the maxAge was decreased,
|
||||
// then we should do an immediate delete.
|
||||
|
||||
BOOL shouldDeleteNow = NO;
|
||||
__auto_type shouldDeleteNow = NO;
|
||||
|
||||
if (oldMaxAge > 0.0) {
|
||||
if (newMaxAge <= 0.0) {
|
||||
@@ -459,10 +428,8 @@
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
@@ -479,14 +446,11 @@
|
||||
// This is the intended result. Fix it by accessing the ivar directly.
|
||||
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
||||
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
||||
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
DDAbstractLoggerAssertLockedPropertyAccess();
|
||||
|
||||
__block NSTimeInterval result;
|
||||
|
||||
dispatch_sync(globalLoggingQueue, ^{
|
||||
dispatch_sync(DDLog.loggingQueue, ^{
|
||||
dispatch_sync(self.loggerQueue, ^{
|
||||
result = self->_deleteInterval;
|
||||
});
|
||||
@@ -496,7 +460,7 @@
|
||||
}
|
||||
|
||||
- (void)setDeleteInterval:(NSTimeInterval)interval {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
// C99 recommended floating point comparison macro
|
||||
// Read: isLessThanOrGreaterThan(floatA, floatB)
|
||||
@@ -549,10 +513,9 @@
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
@@ -569,14 +532,11 @@
|
||||
// This is the intended result. Fix it by accessing the ivar directly.
|
||||
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
||||
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
||||
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
DDAbstractLoggerAssertLockedPropertyAccess();
|
||||
|
||||
__block BOOL result;
|
||||
|
||||
dispatch_sync(globalLoggingQueue, ^{
|
||||
dispatch_sync(DDLog.loggingQueue, ^{
|
||||
dispatch_sync(self.loggerQueue, ^{
|
||||
result = self->_deleteOnEverySave;
|
||||
});
|
||||
@@ -586,7 +546,7 @@
|
||||
}
|
||||
|
||||
- (void)setDeleteOnEverySave:(BOOL)flag {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
self->_deleteOnEverySave = flag;
|
||||
};
|
||||
|
||||
@@ -596,10 +556,8 @@
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
@@ -610,7 +568,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)savePendingLogEntries {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
[self performSaveAndSuspendSaveTimer];
|
||||
}
|
||||
@@ -624,7 +582,7 @@
|
||||
}
|
||||
|
||||
- (void)deleteOldLogEntries {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
[self performDelete];
|
||||
}
|
||||
@@ -643,24 +601,20 @@
|
||||
|
||||
- (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);
|
||||
__auto_type firstUnsavedEntry = (++_unsavedCount == 1);
|
||||
|
||||
if ((_unsavedCount >= _saveThreshold) && (_saveThreshold > 0)) {
|
||||
[self performSaveAndSuspendSaveTimer];
|
||||
@@ -676,7 +630,6 @@
|
||||
//
|
||||
// It is called automatically when the application quits,
|
||||
// or if the developer invokes DDLog's flushLog method prior to crashing or something.
|
||||
|
||||
[self performSaveAndSuspendSaveTimer];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -48,6 +48,11 @@
|
||||
|
||||
#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.
|
||||
//
|
||||
@@ -107,7 +112,7 @@ static NSUInteger _numProcessors;
|
||||
* @return The singleton `DDLog`.
|
||||
*/
|
||||
+ (instancetype)sharedInstance {
|
||||
static id sharedInstance = nil;
|
||||
static DDLog *sharedInstance = nil;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
@@ -159,7 +164,7 @@ static NSUInteger _numProcessors;
|
||||
self._loggers = [[NSMutableArray alloc] initWithCapacity:4];
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
NSString *notificationName = UIApplicationWillTerminateNotification;
|
||||
__auto_type notificationName = UIApplicationWillTerminateNotification;
|
||||
#else
|
||||
NSString *notificationName = nil;
|
||||
|
||||
@@ -317,7 +322,7 @@ static NSUInteger _numProcessors;
|
||||
// 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.
|
||||
|
||||
dispatch_block_t logBlock = ^{
|
||||
__auto_type logBlock = ^{
|
||||
// We're now sure we won't overflow the queue.
|
||||
// It is time to queue our log message.
|
||||
@autoreleasepool {
|
||||
@@ -349,21 +354,16 @@ static NSUInteger _numProcessors;
|
||||
if (format) {
|
||||
va_start(args, format);
|
||||
|
||||
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
||||
|
||||
va_end(args);
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
[self log:asynchronous
|
||||
message:message
|
||||
level:level
|
||||
flag:flag
|
||||
context:context
|
||||
file:file
|
||||
function:function
|
||||
line:line
|
||||
tag:tag];
|
||||
tag:tag
|
||||
format:format
|
||||
args:args];
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
@@ -383,21 +383,16 @@ static NSUInteger _numProcessors;
|
||||
if (format) {
|
||||
va_start(args, format);
|
||||
|
||||
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
||||
|
||||
va_end(args);
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
[self log:asynchronous
|
||||
message:message
|
||||
level:level
|
||||
flag:flag
|
||||
context:context
|
||||
file:file
|
||||
function:function
|
||||
line:line
|
||||
tag:tag];
|
||||
tag:tag
|
||||
format:format
|
||||
args:args];
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
@@ -427,54 +422,26 @@ static NSUInteger _numProcessors;
|
||||
format:(NSString *)format
|
||||
args:(va_list)args {
|
||||
if (format) {
|
||||
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
|
||||
[self log:asynchronous
|
||||
message:message
|
||||
level:level
|
||||
flag:flag
|
||||
context:context
|
||||
file:file
|
||||
function:function
|
||||
line:line
|
||||
tag:tag];
|
||||
// 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:(NSString *)message
|
||||
level:(DDLogLevel)level
|
||||
flag:(DDLogFlag)flag
|
||||
context:(NSInteger)context
|
||||
file:(const char *)file
|
||||
function:(const char *)function
|
||||
line:(NSUInteger)line
|
||||
tag:(id)tag {
|
||||
[self.sharedInstance log:asynchronous message:message level:level flag:flag context:context file:file function:function line:line tag:tag];
|
||||
}
|
||||
|
||||
- (void)log:(BOOL)asynchronous
|
||||
message:(NSString *)message
|
||||
level:(DDLogLevel)level
|
||||
flag:(DDLogFlag)flag
|
||||
context:(NSInteger)context
|
||||
file:(const char *)file
|
||||
function:(const char *)function
|
||||
line:(NSUInteger)line
|
||||
tag:(id)tag {
|
||||
DDLogMessage *logMessage = [[DDLogMessage alloc] initWithMessage:message
|
||||
level:level
|
||||
flag:flag
|
||||
context:context
|
||||
file:[NSString stringWithFormat:@"%s", file]
|
||||
function:[NSString stringWithFormat:@"%s", function]
|
||||
line:line
|
||||
tag:tag
|
||||
options:(DDLogMessageOptions)0
|
||||
timestamp:nil];
|
||||
|
||||
[self queueLogMessage:logMessage asynchronously:asynchronous];
|
||||
}
|
||||
|
||||
+ (void)log:(BOOL)asynchronous message:(DDLogMessage *)logMessage {
|
||||
[self.sharedInstance log:asynchronous message:logMessage];
|
||||
}
|
||||
@@ -488,12 +455,12 @@ static NSUInteger _numProcessors;
|
||||
}
|
||||
|
||||
- (void)flushLog {
|
||||
NSAssert(!dispatch_get_specific(GlobalLoggingQueueIdentityKey),
|
||||
@"This method shouldn't be run on the logging thread/queue that make flush fast enough");
|
||||
|
||||
dispatch_sync(_loggingQueue, ^{ @autoreleasepool {
|
||||
[self lt_flush];
|
||||
} });
|
||||
DDLogAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_sync(_loggingQueue, ^{
|
||||
@autoreleasepool {
|
||||
[self lt_flush];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -501,69 +468,65 @@ static NSUInteger _numProcessors;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+ (BOOL)isRegisteredClass:(Class)class {
|
||||
SEL getterSel = @selector(ddLogLevel);
|
||||
SEL setterSel = @selector(ddSetLogLevel:);
|
||||
|
||||
#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
|
||||
__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+.
|
||||
|
||||
BOOL result = NO;
|
||||
#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);
|
||||
|
||||
unsigned int methodCount, i;
|
||||
Method *methodList = class_copyMethodList(object_getClass(class), &methodCount);
|
||||
if (methodList != NULL) {
|
||||
__auto_type getterFound = NO;
|
||||
__auto_type setterFound = NO;
|
||||
|
||||
if (methodList != NULL) {
|
||||
BOOL getterFound = NO;
|
||||
BOOL setterFound = NO;
|
||||
for (i = 0; i < methodCount; ++i) {
|
||||
__auto_type currentSel = method_getName(methodList[i]);
|
||||
|
||||
for (i = 0; i < methodCount; ++i) {
|
||||
SEL currentSel = method_getName(methodList[i]);
|
||||
if (currentSel == getterSel) {
|
||||
getterFound = YES;
|
||||
} else if (currentSel == setterSel) {
|
||||
setterFound = YES;
|
||||
}
|
||||
|
||||
if (currentSel == getterSel) {
|
||||
getterFound = YES;
|
||||
} else if (currentSel == setterSel) {
|
||||
setterFound = YES;
|
||||
if (getterFound && setterFound) {
|
||||
result = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (getterFound && setterFound) {
|
||||
result = YES;
|
||||
break;
|
||||
}
|
||||
free(methodList);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
#else /* if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR */
|
||||
|
||||
// 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 /* 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.
|
||||
//
|
||||
@@ -579,23 +542,19 @@ static NSUInteger _numProcessors;
|
||||
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.
|
||||
|
||||
NSUInteger bufferSize = numClasses;
|
||||
|
||||
__auto_type bufferSize = numClasses;
|
||||
classes = numClasses ? (Class *)calloc(bufferSize, sizeof(Class)) : NULL;
|
||||
if (classes == NULL) {
|
||||
return @[]; //no memory or classes?
|
||||
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
|
||||
// apparently more classes added between calls (or a problem); try again
|
||||
free(classes);
|
||||
classes = NULL;
|
||||
numClasses = 0;
|
||||
@@ -603,10 +562,9 @@ static NSUInteger _numProcessors;
|
||||
}
|
||||
|
||||
// We can now loop through the classes, and test each one to see if it is a DDLogging class.
|
||||
|
||||
NSMutableArray *result = [NSMutableArray arrayWithCapacity:numClasses];
|
||||
|
||||
__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]) {
|
||||
@@ -620,8 +578,8 @@ static NSUInteger _numProcessors;
|
||||
}
|
||||
|
||||
+ (NSArray *)registeredClassNames {
|
||||
NSArray *registeredClasses = [self registeredClasses];
|
||||
NSMutableArray *result = [NSMutableArray arrayWithCapacity:[registeredClasses count]];
|
||||
__auto_type registeredClasses = [self registeredClasses];
|
||||
__auto_type result = [NSMutableArray arrayWithCapacity:[registeredClasses count]];
|
||||
|
||||
for (Class class in registeredClasses) {
|
||||
[result addObject:NSStringFromClass(class)];
|
||||
@@ -637,9 +595,9 @@ static NSUInteger _numProcessors;
|
||||
}
|
||||
|
||||
+ (DDLogLevel)levelForClassWithName:(NSString *)aClassName {
|
||||
Class aClass = NSClassFromString(aClassName);
|
||||
|
||||
return [self levelForClass:aClass];
|
||||
Class clazz = NSClassFromString(aClassName);
|
||||
if (clazz == nil) return (DDLogLevel)-1;
|
||||
return [self levelForClass:clazz];
|
||||
}
|
||||
|
||||
+ (void)setLevel:(DDLogLevel)level forClass:(Class)aClass {
|
||||
@@ -649,8 +607,9 @@ static NSUInteger _numProcessors;
|
||||
}
|
||||
|
||||
+ (void)setLevel:(DDLogLevel)level forClassWithName:(NSString *)aClassName {
|
||||
Class aClass = NSClassFromString(aClassName);
|
||||
[self setLevel:level forClass:aClass];
|
||||
Class clazz = NSClassFromString(aClassName);
|
||||
if (clazz == nil) return;
|
||||
[self setLevel:level forClass:clazz];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -662,15 +621,13 @@ static NSUInteger _numProcessors;
|
||||
// Need to create loggerQueue if loggerNode doesn't provide one.
|
||||
|
||||
for (DDLoggerNode *node in self._loggers) {
|
||||
if (node->_logger == logger
|
||||
&& node->_level == level) {
|
||||
if (node->_logger == logger && node->_level == level) {
|
||||
// Exactly same logger already added, exit
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
|
||||
@"This method should only be run on the logging thread/queue");
|
||||
DDLogAssertOnGlobalLoggingQueue();
|
||||
|
||||
dispatch_queue_t loggerQueue = NULL;
|
||||
if ([logger respondsToSelector:@selector(loggerQueue)]) {
|
||||
@@ -690,7 +647,7 @@ static NSUInteger _numProcessors;
|
||||
loggerQueue = dispatch_queue_create(loggerQueueName, NULL);
|
||||
}
|
||||
|
||||
DDLoggerNode *loggerNode = [DDLoggerNode nodeWithLogger:logger loggerQueue:loggerQueue level:level];
|
||||
__auto_type loggerNode = [DDLoggerNode nodeWithLogger:logger loggerQueue:loggerQueue level:level];
|
||||
[self._loggers addObject:loggerNode];
|
||||
|
||||
if ([logger respondsToSelector:@selector(didAddLoggerInQueue:)]) {
|
||||
@@ -707,8 +664,7 @@ static NSUInteger _numProcessors;
|
||||
- (void)lt_removeLogger:(id <DDLogger>)logger {
|
||||
// Find associated loggerNode in list of added loggers
|
||||
|
||||
NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
|
||||
@"This method should only be run on the logging thread/queue");
|
||||
DDLogAssertOnGlobalLoggingQueue();
|
||||
|
||||
DDLoggerNode *loggerNode = nil;
|
||||
|
||||
@@ -736,8 +692,7 @@ static NSUInteger _numProcessors;
|
||||
}
|
||||
|
||||
- (void)lt_removeAllLoggers {
|
||||
NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
|
||||
@"This method should only be run on the logging thread/queue");
|
||||
DDLogAssertOnGlobalLoggingQueue();
|
||||
|
||||
// Notify all loggers
|
||||
for (DDLoggerNode *loggerNode in self._loggers) {
|
||||
@@ -749,17 +704,16 @@ static NSUInteger _numProcessors;
|
||||
}
|
||||
|
||||
// Remove all loggers from array
|
||||
|
||||
[self._loggers removeAllObjects];
|
||||
}
|
||||
|
||||
- (NSArray *)lt_allLoggers {
|
||||
NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
|
||||
@"This method should only be run on the logging thread/queue");
|
||||
DDLogAssertOnGlobalLoggingQueue();
|
||||
|
||||
NSMutableArray *theLoggers = [NSMutableArray new];
|
||||
__auto_type loggerNodes = self._loggers;
|
||||
__auto_type theLoggers = [NSMutableArray arrayWithCapacity:loggerNodes.count];
|
||||
|
||||
for (DDLoggerNode *loggerNode in self._loggers) {
|
||||
for (DDLoggerNode *loggerNode in loggerNodes) {
|
||||
[theLoggers addObject:loggerNode->_logger];
|
||||
}
|
||||
|
||||
@@ -767,12 +721,13 @@ static NSUInteger _numProcessors;
|
||||
}
|
||||
|
||||
- (NSArray *)lt_allLoggersWithLevel {
|
||||
NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
|
||||
@"This method should only be run on the logging thread/queue");
|
||||
DDLogAssertOnGlobalLoggingQueue();
|
||||
|
||||
NSMutableArray *theLoggersWithLevel = [NSMutableArray new];
|
||||
|
||||
for (DDLoggerNode *loggerNode in self._loggers) {
|
||||
__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]];
|
||||
}
|
||||
@@ -781,10 +736,9 @@ static NSUInteger _numProcessors;
|
||||
}
|
||||
|
||||
- (void)lt_log:(DDLogMessage *)logMessage {
|
||||
// Execute the given log message on each of our loggers.
|
||||
DDLogAssertOnGlobalLoggingQueue();
|
||||
|
||||
NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
|
||||
@"This method should only be run on the logging thread/queue");
|
||||
// Execute the given log message on each of our loggers.
|
||||
|
||||
if (_numProcessors > 1) {
|
||||
// Execute each logger concurrently, each within its own queue.
|
||||
@@ -797,7 +751,7 @@ static NSUInteger _numProcessors;
|
||||
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)) {
|
||||
if (!(logMessage->_flag & (DDLogFlag)(loggerNode->_level))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -813,7 +767,7 @@ static NSUInteger _numProcessors;
|
||||
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)) {
|
||||
if (!(logMessage->_flag & (DDLogFlag)(loggerNode->_level))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -846,8 +800,7 @@ static NSUInteger _numProcessors;
|
||||
// Now we need to propagate the flush request to any loggers that implement the flush method.
|
||||
// This is designed for loggers that buffer IO.
|
||||
|
||||
NSAssert(dispatch_get_specific(GlobalLoggingQueueIdentityKey),
|
||||
@"This method should only be run on the logging thread/queue");
|
||||
DDLogAssertOnGlobalLoggingQueue();
|
||||
|
||||
for (DDLoggerNode *loggerNode in self._loggers) {
|
||||
if ([loggerNode->_logger respondsToSelector:@selector(flush)]) {
|
||||
@@ -872,8 +825,7 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
char *lastSlash = NULL;
|
||||
char *lastDot = NULL;
|
||||
|
||||
char *p = (char *)filePath;
|
||||
|
||||
__auto_type p = (char *)filePath;
|
||||
while (*p != '\0') {
|
||||
if (*p == '/') {
|
||||
lastSlash = p;
|
||||
@@ -939,9 +891,9 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
|
||||
if (loggerQueue) {
|
||||
_loggerQueue = loggerQueue;
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
dispatch_retain(loggerQueue);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
_level = level;
|
||||
@@ -954,11 +906,11 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
if (_loggerQueue) {
|
||||
dispatch_release(_loggerQueue);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -974,27 +926,33 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
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 {
|
||||
if ((self = [super init])) {
|
||||
BOOL copyMessage = (options & DDLogMessageDontCopyMessage) == 0;
|
||||
_message = copyMessage ? [message copy] : message;
|
||||
_level = level;
|
||||
_flag = flag;
|
||||
_context = context;
|
||||
- (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);
|
||||
|
||||
BOOL copyFile = (options & DDLogMessageCopyFile) != 0;
|
||||
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;
|
||||
|
||||
BOOL copyFunction = (options & DDLogMessageCopyFunction) != 0;
|
||||
__auto_type copyFunction = (options & DDLogMessageCopyFunction) != 0;
|
||||
_function = copyFunction ? [function copy] : function;
|
||||
|
||||
_line = line;
|
||||
@@ -1006,48 +964,111 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
_options = options;
|
||||
_timestamp = timestamp ?: [NSDate new];
|
||||
_timestamp = timestamp ?: [NSDate date];
|
||||
|
||||
__uint64_t tid;
|
||||
if (pthread_threadid_np(NULL, &tid) == 0) {
|
||||
_threadID = [[NSString alloc] initWithFormat:@"%llu", tid];
|
||||
} else {
|
||||
_threadID = @"missing threadId";
|
||||
_threadID = @"N/A";
|
||||
}
|
||||
_threadName = NSThread.currentThread.name;
|
||||
|
||||
// Get the file name without extension
|
||||
_fileName = [_file lastPathComponent];
|
||||
NSUInteger dotLocation = [_fileName rangeOfString:@"." options:NSBackwardsSearch].location;
|
||||
if (dotLocation != NSNotFound)
|
||||
{
|
||||
__auto_type dotLocation = [_fileName rangeOfString:@"." options:NSBackwardsSearch].location;
|
||||
if (dotLocation != NSNotFound) {
|
||||
_fileName = [_fileName substringToIndex:dotLocation];
|
||||
}
|
||||
|
||||
// Try to get the current queue's label
|
||||
_queueLabel = [[NSString alloc] initWithFormat:@"%s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_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 (![super isEqual:other] || ![other isKindOfClass:[self class]]) {
|
||||
} 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]
|
||||
&& [otherMsg->_fileName isEqualToString:_fileName]
|
||||
&& [otherMsg->_function isEqualToString:_function]
|
||||
&& _nullable_strings_equal(otherMsg->_function, _function)
|
||||
&& otherMsg->_line == _line
|
||||
&& (([otherMsg->_representedObject respondsToSelector:@selector(isEqual:)] && [otherMsg->_representedObject isEqual:_representedObject]) || otherMsg->_representedObject == _representedObject)
|
||||
&& otherMsg->_options == _options
|
||||
&& [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]
|
||||
@@ -1056,17 +1077,17 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return [super hash]
|
||||
^ _message.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
|
||||
^ _fileName.hash
|
||||
^ _function.hash
|
||||
^ _line
|
||||
^ ([_representedObject respondsToSelector:@selector(hash)] ? [_representedObject hash] : 0)
|
||||
^ _options
|
||||
^ ([_representedObject respondsToSelector:@selector(hash)] ? [_representedObject hash] : (NSUInteger)_representedObject)
|
||||
^ _timestamp.hash
|
||||
^ _threadID.hash
|
||||
^ _queueLabel.hash
|
||||
@@ -1076,6 +1097,7 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
- (id)copyWithZone:(NSZone * __attribute__((unused)))zone {
|
||||
DDLogMessage *newMessage = [DDLogMessage new];
|
||||
|
||||
newMessage->_messageFormat = _messageFormat;
|
||||
newMessage->_message = _message;
|
||||
newMessage->_level = _level;
|
||||
newMessage->_flag = _flag;
|
||||
@@ -1139,8 +1161,8 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
//
|
||||
// This is used primarily for thread-safety assertions (via the isOnInternalLoggerQueue method below).
|
||||
|
||||
void *key = (__bridge void *)self;
|
||||
void *nonNullValue = (__bridge void *)self;
|
||||
__auto_type key = (__bridge void *)self;
|
||||
__auto_type nonNullValue = (__bridge void *)self;
|
||||
|
||||
dispatch_queue_set_specific(_loggerQueue, key, nonNullValue, NULL);
|
||||
}
|
||||
@@ -1149,13 +1171,11 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
if (_loggerQueue) {
|
||||
dispatch_release(_loggerQueue);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)logMessage:(DDLogMessage * __attribute__((unused)))logMessage {
|
||||
@@ -1212,14 +1232,10 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
// This is the intended result. Fix it by accessing the ivar directly.
|
||||
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
||||
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
||||
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
DDAbstractLoggerAssertLockedPropertyAccess();
|
||||
|
||||
__block id <DDLogFormatter> result;
|
||||
|
||||
dispatch_sync(globalLoggingQueue, ^{
|
||||
dispatch_sync(DDLog.loggingQueue, ^{
|
||||
dispatch_sync(self->_loggerQueue, ^{
|
||||
result = self->_logFormatter;
|
||||
});
|
||||
@@ -1231,10 +1247,9 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
- (void)setLogFormatter:(id <DDLogFormatter>)logFormatter {
|
||||
// The design of this method is documented extensively in the logFormatter message (above in code).
|
||||
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
||||
DDAbstractLoggerAssertLockedPropertyAccess();
|
||||
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
if (self->_logFormatter != logFormatter) {
|
||||
if ([self->_logFormatter respondsToSelector:@selector(willRemoveFromLogger:)]) {
|
||||
@@ -1270,9 +1285,7 @@ NSString * __nullable DDExtractFileNameWithoutExtension(const char *filePath, BO
|
||||
}
|
||||
|
||||
- (BOOL)isOnInternalLoggerQueue {
|
||||
void *key = (__bridge void *)self;
|
||||
|
||||
return (dispatch_get_specific(key) != NULL);
|
||||
return dispatch_get_specific((__bridge void *)self) != NULL;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -13,18 +13,51 @@
|
||||
// to endorse or promote products derived from this software without specific
|
||||
// prior written permission of Deusty, LLC.
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
#import <os/log.h>
|
||||
|
||||
#import <CocoaLumberjack/DDOSLogger.h>
|
||||
|
||||
@interface DDOSLogger () {
|
||||
NSString *_subsystem;
|
||||
NSString *_category;
|
||||
@implementation DDOSLogLevelMapperDefault
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
return self;
|
||||
}
|
||||
|
||||
@property (copy, nonatomic, readonly, nullable) NSString *subsystem;
|
||||
@property (copy, nonatomic, readonly, nullable) NSString *category;
|
||||
@property (strong, nonatomic, readwrite, nonnull) os_log_t logger;
|
||||
- (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
|
||||
|
||||
@@ -32,29 +65,14 @@
|
||||
|
||||
@synthesize subsystem = _subsystem;
|
||||
@synthesize category = _category;
|
||||
@synthesize logLevelMapper = _logLevelMapper;
|
||||
@synthesize logger = _logger;
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
/**
|
||||
* Assertion
|
||||
* Swift: (String, String)?
|
||||
*/
|
||||
- (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];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
#pragma mark - Shared Instance
|
||||
|
||||
API_AVAILABLE(macos(10.12), ios(10.0), watchos(3.0), tvos(10.0))
|
||||
static DDOSLogger *sharedInstance;
|
||||
|
||||
- (instancetype)init {
|
||||
return [self initWithSubsystem:nil category:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static dispatch_once_t DDOSLoggerOnceToken;
|
||||
|
||||
@@ -65,53 +83,75 @@ static DDOSLogger *sharedInstance;
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
#pragma mark - os_log
|
||||
|
||||
- (os_log_t)getLogger {
|
||||
if (self.subsystem == nil || self.category == nil) {
|
||||
return OS_LOG_DEFAULT;
|
||||
#pragma mark - Initialization
|
||||
- (instancetype)initWithSubsystem:(NSString *)subsystem
|
||||
category:(NSString *)category
|
||||
logLevelMapper:(id<DDOSLogLevelMapper>)logLevelMapper {
|
||||
NSAssert((subsystem == nil) == (category == nil),
|
||||
@"Either both subsystem and category or neither should be nil.");
|
||||
NSParameterAssert(logLevelMapper);
|
||||
if (self = [super init]) {
|
||||
_subsystem = [subsystem copy];
|
||||
_category = [category copy];
|
||||
_logLevelMapper = logLevelMapper;
|
||||
}
|
||||
return os_log_create(self.subsystem.UTF8String, self.category.UTF8String);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSubsystem:(NSString *)subsystem category:(NSString *)category {
|
||||
return [self initWithSubsystem:subsystem
|
||||
category:category
|
||||
logLevelMapper:[[DDOSLogLevelMapperDefault alloc] init]];
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
return [self initWithSubsystem:nil category:nil];
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (instancetype)initWithLogLevelMapper:(id<DDOSLogLevelMapper>)logLevelMapper {
|
||||
return [self initWithSubsystem:nil category:nil logLevelMapper:logLevelMapper];
|
||||
}
|
||||
|
||||
#pragma mark - Mapper
|
||||
- (id<DDOSLogLevelMapper>)logLevelMapper {
|
||||
if (_logLevelMapper == nil) {
|
||||
_logLevelMapper = [[DDOSLogLevelMapperDefault alloc] init];
|
||||
}
|
||||
return _logLevelMapper;
|
||||
}
|
||||
|
||||
#pragma mark - os_log
|
||||
- (os_log_t)logger {
|
||||
if (_logger == nil) {
|
||||
_logger = [self getLogger];
|
||||
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 {
|
||||
// Skip captured log messages
|
||||
#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, *)) {
|
||||
NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
|
||||
__auto_type message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
|
||||
if (message != nil) {
|
||||
const char *msg = [message UTF8String];
|
||||
__auto_type logger = [self logger];
|
||||
switch (logMessage->_flag) {
|
||||
case DDLogFlagError :
|
||||
os_log_error(logger, "%{public}s", msg);
|
||||
break;
|
||||
case DDLogFlagWarning:
|
||||
case DDLogFlagInfo :
|
||||
os_log_info(logger, "%{public}s", msg);
|
||||
break;
|
||||
case DDLogFlagDebug :
|
||||
case DDLogFlagVerbose:
|
||||
default :
|
||||
os_log_debug(logger, "%{public}s", msg);
|
||||
break;
|
||||
}
|
||||
__auto_type logType = [self.logLevelMapper osLogTypeForLogFlag:logMessage->_flag];
|
||||
os_log_with_type(self.logger, logType, "%{public}s", message.UTF8String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -79,23 +79,18 @@
|
||||
#define MAP_TO_TERMINAL_APP_COLORS 1
|
||||
|
||||
typedef struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
} DDRGBColor;
|
||||
|
||||
@interface DDTTYLoggerColorProfile : NSObject {
|
||||
@public
|
||||
@public
|
||||
DDLogFlag mask;
|
||||
NSInteger 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;
|
||||
DDRGBColor fg;
|
||||
DDRGBColor bg;
|
||||
|
||||
NSUInteger fgCodeIndex;
|
||||
NSString *fgCodeRaw;
|
||||
@@ -117,19 +112,15 @@ typedef struct {
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface DDTTYLogger () {
|
||||
NSString *_appName;
|
||||
char *_app;
|
||||
size_t _appLen;
|
||||
|
||||
|
||||
NSString *_processID;
|
||||
char *_pid;
|
||||
size_t _pidLen;
|
||||
|
||||
|
||||
BOOL _colorsEnabled;
|
||||
NSMutableArray *_colorProfilesArray;
|
||||
NSMutableDictionary *_colorProfilesDict;
|
||||
@@ -137,6 +128,7 @@ typedef struct {
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation DDTTYLogger
|
||||
|
||||
@@ -144,30 +136,30 @@ static BOOL isaColorTTY;
|
||||
static BOOL isaColor256TTY;
|
||||
static BOOL isaXcodeColorTTY;
|
||||
|
||||
static NSArray *codes_fg = nil;
|
||||
static NSArray *codes_bg = nil;
|
||||
static NSArray *codesFg = nil;
|
||||
static NSArray *codesBg = 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.
|
||||
* 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)initialize_colors_16 {
|
||||
if (codes_fg || codes_bg || colors) {
|
||||
+ (void)initializeColors16 {
|
||||
if (codesFg || codesBg || colors) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableArray *m_colors = [NSMutableArray arrayWithCapacity:16];
|
||||
__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
|
||||
codes_fg = @[
|
||||
codesFg = @[
|
||||
@"30m", // normal - black
|
||||
@"31m", // normal - red
|
||||
@"32m", // normal - green
|
||||
@@ -186,7 +178,7 @@ static DDTTYLogger *sharedInstance;
|
||||
@"1;37m", // bright - white
|
||||
];
|
||||
|
||||
codes_bg = @[
|
||||
codesBg = @[
|
||||
@"40m", // normal - black
|
||||
@"41m", // normal - red
|
||||
@"42m", // normal - green
|
||||
@@ -205,13 +197,12 @@ static DDTTYLogger *sharedInstance;
|
||||
@"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.
|
||||
DDRGBColor rgbColors[] = {
|
||||
const DDRGBColor rgbColors[] = {
|
||||
{ 0, 0, 0}, // normal - black
|
||||
{194, 54, 33}, // normal - red
|
||||
{ 37, 188, 36}, // normal - green
|
||||
@@ -235,8 +226,7 @@ static DDTTYLogger *sharedInstance;
|
||||
// Standard xterm colors:
|
||||
//
|
||||
// These are the default colors used by most xterm shells.
|
||||
|
||||
DDRGBColor rgbColors[] = {
|
||||
const DDRGBColor rgbColors[] = {
|
||||
{ 0, 0, 0}, // normal - black
|
||||
{205, 0, 0}, // normal - red
|
||||
{ 0, 205, 0}, // normal - green
|
||||
@@ -257,30 +247,30 @@ static DDTTYLogger *sharedInstance;
|
||||
#endif /* if MAP_TO_TERMINAL_APP_COLORS */
|
||||
|
||||
for (size_t i = 0; i < sizeof(rgbColors) / sizeof(rgbColors[0]); ++i) {
|
||||
[m_colors addObject:DDMakeColor(rgbColors[i].r, rgbColors[i].g, rgbColors[i].b)];
|
||||
[mColors addObject:DDMakeColor(rgbColors[i].r, rgbColors[i].g, rgbColors[i].b)];
|
||||
}
|
||||
colors = [m_colors copy];
|
||||
colors = [mColors copy];
|
||||
|
||||
NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
|
||||
NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)");
|
||||
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 codes_fg and codes_bg arrays, for 256 color mode.
|
||||
* 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)initialize_colors_256 {
|
||||
if (codes_fg || codes_bg || colors) {
|
||||
+ (void)initializeColors256 {
|
||||
if (codesFg || codesBg || 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)];
|
||||
__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
|
||||
#if MAP_TO_TERMINAL_APP_COLORS
|
||||
|
||||
// Standard Terminal.app colors:
|
||||
//
|
||||
@@ -307,7 +297,7 @@ static DDTTYLogger *sharedInstance;
|
||||
// http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
|
||||
// Colors
|
||||
DDRGBColor rgbColors[] = {
|
||||
const DDRGBColor rgbColors[] = {
|
||||
{ 47, 49, 49},
|
||||
{ 60, 42, 144},
|
||||
{ 66, 44, 183},
|
||||
@@ -592,21 +582,19 @@ static DDTTYLogger *sharedInstance;
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(rgbColors) / sizeof(rgbColors[0]); ++i) {
|
||||
[m_colors addObject:DDMakeColor(rgbColors[i].r, rgbColors[i].g, rgbColors[i].b)];
|
||||
[mColors addObject:DDMakeColor(rgbColors[i].r, rgbColors[i].g, rgbColors[i].b)];
|
||||
}
|
||||
|
||||
// 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]];
|
||||
[mCodesFg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
|
||||
[mCodesBg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
#else /* if MAP_TO_TERMINAL_APP_COLORS */
|
||||
#else /* if MAP_TO_TERMINAL_APP_COLORS */
|
||||
|
||||
// Standard xterm colors:
|
||||
//
|
||||
@@ -652,9 +640,9 @@ static DDTTYLogger *sharedInstance;
|
||||
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:DDMakeColor(r, g, b)];
|
||||
[mCodesFg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
|
||||
[mCodesBg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
|
||||
[mColors addObject:DDMakeColor(r, g, b)];
|
||||
|
||||
index++;
|
||||
}
|
||||
@@ -668,9 +656,9 @@ static DDTTYLogger *sharedInstance;
|
||||
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:DDMakeColor(r, g, b)];
|
||||
[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;
|
||||
@@ -679,22 +667,21 @@ static DDTTYLogger *sharedInstance;
|
||||
index++;
|
||||
}
|
||||
|
||||
#endif /* if MAP_TO_TERMINAL_APP_COLORS */
|
||||
#endif /* if MAP_TO_TERMINAL_APP_COLORS */
|
||||
|
||||
codes_fg = [m_codes_fg copy];
|
||||
codes_bg = [m_codes_bg copy];
|
||||
colors = [m_colors copy];
|
||||
codesFg = [mCodesFg copy];
|
||||
codesBg = [mCodesBg copy];
|
||||
colors = [mColors copy];
|
||||
|
||||
NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
|
||||
NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)");
|
||||
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
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
// iOS
|
||||
|
||||
BOOL done = NO;
|
||||
__auto_type done = NO;
|
||||
|
||||
if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)]) {
|
||||
done = [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL];
|
||||
@@ -704,44 +691,49 @@ static DDTTYLogger *sharedInstance;
|
||||
// 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();
|
||||
__auto_type rgbColorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
unsigned char pixel[4];
|
||||
CGContextRef context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, rgbColorSpace, (CGBitmapInfo)(kCGBitmapAlphaInfoMask & kCGImageAlphaNoneSkipLast));
|
||||
__auto_type context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, rgbColorSpace, (CGBitmapInfo)(((CGImageAlphaInfo)kCGBitmapAlphaInfoMask) & kCGImageAlphaNoneSkipLast));
|
||||
|
||||
CGContextSetFillColorWithColor(context, [color CGColor]);
|
||||
CGContextFillRect(context, CGRectMake(0, 0, 1, 1));
|
||||
|
||||
if (rPtr) {
|
||||
*rPtr = pixel[0] / 255.0f;
|
||||
*rPtr = pixel[0] / 255.0;
|
||||
}
|
||||
|
||||
if (gPtr) {
|
||||
*gPtr = pixel[1] / 255.0f;
|
||||
*gPtr = pixel[1] / 255.0;
|
||||
}
|
||||
|
||||
if (bPtr) {
|
||||
*bPtr = pixel[2] / 255.0f;
|
||||
*bPtr = pixel[2] / 255.0;
|
||||
}
|
||||
|
||||
CGContextRelease(context);
|
||||
CGColorSpaceRelease(rgbColorSpace);
|
||||
}
|
||||
|
||||
#elif defined(DD_CLI) || !__has_include(<AppKit/NSColor.h>)
|
||||
#elif defined(DD_CLI) || !__has_include(<AppKit/NSColor.h>)
|
||||
|
||||
// OS X without AppKit
|
||||
|
||||
[color getRed:rPtr green:gPtr blue:bPtr alpha:NULL];
|
||||
|
||||
#else /* if TARGET_OS_IPHONE */
|
||||
#else /* if TARGET_OS_IPHONE */
|
||||
|
||||
// OS X with AppKit
|
||||
|
||||
NSColor *safeColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
|
||||
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 */
|
||||
|
||||
#endif /* if TARGET_OS_IPHONE */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -750,7 +742,7 @@ static DDTTYLogger *sharedInstance;
|
||||
*
|
||||
* 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.
|
||||
* This array index may also be used as the index within the `codesFg` and `codesBg` arrays.
|
||||
**/
|
||||
+ (NSUInteger)codeIndexForColor:(DDColor *)inColor {
|
||||
CGFloat inR, inG, inB;
|
||||
@@ -758,7 +750,7 @@ static DDTTYLogger *sharedInstance;
|
||||
[self getRed:&inR green:&inG blue:&inB fromColor:inColor];
|
||||
|
||||
NSUInteger bestIndex = 0;
|
||||
CGFloat lowestDistance = 100.0f;
|
||||
CGFloat lowestDistance = 100.0;
|
||||
|
||||
NSUInteger i = 0;
|
||||
|
||||
@@ -768,14 +760,14 @@ static DDTTYLogger *sharedInstance;
|
||||
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
|
||||
#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, inR, inG, inB, r, g, b, distance);
|
||||
(unsigned long)i, (double)inR, (double)inG, (double)inB, (double)r, (double)g, (double)b, (double)distance);
|
||||
|
||||
if (distance < lowestDistance) {
|
||||
bestIndex = i;
|
||||
@@ -799,10 +791,10 @@ static DDTTYLogger *sharedInstance;
|
||||
//
|
||||
// PS - Please read the header file before diving into the source code.
|
||||
|
||||
char *xcode_colors = getenv("XcodeColors");
|
||||
char *term = getenv("TERM");
|
||||
__auto_type xcodeColors = getenv("XcodeColors");
|
||||
__auto_type term = getenv("TERM");
|
||||
|
||||
if (xcode_colors && (strcmp(xcode_colors, "YES") == 0)) {
|
||||
if (xcodeColors && (strcmp(xcodeColors, "YES") == 0)) {
|
||||
isaXcodeColorTTY = YES;
|
||||
} else if (term) {
|
||||
if (strcasestr(term, "color") != NULL) {
|
||||
@@ -810,9 +802,9 @@ static DDTTYLogger *sharedInstance;
|
||||
isaColor256TTY = (strcasestr(term, "256") != NULL);
|
||||
|
||||
if (isaColor256TTY) {
|
||||
[self initialize_colors_256];
|
||||
[self initializeColors256];
|
||||
} else {
|
||||
[self initialize_colors_16];
|
||||
[self initializeColors16];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -840,9 +832,7 @@ static DDTTYLogger *sharedInstance;
|
||||
|
||||
if ((self = [super init])) {
|
||||
// Initialize 'app' variable (char *)
|
||||
|
||||
_appName = [[NSProcessInfo processInfo] processName];
|
||||
|
||||
_appLen = [_appName lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
if (_appLen == 0) {
|
||||
@@ -851,14 +841,12 @@ static DDTTYLogger *sharedInstance;
|
||||
}
|
||||
|
||||
_app = (char *)calloc(_appLen + 1, sizeof(char));
|
||||
|
||||
if (_app == NULL) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
BOOL processedAppName = [_appName getCString:_app maxLength:(_appLen + 1) encoding:NSUTF8StringEncoding];
|
||||
|
||||
if (NO == processedAppName) {
|
||||
if (!processedAppName) {
|
||||
free(_app);
|
||||
return nil;
|
||||
}
|
||||
@@ -876,8 +864,7 @@ static DDTTYLogger *sharedInstance;
|
||||
}
|
||||
|
||||
BOOL processedID = [_processID getCString:_pid maxLength:(_pidLen + 1) encoding:NSUTF8StringEncoding];
|
||||
|
||||
if (NO == processedID) {
|
||||
if (!processedID) {
|
||||
free(_app);
|
||||
free(_pid);
|
||||
return nil;
|
||||
@@ -915,14 +902,9 @@ static DDTTYLogger *sharedInstance;
|
||||
// This is the intended result. Fix it by accessing the ivar directly.
|
||||
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
||||
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
||||
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
|
||||
DDAbstractLoggerAssertLockedPropertyAccess();
|
||||
__block BOOL result;
|
||||
|
||||
dispatch_sync(globalLoggingQueue, ^{
|
||||
dispatch_sync(DDLog.loggingQueue, ^{
|
||||
dispatch_sync(self.loggerQueue, ^{
|
||||
result = self->_colorsEnabled;
|
||||
});
|
||||
@@ -932,7 +914,7 @@ static DDTTYLogger *sharedInstance;
|
||||
}
|
||||
|
||||
- (void)setColorsEnabled:(BOOL)newColorsEnabled {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
self->_colorsEnabled = newColorsEnabled;
|
||||
|
||||
@@ -952,12 +934,8 @@ static DDTTYLogger *sharedInstance;
|
||||
// This is the intended result. Fix it by accessing the ivar directly.
|
||||
// Great strides have been take to ensure this is safe to do. Plus it's MUCH faster.
|
||||
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
|
||||
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertLockedPropertyAccess();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
@@ -969,11 +947,11 @@ static DDTTYLogger *sharedInstance;
|
||||
- (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];
|
||||
DDTTYLoggerColorProfile *newColorProfile = [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
|
||||
backgroundColor:bgColor
|
||||
flag:mask
|
||||
context:ctxt];
|
||||
if (!newColorProfile) return;
|
||||
|
||||
NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
|
||||
|
||||
@@ -1001,25 +979,22 @@ static DDTTYLogger *sharedInstance;
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setForegroundColor:(DDColor *)txtColor backgroundColor:(DDColor *)bgColor forTag:(id <NSCopying>)tag {
|
||||
NSAssert([(id < NSObject >) tag conformsToProtocol: @protocol(NSCopying)], @"Invalid tag");
|
||||
NSAssert([(id <NSObject>)tag conformsToProtocol: @protocol(NSCopying)], @"Invalid tag");
|
||||
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
DDTTYLoggerColorProfile *newColorProfile =
|
||||
[[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
|
||||
backgroundColor:bgColor
|
||||
flag:(DDLogFlag)0
|
||||
context:0];
|
||||
__auto_type newColorProfile = [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
|
||||
backgroundColor:bgColor
|
||||
flag:(DDLogFlag)0
|
||||
context:0];
|
||||
|
||||
NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
|
||||
|
||||
@@ -1033,10 +1008,8 @@ static DDTTYLogger *sharedInstance;
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
@@ -1047,7 +1020,7 @@ static DDTTYLogger *sharedInstance;
|
||||
}
|
||||
|
||||
- (void)clearColorsForFlag:(DDLogFlag)mask context:(NSInteger)context {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
NSUInteger i = 0;
|
||||
|
||||
@@ -1071,19 +1044,17 @@ static DDTTYLogger *sharedInstance;
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearColorsForTag:(id <NSCopying>)tag {
|
||||
NSAssert([(id < NSObject >) tag conformsToProtocol: @protocol(NSCopying)], @"Invalid tag");
|
||||
NSAssert([(id <NSObject>) tag conformsToProtocol: @protocol(NSCopying)], @"Invalid tag");
|
||||
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
[self->_colorProfilesDict removeObjectForKey:tag];
|
||||
}
|
||||
@@ -1095,17 +1066,15 @@ static DDTTYLogger *sharedInstance;
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearColorsForAllFlags {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
[self->_colorProfilesArray removeAllObjects];
|
||||
}
|
||||
@@ -1117,17 +1086,15 @@ static DDTTYLogger *sharedInstance;
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearColorsForAllTags {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
[self->_colorProfilesDict removeAllObjects];
|
||||
}
|
||||
@@ -1139,17 +1106,15 @@ static DDTTYLogger *sharedInstance;
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearAllColors {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
[self->_colorProfilesArray removeAllObjects];
|
||||
[self->_colorProfilesDict removeAllObjects];
|
||||
@@ -1162,18 +1127,16 @@ static DDTTYLogger *sharedInstance;
|
||||
if ([self isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_async(globalLoggingQueue, ^{
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue();
|
||||
dispatch_async(DDLog.loggingQueue, ^{
|
||||
dispatch_async(self.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)logMessage:(DDLogMessage *)logMessage {
|
||||
NSString *logMsg = logMessage->_message;
|
||||
BOOL isFormatted = NO;
|
||||
__auto_type logMsg = logMessage->_message;
|
||||
__auto_type isFormatted = NO;
|
||||
|
||||
if (_logFormatter) {
|
||||
logMsg = [_logFormatter formatLogMessage:logMessage];
|
||||
@@ -1217,8 +1180,8 @@ static DDTTYLogger *sharedInstance;
|
||||
// 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);
|
||||
__auto_type msgLen = [logMsg lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
const __auto_type useStack = msgLen < (1024 * 4);
|
||||
|
||||
char *msg;
|
||||
if (useStack) {
|
||||
@@ -1242,8 +1205,12 @@ static DDTTYLogger *sharedInstance;
|
||||
|
||||
if (isFormatted) {
|
||||
// The log message has already been formatted.
|
||||
const int iovec_len = (_automaticallyAppendNewlineForCustomFormatters) ? 5 : 4;
|
||||
struct iovec v[iovec_len];
|
||||
|
||||
// Needs to be a define, because otherwise the compiler warns "Variable length array folded to constant array as an extension"
|
||||
#define DD_TTYLOGGER_MAX_IOVEC_LEN 5
|
||||
|
||||
size_t iovecLen = _automaticallyAppendNewlineForCustomFormatters ? 5 : 4;
|
||||
struct iovec v[DD_TTYLOGGER_MAX_IOVEC_LEN] = { 0 };
|
||||
|
||||
if (colorProfile) {
|
||||
v[0].iov_base = colorProfile->fgCode;
|
||||
@@ -1252,28 +1219,20 @@ static DDTTYLogger *sharedInstance;
|
||||
v[1].iov_base = colorProfile->bgCode;
|
||||
v[1].iov_len = colorProfile->bgCodeLen;
|
||||
|
||||
v[iovec_len - 1].iov_base = colorProfile->resetCode;
|
||||
v[iovec_len - 1].iov_len = colorProfile->resetCodeLen;
|
||||
} else {
|
||||
v[0].iov_base = "";
|
||||
v[0].iov_len = 0;
|
||||
|
||||
v[1].iov_base = "";
|
||||
v[1].iov_len = 0;
|
||||
|
||||
v[iovec_len - 1].iov_base = "";
|
||||
v[iovec_len - 1].iov_len = 0;
|
||||
v[DD_TTYLOGGER_MAX_IOVEC_LEN - 1].iov_base = colorProfile->resetCode;
|
||||
v[DD_TTYLOGGER_MAX_IOVEC_LEN - 1].iov_len = colorProfile->resetCodeLen;
|
||||
}
|
||||
|
||||
v[2].iov_base = msg;
|
||||
v[2].iov_len = msgLen;
|
||||
v[2].iov_len = (msgLen > SIZE_MAX - 1) ? SIZE_MAX - 1 : msgLen;
|
||||
|
||||
if (iovec_len == 5) {
|
||||
if (_automaticallyAppendNewlineForCustomFormatters && (v[2].iov_len == 0 || msg[v[2].iov_len - 1] != '\n')) {
|
||||
v[3].iov_base = "\n";
|
||||
v[3].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
|
||||
v[3].iov_len = 1;
|
||||
iovecLen = 5;
|
||||
}
|
||||
|
||||
writev(STDERR_FILENO, v, iovec_len);
|
||||
writev(STDERR_FILENO, v, (int)iovecLen);
|
||||
} else {
|
||||
// The log message is unformatted, so apply standard NSLog style formatting.
|
||||
|
||||
@@ -1284,13 +1243,15 @@ static DDTTYLogger *sharedInstance;
|
||||
// Calculate timestamp.
|
||||
// The technique below is faster than using NSDateFormatter.
|
||||
if (logMessage->_timestamp) {
|
||||
NSTimeInterval epoch = [logMessage->_timestamp timeIntervalSince1970];
|
||||
__auto_type epoch = [logMessage->_timestamp timeIntervalSince1970];
|
||||
double integral;
|
||||
__auto_type fract = modf(epoch, &integral);
|
||||
struct tm tm;
|
||||
time_t time = (time_t)epoch;
|
||||
__auto_type time = (time_t)integral;
|
||||
(void)localtime_r(&time, &tm);
|
||||
int milliseconds = (int)((epoch - floor(epoch)) * 1000.0);
|
||||
__auto_type milliseconds = (long)(fract * 1000.0);
|
||||
|
||||
len = snprintf(ts, 24, "%04d-%02d-%02d %02d:%02d:%02d:%03d", // yyyy-MM-dd HH:mm:ss:SSS
|
||||
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,
|
||||
@@ -1312,7 +1273,7 @@ static DDTTYLogger *sharedInstance;
|
||||
char tid[9];
|
||||
len = snprintf(tid, 9, "%s", [logMessage->_threadID cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
|
||||
size_t tidLen = (NSUInteger)MAX(MIN(9 - 1, len), 0);
|
||||
__auto_type tidLen = (NSUInteger)MAX(MIN(9 - 1, len), 0);
|
||||
|
||||
// Here is our format: "%s %s[%i:%s] %s", timestamp, appName, processID, threadID, logMsg
|
||||
|
||||
@@ -1379,7 +1340,7 @@ static DDTTYLogger *sharedInstance;
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
|
||||
@implementation DDTTYLoggerColorProfile
|
||||
|
||||
@@ -1393,31 +1354,31 @@ static DDTTYLogger *sharedInstance;
|
||||
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);
|
||||
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 * 255.0f);
|
||||
bg_g = (uint8_t)(g * 255.0f);
|
||||
bg_b = (uint8_t)(b * 255.0f);
|
||||
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 = codes_fg[fgCodeIndex];
|
||||
fgCodeRaw = codesFg[fgCodeIndex];
|
||||
|
||||
NSString *escapeSeq = @"\033[";
|
||||
const __auto_type escapeSeq = @"\033[";
|
||||
|
||||
NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSUInteger len2 = [fgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
__auto_type len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
__auto_type len2 = [fgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
BOOL escapeSeqEnc = [escapeSeq getCString:(fgCode) maxLength:(len1 + 1) encoding: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) {
|
||||
@@ -1427,14 +1388,11 @@ static DDTTYLogger *sharedInstance;
|
||||
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);
|
||||
__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;
|
||||
}
|
||||
@@ -1443,14 +1401,14 @@ static DDTTYLogger *sharedInstance;
|
||||
// Map background color to closest available shell color
|
||||
|
||||
bgCodeIndex = [DDTTYLogger codeIndexForColor:bgColor];
|
||||
bgCodeRaw = codes_bg[bgCodeIndex];
|
||||
bgCodeRaw = codesBg[bgCodeIndex];
|
||||
|
||||
NSString *escapeSeq = @"\033[";
|
||||
const __auto_type escapeSeq = @"\033[";
|
||||
|
||||
NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSUInteger len2 = [bgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
__auto_type len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
__auto_type len2 = [bgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
BOOL escapeSeqEnc = [escapeSeq getCString:(bgCode) maxLength:(len1 + 1) encoding: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) {
|
||||
@@ -1460,14 +1418,11 @@ static DDTTYLogger *sharedInstance;
|
||||
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);
|
||||
__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;
|
||||
}
|
||||
@@ -1488,7 +1443,7 @@ static DDTTYLogger *sharedInstance;
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:
|
||||
@"<DDTTYLoggerColorProfile: %p mask:%i ctxt:%ld fg:%u,%u,%u bg:%u,%u,%u fgCode:%@ bgCode:%@>",
|
||||
self, (int)mask, (long)context, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b, fgCodeRaw, bgCodeRaw];
|
||||
self, (int)mask, (long)context, fg.r, fg.g, fg.b, bg.r, bg.g, bg.b, fgCodeRaw, bgCodeRaw];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -171,7 +171,7 @@
|
||||
}
|
||||
|
||||
- (BOOL)isInSet:(NSInteger)loggingContext {
|
||||
BOOL result = NO;
|
||||
__auto_type result = NO;
|
||||
|
||||
pthread_mutex_lock(&_mutex);
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -134,99 +134,70 @@ static DDQualityOfServiceName _qos_name(NSUInteger qos) {
|
||||
- (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;
|
||||
|
||||
__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.
|
||||
|
||||
NSArray *names = @[
|
||||
const NSArray<NSString *> *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"
|
||||
@"com.apple.root.default-qos.overcommit",
|
||||
];
|
||||
|
||||
for (NSString * name in names) {
|
||||
for (NSString *name in names) {
|
||||
if ([logMessage->_queueLabel isEqualToString:name]) {
|
||||
useQueueLabel = NO;
|
||||
useThreadName = [logMessage->_threadName length] > 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
useQueueLabel = NO;
|
||||
useThreadName = [logMessage->_threadName length] > 0;
|
||||
}
|
||||
|
||||
if (useQueueLabel || useThreadName) {
|
||||
NSString *fullLabel;
|
||||
// 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;
|
||||
|
||||
if (useQueueLabel) {
|
||||
fullLabel = logMessage->_queueLabel;
|
||||
} else {
|
||||
fullLabel = logMessage->_threadName;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_mutex);
|
||||
{
|
||||
abrvLabel = _replacements[fullLabel];
|
||||
}
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
|
||||
if (abrvLabel) {
|
||||
queueThreadLabel = abrvLabel;
|
||||
} else {
|
||||
queueThreadLabel = fullLabel;
|
||||
}
|
||||
queueThreadLabel = abrvLabel ?: fullLabel;
|
||||
} else {
|
||||
queueThreadLabel = logMessage->_threadID;
|
||||
}
|
||||
|
||||
// Now use the thread label in the output
|
||||
|
||||
NSUInteger labelLength = [queueThreadLabel length];
|
||||
|
||||
// labelLength > maxQueueLength : truncate
|
||||
// labelLength < minQueueLength : padding
|
||||
// : exact
|
||||
|
||||
if ((maxQueueLength > 0) && (labelLength > maxQueueLength)) {
|
||||
__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
|
||||
|
||||
NSUInteger numSpaces = minQueueLength - labelLength;
|
||||
|
||||
char spaces[numSpaces + 1];
|
||||
memset(spaces, ' ', numSpaces);
|
||||
spaces[numSpaces] = '\0';
|
||||
|
||||
return [NSString stringWithFormat:@"%@%s", queueThreadLabel, spaces];
|
||||
return [queueThreadLabel stringByPaddingToLength:minQueueLength
|
||||
withString:@" "
|
||||
startingAtIndex:0];
|
||||
} else {
|
||||
// Exact
|
||||
|
||||
return queueThreadLabel;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
|
||||
NSString *timestamp = [self stringFromDate:(logMessage->_timestamp)];
|
||||
NSString *queueThreadLabel = [self queueThreadLabelForLogMessage: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];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -26,11 +26,11 @@ static const NSUInteger kDDMaxBufferSize = 1048576; // ~1 mB, f_iosize on iphone
|
||||
// f_bsize == "default", and f_iosize == "max"
|
||||
static inline NSUInteger p_DDGetDefaultBufferSizeBytesMax(const BOOL max) {
|
||||
struct statfs *mountedFileSystems = NULL;
|
||||
int count = getmntinfo(&mountedFileSystems, 0);
|
||||
__auto_type count = getmntinfo(&mountedFileSystems, 0);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
struct statfs mounted = mountedFileSystems[i];
|
||||
const char *name = mounted.f_mntonname;
|
||||
__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 == '/') {
|
||||
@@ -41,7 +41,7 @@ static inline NSUInteger p_DDGetDefaultBufferSizeBytesMax(const BOOL max) {
|
||||
return max ? kDDMaxBufferSize : kDDDefaultBufferSize;
|
||||
}
|
||||
|
||||
static NSUInteger DDGetMaxBufferSizeBytes() {
|
||||
static NSUInteger DDGetMaxBufferSizeBytes(void) {
|
||||
static NSUInteger maxBufferSize = 0;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
@@ -50,7 +50,7 @@ static NSUInteger DDGetMaxBufferSizeBytes() {
|
||||
return maxBufferSize;
|
||||
}
|
||||
|
||||
static NSUInteger DDGetDefaultBufferSizeBytes() {
|
||||
static NSUInteger DDGetDefaultBufferSizeBytes(void) {
|
||||
static NSUInteger defaultBufferSize = 0;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
@@ -80,7 +80,7 @@ static NSUInteger DDGetDefaultBufferSizeBytes() {
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
[self lt_sendBufferedDataToFileLogger];
|
||||
self.fileLogger = nil;
|
||||
};
|
||||
@@ -111,18 +111,18 @@ static NSUInteger DDGetDefaultBufferSizeBytes() {
|
||||
|
||||
- (void)logMessage:(DDLogMessage *)logMessage {
|
||||
// Don't need to check for isOnInternalLoggerQueue, -lt_dataForMessage: will do it for us.
|
||||
NSData *data = [_fileLogger lt_dataForMessage:logMessage];
|
||||
__auto_type data = [_fileLogger lt_dataForMessage:logMessage];
|
||||
|
||||
if (data.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
[data enumerateByteRangesUsingBlock:^(const void * __nonnull bytes, NSRange byteRange, BOOL * __nonnull __unused stop) {
|
||||
NSUInteger bytesLength = byteRange.length;
|
||||
__auto_type bytesLength = byteRange.length;
|
||||
#ifdef NS_BLOCK_ASSERTIONS
|
||||
__unused
|
||||
#endif
|
||||
NSInteger written = [_buffer write:bytes maxLength:bytesLength];
|
||||
__auto_type written = [_buffer write:bytes maxLength:bytesLength];
|
||||
NSAssert(written > 0 && (NSUInteger)written == bytesLength, @"Failed to write to memory buffer.");
|
||||
|
||||
_currentBufferSizeBytes += bytesLength;
|
||||
@@ -137,7 +137,7 @@ static NSUInteger DDGetDefaultBufferSizeBytes() {
|
||||
// This method is public.
|
||||
// We need to execute the rolling on our logging thread/queue.
|
||||
|
||||
dispatch_block_t block = ^{
|
||||
__auto_type block = ^{
|
||||
@autoreleasepool {
|
||||
[self lt_sendBufferedDataToFileLogger];
|
||||
[self.fileLogger flush];
|
||||
@@ -150,10 +150,8 @@ static NSUInteger DDGetDefaultBufferSizeBytes() {
|
||||
if ([self.fileLogger isOnInternalLoggerQueue]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
|
||||
NSAssert(![self.fileLogger isOnGlobalLoggingQueue], @"Core architecture requirement failure");
|
||||
|
||||
dispatch_sync(globalLoggingQueue, ^{
|
||||
dispatch_sync(DDLog.loggingQueue, ^{
|
||||
dispatch_sync(self.fileLogger.loggerQueue, block);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -45,11 +45,11 @@
|
||||
#pragma mark Processing
|
||||
|
||||
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage {
|
||||
__block NSString *line = logMessage->_message;
|
||||
__block __auto_type line = logMessage->_message;
|
||||
|
||||
dispatch_sync(_queue, ^{
|
||||
for (id<DDLogFormatter> formatter in self->_formatters) {
|
||||
DDLogMessage *message = [self logMessageForLine:line originalMessage:logMessage];
|
||||
__auto_type message = [self logMessageForLine:line originalMessage:logMessage];
|
||||
line = [formatter formatLogMessage:message];
|
||||
|
||||
if (!line) {
|
||||
@@ -63,7 +63,6 @@
|
||||
|
||||
- (DDLogMessage *)logMessageForLine:(NSString *)line originalMessage:(DDLogMessage *)message {
|
||||
DDLogMessage *newMessage = [message copy];
|
||||
|
||||
newMessage->_message = line;
|
||||
return newMessage;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -22,7 +22,7 @@
|
||||
DDLogError(@"%@", description); \
|
||||
NSAssert(NO, @"%@", description); \
|
||||
}
|
||||
#define DDAssertCondition(condition) DDAssert(condition, @"Condition not satisfied: %s", #condition)
|
||||
#define DDAssertCondition(condition) DDAssert(condition, @"Condition not satisfied: %@", @(#condition))
|
||||
|
||||
/**
|
||||
* Analog to `DDAssertionFailure` from DDAssert.swift for use in Objective C
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -48,6 +48,41 @@ 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 <NSObject>
|
||||
@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 <DDFileLogMessageSerializer>
|
||||
|
||||
- (instancetype)init;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@class DDFileLogger;
|
||||
/**
|
||||
* The LogFileManager protocol is designed to allow you to control all aspects of your log files.
|
||||
*
|
||||
@@ -152,30 +187,49 @@ extern unsigned long long const kDDDefaultLogFilesDiskQuota;
|
||||
|
||||
@optional
|
||||
|
||||
// Private methods (only to be used by DDFileLogger)
|
||||
/**
|
||||
* 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:");
|
||||
/// The log message serializer.
|
||||
@property (nonatomic, readonly, strong) id<DDFileLogMessageSerializer> logMessageSerializer;
|
||||
|
||||
// Notifications from DDFileLogger
|
||||
/// The file manager to use. Defaults to `[NSFileManager defaultManager]`.
|
||||
@property (nonatomic, readonly, strong) NSFileManager *fileManager;
|
||||
|
||||
/// Whether the log file should be locked by the file logger before writing to it (and unlocked after).
|
||||
/// - Parameter logFilePath: The path to the log file for which to decide locking.
|
||||
/// - Remark: Logging from multiple processes (e.g. an app extensions) to the same log file without file locking will result in interleaved and possibly even overwritten log messages.
|
||||
/// Without locking, the resulting logfile could be described as "best effort" and might become corrupted.
|
||||
/// The downside of locking is that if the process holds the file lock when it gets suspended by the system, the system will kill the process.
|
||||
/// This could happen by inproper handling of app suspension (e.g. not properly calling `+[DDLog flushLog]` and waiting for its completion before suspension).
|
||||
/// Regardless of locking, you should always call `+[DDLog flushLog]` before your app gets suspended or terminated to make sure every log message makes it to your disk.
|
||||
- (BOOL)shouldLockLogFile:(NSString *)logFilePath;
|
||||
|
||||
/// 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:));
|
||||
|
||||
// Deprecated APIs
|
||||
/**
|
||||
* Called when a log file was archived. Executed on global queue with default priority.
|
||||
*/
|
||||
// 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.
|
||||
*/
|
||||
/// 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
|
||||
@@ -199,11 +253,6 @@ extern unsigned long long const kDDDefaultLogFilesDiskQuota;
|
||||
**/
|
||||
@interface DDLogFileManagerDefault : NSObject <DDLogFileManager>
|
||||
|
||||
/**
|
||||
* Default initializer
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
* If logDirectory is not specified, then a folder called "Logs" is created in the app's cache directory.
|
||||
* While running on the simulator, the "Logs" folder is located in the library temporary directory.
|
||||
@@ -226,6 +275,9 @@ extern unsigned long long const kDDDefaultLogFilesDiskQuota;
|
||||
defaultFileProtectionLevel:(NSFileProtectionType)fileProtectionLevel;
|
||||
#endif
|
||||
|
||||
/// Convenience initializer.
|
||||
- (instancetype)init;
|
||||
|
||||
/*
|
||||
* Methods to override.
|
||||
*
|
||||
@@ -276,6 +328,12 @@ extern unsigned long long const kDDDefaultLogFilesDiskQuota;
|
||||
**/
|
||||
@property (readonly, copy, nullable) NSString *logFileHeader;
|
||||
|
||||
/// The log message serializer.
|
||||
@property (nonatomic, strong) id<DDFileLogMessageSerializer> logMessageSerializer;
|
||||
|
||||
/// The file manager to use. Defaults to `[NSFileManager defaultManager]`.
|
||||
@property (nonatomic, strong) NSFileManager *fileManager;
|
||||
|
||||
/* Inherited from DDLogFileManager protocol:
|
||||
|
||||
@property (readwrite, assign, atomic) NSUInteger maximumNumberOfLogFiles;
|
||||
@@ -310,16 +368,12 @@ extern unsigned long long const kDDDefaultLogFilesDiskQuota;
|
||||
**/
|
||||
@interface DDLogFileFormatterDefault : NSObject <DDLogFormatter>
|
||||
|
||||
/**
|
||||
* Default initializer
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
* Designated initializer, requires a date formatter
|
||||
*/
|
||||
/// Designated initializer, requires a date formatter
|
||||
- (instancetype)initWithDateFormatter:(nullable NSDateFormatter *)dateFormatter NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/// Convenience initializer
|
||||
- (instancetype)init;
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -507,12 +561,18 @@ extern unsigned long long const kDDDefaultLogFilesDiskQuota;
|
||||
|
||||
@property (nonatomic, readonly) NSTimeInterval age;
|
||||
|
||||
@property (nonatomic, readonly) BOOL isSymlink;
|
||||
|
||||
@property (nonatomic, readwrite) BOOL isArchived;
|
||||
|
||||
+ (nullable instancetype)logFileWithPath:(nullable NSString *)filePath NS_SWIFT_UNAVAILABLE("Use init(filePath:)");
|
||||
+ (nullable instancetype)logFileWithPath:(nullable NSString *)filePath
|
||||
__attribute__((deprecated("Check file path for nil and pass it to the initializer instead")))
|
||||
NS_SWIFT_UNAVAILABLE("Use init(filePath:)");
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath NS_DESIGNATED_INITIALIZER;
|
||||
// TODO: This should really become the designated initializer.
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath fileManager:(NSFileManager *)fileManager;
|
||||
|
||||
- (void)reset;
|
||||
- (void)renameFile:(NSString *)newFileName NS_SWIFT_NAME(renameFile(to:));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -207,6 +207,20 @@ FOUNDATION_EXTERN NSString * __nullable DDExtractFileNameWithoutExtension(const
|
||||
**/
|
||||
#define THIS_METHOD NSStringFromSelector(_cmd)
|
||||
|
||||
/**
|
||||
* Makes a declaration "Sendable" in Swift (if supported by the compiler).
|
||||
*/
|
||||
#ifndef DD_SENDABLE
|
||||
#ifdef __has_attribute
|
||||
#if __has_attribute(swift_attr)
|
||||
#define DD_SENDABLE __attribute__((swift_attr("@Sendable")))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifndef DD_SENDABLE
|
||||
#define DD_SENDABLE
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
@@ -216,6 +230,7 @@ FOUNDATION_EXTERN NSString * __nullable DDExtractFileNameWithoutExtension(const
|
||||
* The main class, exposes all logging mechanisms, loggers, ...
|
||||
* For most of the users, this class is hidden behind the logging functions like `DDLogInfo`
|
||||
*/
|
||||
DD_SENDABLE
|
||||
@interface DDLog : NSObject
|
||||
|
||||
/**
|
||||
@@ -770,11 +785,13 @@ typedef NS_OPTIONS(NSInteger, DDLogMessageOptions){
|
||||
* 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.
|
||||
**/
|
||||
DD_SENDABLE
|
||||
@interface DDLogMessage : NSObject <NSCopying>
|
||||
{
|
||||
// Direct accessors to be used only for performance
|
||||
@public
|
||||
NSString *_message;
|
||||
NSString *_messageFormat;
|
||||
DDLogLevel _level;
|
||||
DDLogFlag _flag;
|
||||
NSInteger _context;
|
||||
@@ -782,9 +799,9 @@ typedef NS_OPTIONS(NSInteger, DDLogMessageOptions){
|
||||
NSString *_fileName;
|
||||
NSString *_function;
|
||||
NSUInteger _line;
|
||||
#if DD_LEGACY_MESSAGE_TAG
|
||||
id _tag __attribute__((deprecated("Use _representedObject instead", "_representedObject")));;
|
||||
#endif
|
||||
#if DD_LEGACY_MESSAGE_TAG
|
||||
id _tag __attribute__((deprecated("Use _representedObject instead", "_representedObject")));
|
||||
#endif
|
||||
id _representedObject;
|
||||
DDLogMessageOptions _options;
|
||||
NSDate * _timestamp;
|
||||
@@ -813,6 +830,64 @@ typedef NS_OPTIONS(NSInteger, DDLogMessageOptions){
|
||||
* 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.
|
||||
*
|
||||
* @param messageFormat the message format
|
||||
* @param message the formatted message
|
||||
* @param level the log level
|
||||
* @param flag the log flag
|
||||
* @param context the context (if any is defined)
|
||||
* @param file the current file
|
||||
* @param function the current function
|
||||
* @param line the current code line
|
||||
* @param tag potential tag
|
||||
* @param options a bitmask which supports DDLogMessageCopyFile and DDLogMessageCopyFunction.
|
||||
* @param timestamp the log timestamp
|
||||
*
|
||||
* @return a new instance of a log message model object
|
||||
*/
|
||||
- (instancetype)initWithFormat:(NSString *)messageFormat
|
||||
formatted:(NSString *)message
|
||||
level:(DDLogLevel)level
|
||||
flag:(DDLogFlag)flag
|
||||
context:(NSInteger)context
|
||||
file:(NSString *)file
|
||||
function:(nullable NSString *)function
|
||||
line:(NSUInteger)line
|
||||
tag:(nullable id)tag
|
||||
options:(DDLogMessageOptions)options
|
||||
timestamp:(nullable NSDate *)timestamp NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Convenience initializer taking a `va_list` as arguments to create the formatted message.
|
||||
*
|
||||
* @param messageFormat the message format
|
||||
* @param messageArgs the message arguments.
|
||||
* @param level the log level
|
||||
* @param flag the log flag
|
||||
* @param context the context (if any is defined)
|
||||
* @param file the current file
|
||||
* @param function the current function
|
||||
* @param line the current code line
|
||||
* @param tag potential tag
|
||||
* @param options a bitmask which supports DDLogMessageCopyFile and DDLogMessageCopyFunction.
|
||||
* @param timestamp the log timestamp
|
||||
*
|
||||
* @return a new instance of a log message model object
|
||||
*/
|
||||
- (instancetype)initWithFormat:(NSString *)messageFormat
|
||||
args:(va_list)messageArgs
|
||||
level:(DDLogLevel)level
|
||||
flag:(DDLogFlag)flag
|
||||
context:(NSInteger)context
|
||||
file:(NSString *)file
|
||||
function:(nullable NSString *)function
|
||||
line:(NSUInteger)line
|
||||
tag:(nullable id)tag
|
||||
options:(DDLogMessageOptions)options
|
||||
timestamp:(nullable NSDate *)timestamp;
|
||||
|
||||
/**
|
||||
* Deprecated initialier. See initWithFormat:args:formatted:level:flag:context:file:function:line:tag:options:timestamp:.
|
||||
*
|
||||
* @param message the message
|
||||
* @param level the log level
|
||||
* @param flag the log flag
|
||||
@@ -835,16 +910,21 @@ typedef NS_OPTIONS(NSInteger, DDLogMessageOptions){
|
||||
line:(NSUInteger)line
|
||||
tag:(nullable id)tag
|
||||
options:(DDLogMessageOptions)options
|
||||
timestamp:(nullable NSDate *)timestamp NS_DESIGNATED_INITIALIZER;
|
||||
timestamp:(nullable NSDate *)timestamp
|
||||
__attribute__((deprecated("Use initializer taking unformatted message and args instead", "initWithFormat:formatted:level:flag:context:file:function:line:tag:options:timestamp:")));
|
||||
|
||||
/**
|
||||
* Read-only properties
|
||||
**/
|
||||
|
||||
/**
|
||||
* The log message
|
||||
* The log message.
|
||||
*/
|
||||
@property (readonly, nonatomic) NSString *message;
|
||||
/**
|
||||
* The message format. When the deprecated initializer is used, this might be the same as `message`.
|
||||
*/
|
||||
@property (readonly, nonatomic) NSString *messageFormat;
|
||||
@property (readonly, nonatomic) DDLogLevel level;
|
||||
@property (readonly, nonatomic) DDLogFlag flag;
|
||||
@property (readonly, nonatomic) NSInteger context;
|
||||
@@ -889,7 +969,7 @@ typedef NS_OPTIONS(NSInteger, DDLogMessageOptions){
|
||||
{
|
||||
// Direct accessors to be used only for performance
|
||||
@public
|
||||
id <DDLogFormatter> _logFormatter;
|
||||
_Nullable id <DDLogFormatter> _logFormatter;
|
||||
dispatch_queue_t _loggerQueue;
|
||||
}
|
||||
|
||||
@@ -901,7 +981,7 @@ typedef NS_OPTIONS(NSInteger, DDLogMessageOptions){
|
||||
/**
|
||||
* Return YES if the current logger uses a global queue for logging
|
||||
*/
|
||||
@property (nonatomic, readonly, getter=isOnGlobalLoggingQueue) BOOL onGlobalLoggingQueue;
|
||||
@property (nonatomic, readonly, getter=isOnGlobalLoggingQueue) BOOL onGlobalLoggingQueue;
|
||||
|
||||
/**
|
||||
* Return YES if the current logger uses the internal designated queue for logging
|
||||
@@ -910,10 +990,27 @@ typedef NS_OPTIONS(NSInteger, DDLogMessageOptions){
|
||||
|
||||
@end
|
||||
|
||||
#define _DDAbstractLoggerSelectorMessage(msg) [NSStringFromSelector(_cmd) stringByAppendingString:@" " msg]
|
||||
// Note: we do not wrap these in any do {...} while 0 construct, because NSAssert does that for us.
|
||||
#define DDAbstractLoggerAssertOnGlobalLoggingQueue() \
|
||||
NSAssert([self isOnGlobalLoggingQueue], _DDAbstractLoggerSelectorMessage("must only be called on the global logging queue!"))
|
||||
#define DDAbstractLoggerAssertOnInternalLoggerQueue() \
|
||||
NSAssert([self isOnInternalLoggerQueue], _DDAbstractLoggerSelectorMessage("must only be called on the internal logger queue!"))
|
||||
#define DDAbstractLoggerAssertNotOnGlobalLoggingQueue() \
|
||||
NSAssert(![self isOnGlobalLoggingQueue], _DDAbstractLoggerSelectorMessage("must not be called on the global logging queue!"))
|
||||
#define DDAbstractLoggerAssertNotOnInternalLoggerQueue() \
|
||||
NSAssert(![self isOnGlobalLoggingQueue], _DDAbstractLoggerSelectorMessage("must not be called on the internal logger queue!"))
|
||||
|
||||
#define DDAbstractLoggerAssertLockedPropertyAccess() \
|
||||
DDAbstractLoggerAssertNotOnGlobalLoggingQueue(); \
|
||||
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.")
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DD_SENDABLE
|
||||
@interface DDLoggerInformation : NSObject
|
||||
|
||||
@property (nonatomic, readonly) id <DDLogger> logger;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -80,10 +80,10 @@
|
||||
* We also define shorthand versions for asynchronous and synchronous logging.
|
||||
**/
|
||||
#define LOG_MAYBE(async, lvl, flg, ctx, tag, fnct, frmt, ...) \
|
||||
do { if((lvl & flg) != 0) LOG_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0)
|
||||
do { if(((NSUInteger)lvl & (NSUInteger)flg) != 0) LOG_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0)
|
||||
|
||||
#define LOG_MAYBE_TO_DDLOG(ddlog, async, lvl, flg, ctx, tag, fnct, frmt, ...) \
|
||||
do { if((lvl & flg) != 0) LOG_MACRO_TO_DDLOG(ddlog, async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0)
|
||||
do { if(((NSUInteger)lvl & (NSUInteger)flg) != 0) LOG_MACRO_TO_DDLOG(ddlog, async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0)
|
||||
|
||||
/**
|
||||
* Ready to use log macros with no context or tag.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -13,7 +13,9 @@
|
||||
// to endorse or promote products derived from this software without specific
|
||||
// prior written permission of Deusty, LLC.
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <os/log.h>
|
||||
|
||||
// Disable legacy macros
|
||||
#ifndef DD_LEGACY_MACROS
|
||||
@@ -24,31 +26,79 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* This class provides a logger for the Apple os_log facility.
|
||||
**/
|
||||
/// Describes a type that maps CocoaLumberjack log levels to os\_log levels (`os_log_type_t`).
|
||||
API_AVAILABLE(macos(10.12), ios(10.0), watchos(3.0), tvos(10.0))
|
||||
DD_SENDABLE
|
||||
@protocol DDOSLogLevelMapper <NSObject>
|
||||
|
||||
/// Maps the given `DDLogFlag` to a `os_log_type_t`.
|
||||
/// - Parameter logFlag: `DDLogFlag` for which to return the os log type.
|
||||
- (os_log_type_t)osLogTypeForLogFlag:(DDLogFlag)logFlag;
|
||||
|
||||
@end
|
||||
|
||||
/// The default os\_log level mapper.
|
||||
/// Uses the following mapping:
|
||||
/// - `DDLogFlagError` -> `OS_LOG_TYPE_ERROR`
|
||||
/// - `DDLogFlagWarning` -> `OS_LOG_TYPE_ERROR`
|
||||
/// - `DDLogFlagInfo` -> `OS_LOG_TYPE_INFO`
|
||||
/// - `DDLogFlagDebug` -> `OS_LOG_TYPE_DEBUG`
|
||||
/// - `DDLogFlagVerbose` -> `OS_LOG_TYPE_DEBUG`
|
||||
API_AVAILABLE(macos(10.12), ios(10.0), watchos(3.0), tvos(10.0))
|
||||
DD_SENDABLE
|
||||
@interface DDOSLogLevelMapperDefault : NSObject <DDOSLogLevelMapper>
|
||||
|
||||
- (instancetype)init NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
#if TARGET_OS_SIMULATOR
|
||||
/// An os\_log level mapper that works around the fact that `OS_LOG_TYPE_DEBUG` messages logged in the simulator do not show up in the Console.app.
|
||||
/// Performs the same mapping as ``DDOSLogLevelMapperDefault``, except that `OS_LOG_TYPE_DEBUG` is raised to `OS_LOG_TYPE_DEFAULT`.
|
||||
/// See [this thread](https://developer.apple.com/forums/thread/82736?answerId=761544022#761544022) in the Apple Developer Forums.
|
||||
API_AVAILABLE(macos(10.12), ios(10.0), watchos(3.0), tvos(10.0))
|
||||
DD_SENDABLE
|
||||
@interface DDOSLogLevelMapperSimulatorConsoleAppWorkaround : DDOSLogLevelMapperDefault
|
||||
@end
|
||||
#endif
|
||||
|
||||
/// This class provides a logger for the Apple os\_log facility.
|
||||
API_AVAILABLE(macos(10.12), ios(10.0), watchos(3.0), tvos(10.0))
|
||||
DD_SENDABLE
|
||||
@interface DDOSLogger : DDAbstractLogger <DDLogger>
|
||||
|
||||
/**
|
||||
* Singleton method
|
||||
*
|
||||
* @return the shared instance with OS_LOG_DEFAULT.
|
||||
*/
|
||||
/// The shared instance using `OS_LOG_DEFAULT`.
|
||||
@property (nonatomic, class, readonly, strong) DDOSLogger *sharedInstance;
|
||||
|
||||
/**
|
||||
Designated initializer
|
||||
|
||||
@param subsystem Desired subsystem in log. E.g. "org.example"
|
||||
@param category Desired category in log. E.g. "Point of interests."
|
||||
@return New instance of DDOSLogger.
|
||||
|
||||
@discussion This method requires either both or no parameter to be set. Much like `(String, String)?` in Swift.
|
||||
If both parameters are nil, this method will return a logger configured with `OS_LOG_DEFAULT`.
|
||||
If both parameters are non-nil, it will return a logger configured with `os_log_create(subsystem, category)`
|
||||
*/
|
||||
- (instancetype)initWithSubsystem:(nullable NSString *)subsystem category:(nullable NSString *)category NS_DESIGNATED_INITIALIZER;
|
||||
/// The log level mapper, that maps ``DDLogFlag``s to ``os_log_type_t`` for this logger.
|
||||
@property (nonatomic, strong, readonly) id<DDOSLogLevelMapper> logLevelMapper;
|
||||
|
||||
/// An initializer that in addition to subsystem and category also allows providing the log level mapper.
|
||||
/// @param subsystem Desired subsystem in log. E.g. "org.example"
|
||||
/// @param category Desired category in log. E.g. "Point of interests."
|
||||
/// @param logLevelMapper The log level mapper to use.
|
||||
/// @discussion This method requires either both or no parameter to be set. Much like `(String, String)?` in Swift.
|
||||
/// If both parameters are nil, this method will return a logger configured with `OS_LOG_DEFAULT`.
|
||||
/// If both parameters are non-nil, it will return a logger configured with `os_log_create(subsystem, category)`
|
||||
- (instancetype)initWithSubsystem:(nullable NSString *)subsystem
|
||||
category:(nullable NSString *)category
|
||||
logLevelMapper:(id<DDOSLogLevelMapper>)logLevelMapper NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/// The designated initializer, using `DDOSLogLevelMapperDefault`.
|
||||
/// @param subsystem Desired subsystem in log. E.g. "org.example"
|
||||
/// @param category Desired category in log. E.g. "Point of interests."
|
||||
/// @discussion This method requires either both or no parameter to be set. Much like `(String, String)?` in Swift.
|
||||
/// If both parameters are nil, this method will return a logger configured with `OS_LOG_DEFAULT`.
|
||||
/// If both parameters are non-nil, it will return a logger configured with `os_log_create(subsystem, category)`.
|
||||
- (instancetype)initWithSubsystem:(nullable NSString *)subsystem
|
||||
category:(nullable NSString *)category;
|
||||
|
||||
/// Creates an instance that uses `OS_LOG_DEFAULT`.
|
||||
/// @param logLevelMapper The log level mapper to use.
|
||||
- (instancetype)initWithLogLevelMapper:(id<DDOSLogLevelMapper>)logLevelMapper;
|
||||
|
||||
/// Creates an instance that uses `OS_LOG_DEFAULT` and `DDOSLogLevelMapperDefault`.
|
||||
- (instancetype)init;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -28,17 +28,17 @@
|
||||
// iOS or tvOS or watchOS
|
||||
#import <UIKit/UIColor.h>
|
||||
typedef UIColor DDColor;
|
||||
static inline DDColor* _Nonnull DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];}
|
||||
static inline DDColor* _Nonnull DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithRed:(r/(CGFloat)255.0) green:(g/(CGFloat)255.0) blue:(b/(CGFloat)255.0) alpha:1.0];}
|
||||
#elif defined(DD_CLI) || !__has_include(<AppKit/NSColor.h>)
|
||||
// OS X CLI
|
||||
#import <CocoaLumberjack/CLIColor.h>
|
||||
typedef CLIColor DDColor;
|
||||
static inline DDColor* _Nonnull DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];}
|
||||
static inline DDColor* _Nonnull DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithCalibratedRed:(r/255.0) green:(g/255.0) blue:(b/255.0) alpha:1.0];}
|
||||
#else
|
||||
// OS X with AppKit
|
||||
#import <AppKit/NSColor.h>
|
||||
typedef NSColor DDColor;
|
||||
static inline DDColor * _Nonnull DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f];}
|
||||
static inline DDColor * _Nonnull DDMakeColor(CGFloat r, CGFloat g, CGFloat b) {return [DDColor colorWithCalibratedRed:(r/255.0) green:(g/255.0) blue:(b/255.0) alpha:1.0];}
|
||||
#endif
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -13,71 +13,164 @@
|
||||
// to endorse or promote products derived from this software without specific
|
||||
// prior written permission of Deusty, LLC.
|
||||
|
||||
@_exported import CocoaLumberjack
|
||||
@_exported public import CocoaLumberjack
|
||||
#if SWIFT_PACKAGE
|
||||
import CocoaLumberjackSwiftSupport
|
||||
public import CocoaLumberjackSwiftSupport
|
||||
#endif
|
||||
|
||||
extension DDLogFlag {
|
||||
public static func from(_ logLevel: DDLogLevel) -> DDLogFlag {
|
||||
return DDLogFlag(rawValue: logLevel.rawValue)
|
||||
}
|
||||
|
||||
public init(_ logLevel: DDLogLevel) {
|
||||
self = DDLogFlag(rawValue: logLevel.rawValue)
|
||||
}
|
||||
|
||||
/// Returns the log level, or the lowest equivalent.
|
||||
public func toLogLevel() -> DDLogLevel {
|
||||
if let ourValid = DDLogLevel(rawValue: rawValue) {
|
||||
return ourValid
|
||||
} else {
|
||||
if contains(.verbose) {
|
||||
return .verbose
|
||||
} else if contains(.debug) {
|
||||
return .debug
|
||||
} else if contains(.info) {
|
||||
return .info
|
||||
} else if contains(.warning) {
|
||||
return .warning
|
||||
} else if contains(.error) {
|
||||
return .error
|
||||
} else {
|
||||
return .off
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The log level that can dynamically limit log messages (vs. the static DDDefaultLogLevel). This log level will only be checked, if the message passes the `DDDefaultLogLevel`.
|
||||
public var dynamicLogLevel = DDLogLevel.all
|
||||
|
||||
/// Resets the `dynamicLogLevel` to `.all`.
|
||||
/// - SeeAlso: `dynamicLogLevel`
|
||||
@inlinable
|
||||
public func resetDynamicLogLevel() {
|
||||
dynamicLogLevel = .all
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Please use dynamicLogLevel", renamed: "dynamicLogLevel")
|
||||
public var defaultDebugLevel: DDLogLevel {
|
||||
get {
|
||||
return dynamicLogLevel
|
||||
public func _DDLogMessage(_ messageFormat: @autoclosure () -> DDLogMessageFormat,
|
||||
level: DDLogLevel,
|
||||
flag: DDLogFlag,
|
||||
context: Int,
|
||||
file: StaticString,
|
||||
function: StaticString,
|
||||
line: UInt,
|
||||
tag: Any?,
|
||||
asynchronous: Bool?,
|
||||
ddlog: DDLog) {
|
||||
// The `dynamicLogLevel` will always be checked here (instead of being passed in).
|
||||
// We cannot "mix" it with the `DDDefaultLogLevel`, because otherwise the compiler won't strip strings that are not logged.
|
||||
#if compiler(>=6.2)
|
||||
if unsafe level.rawValue & flag.rawValue != 0 && dynamicLogLevel.rawValue & flag.rawValue != 0 {
|
||||
let logMessage = DDLogMessage(messageFormat(),
|
||||
level: level,
|
||||
flag: flag,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag)
|
||||
unsafe ddlog.log(asynchronous: asynchronous ?? asyncLoggingEnabled, message: logMessage)
|
||||
}
|
||||
set {
|
||||
dynamicLogLevel = newValue
|
||||
#else
|
||||
if level.rawValue & flag.rawValue != 0 && dynamicLogLevel.rawValue & flag.rawValue != 0 {
|
||||
let logMessage = DDLogMessage(messageFormat(),
|
||||
level: level,
|
||||
flag: flag,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag)
|
||||
ddlog.log(asynchronous: asynchronous ?? asyncLoggingEnabled, message: logMessage)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Please use resetDynamicLogLevel", renamed: "resetDynamicLogLevel")
|
||||
public func resetDefaultDebugLevel() {
|
||||
resetDynamicLogLevel()
|
||||
}
|
||||
|
||||
/// If `true`, all logs (except errors) are logged asynchronously by default.
|
||||
public var asyncLoggingEnabled = true
|
||||
|
||||
@inlinable
|
||||
public func DDLogDebug(_ message: @autoclosure () -> DDLogMessageFormat,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
file: StaticString = #file,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .debug,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: asynchronous,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func DDLogInfo(_ message: @autoclosure () -> DDLogMessageFormat,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
file: StaticString = #file,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .info,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: asynchronous,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func DDLogWarn(_ message: @autoclosure () -> DDLogMessageFormat,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
file: StaticString = #file,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .warning,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: asynchronous,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func DDLogVerbose(_ message: @autoclosure () -> DDLogMessageFormat,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
file: StaticString = #file,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .verbose,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: asynchronous,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func DDLogError(_ message: @autoclosure () -> DDLogMessageFormat,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
file: StaticString = #file,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .error,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: asynchronous ?? false,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use an interpolated DDLogMessageFormat instead")
|
||||
@inlinable
|
||||
@_disfavoredOverload
|
||||
public func _DDLogMessage(_ message: @autoclosure () -> Any,
|
||||
level: DDLogLevel,
|
||||
flag: DDLogFlag,
|
||||
@@ -86,27 +179,25 @@ public func _DDLogMessage(_ message: @autoclosure () -> Any,
|
||||
function: StaticString,
|
||||
line: UInt,
|
||||
tag: Any?,
|
||||
asynchronous: Bool,
|
||||
asynchronous: Bool?,
|
||||
ddlog: DDLog) {
|
||||
// The `dynamicLogLevel` will always be checked here (instead of being passed in).
|
||||
// We cannot "mix" it with the `DDDefaultLogLevel`, because otherwise the compiler won't strip strings that are not logged.
|
||||
if level.rawValue & flag.rawValue != 0 && dynamicLogLevel.rawValue & flag.rawValue != 0 {
|
||||
// Tell the DDLogMessage constructor to copy the C strings that get passed to it.
|
||||
let logMessage = DDLogMessage(message: String(describing: message()),
|
||||
level: level,
|
||||
flag: flag,
|
||||
context: context,
|
||||
file: String(describing: file),
|
||||
function: String(describing: function),
|
||||
line: line,
|
||||
tag: tag,
|
||||
options: [.copyFile, .copyFunction],
|
||||
timestamp: nil)
|
||||
ddlog.log(asynchronous: asynchronous, message: logMessage)
|
||||
}
|
||||
// This will lead to `messageFormat` and `message` being equal on DDLogMessage,
|
||||
// which is what the legacy initializer of DDLogMessage does as well.
|
||||
_DDLogMessage(.init(_formattedMessage: String(describing: message())),
|
||||
level: level,
|
||||
flag: flag,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: asynchronous,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use an interpolated DDLogMessageFormat instead")
|
||||
@inlinable
|
||||
@_disfavoredOverload
|
||||
public func DDLogDebug(_ message: @autoclosure () -> Any,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
@@ -114,12 +205,23 @@ public func DDLogDebug(_ message: @autoclosure () -> Any,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous async: Bool = asyncLoggingEnabled,
|
||||
asynchronous async: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(), level: level, flag: .debug, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .debug,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: async,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use an interpolated DDLogMessageFormat instead")
|
||||
@inlinable
|
||||
@_disfavoredOverload
|
||||
public func DDLogInfo(_ message: @autoclosure () -> Any,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
@@ -127,12 +229,23 @@ public func DDLogInfo(_ message: @autoclosure () -> Any,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous async: Bool = asyncLoggingEnabled,
|
||||
asynchronous async: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(), level: level, flag: .info, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .info,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: async,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use an interpolated DDLogMessageFormat instead")
|
||||
@inlinable
|
||||
@_disfavoredOverload
|
||||
public func DDLogWarn(_ message: @autoclosure () -> Any,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
@@ -140,12 +253,23 @@ public func DDLogWarn(_ message: @autoclosure () -> Any,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous async: Bool = asyncLoggingEnabled,
|
||||
asynchronous async: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(), level: level, flag: .warning, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .warning,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: async,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use an interpolated DDLogMessageFormat instead")
|
||||
@inlinable
|
||||
@_disfavoredOverload
|
||||
public func DDLogVerbose(_ message: @autoclosure () -> Any,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
@@ -153,12 +277,23 @@ public func DDLogVerbose(_ message: @autoclosure () -> Any,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous async: Bool = asyncLoggingEnabled,
|
||||
asynchronous async: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(), level: level, flag: .verbose, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .verbose,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: async,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "Use an interpolated DDLogMessageFormat instead")
|
||||
@inlinable
|
||||
@_disfavoredOverload
|
||||
public func DDLogError(_ message: @autoclosure () -> Any,
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
@@ -166,28 +301,16 @@ public func DDLogError(_ message: @autoclosure () -> Any,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous async: Bool = false,
|
||||
asynchronous async: Bool? = nil,
|
||||
ddlog: DDLog = .sharedInstance) {
|
||||
_DDLogMessage(message(), level: level, flag: .error, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
|
||||
}
|
||||
|
||||
/// Returns a String of the current filename, without full path or extension.
|
||||
///
|
||||
/// Analogous to the C preprocessor macro `THIS_FILE`.
|
||||
public func currentFileName(_ fileName: StaticString = #file) -> String {
|
||||
var str = String(describing: fileName)
|
||||
if let idx = str.range(of: "/", options: .backwards)?.upperBound {
|
||||
str = String(str[idx...])
|
||||
}
|
||||
if let idx = str.range(of: ".", options: .backwards)?.lowerBound {
|
||||
str = String(str[..<idx])
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// swiftlint:disable identifier_name
|
||||
// swiftlint doesn't like func names that begin with a capital letter - deprecated
|
||||
@available(*, deprecated, message: "Please use currentFileName", renamed: "currentFileName")
|
||||
public func CurrentFileName(_ fileName: StaticString = #file) -> String {
|
||||
return currentFileName(fileName)
|
||||
_DDLogMessage(message(),
|
||||
level: level,
|
||||
flag: .error,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: async ?? false,
|
||||
ddlog: ddlog)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -14,8 +14,8 @@
|
||||
// prior written permission of Deusty, LLC.
|
||||
|
||||
#if SWIFT_PACKAGE
|
||||
import CocoaLumberjack
|
||||
import CocoaLumberjackSwiftSupport
|
||||
public import CocoaLumberjack
|
||||
public import CocoaLumberjackSwiftSupport
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -29,9 +29,91 @@ import CocoaLumberjackSwiftSupport
|
||||
* The default is an empty string.
|
||||
*/
|
||||
@inlinable
|
||||
public func DDAssert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = "", level: DDLogLevel = DDDefaultLogLevel, context: Int = 0, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, tag: Any? = nil, asynchronous async: Bool = false, ddlog: DDLog = DDLog.sharedInstance) {
|
||||
public func DDAssert(_ condition: @autoclosure () -> Bool,
|
||||
_ message: @autoclosure () -> DDLogMessageFormat = "",
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
file: StaticString = #file,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous async: Bool? = nil,
|
||||
ddlog: DDLog = DDLog.sharedInstance) {
|
||||
if !condition() {
|
||||
DDLogError(message(), level: level, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
|
||||
DDLogError(message(),
|
||||
level: level,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: async,
|
||||
ddlog: ddlog)
|
||||
Swift.assertionFailure(message().formatted, file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for Swift's `assertionFailure` function that will output a log message even
|
||||
* when assertions are disabled.
|
||||
*
|
||||
* - Parameters:
|
||||
* - message: A string to log (using `DDLogError`). The default is an empty string.
|
||||
*/
|
||||
@inlinable
|
||||
public func DDAssertionFailure(_ message: @autoclosure () -> DDLogMessageFormat = "",
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
file: StaticString = #file,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous async: Bool? = nil,
|
||||
ddlog: DDLog = DDLog.sharedInstance) {
|
||||
DDLogError(message(),
|
||||
level: level,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: async,
|
||||
ddlog: ddlog)
|
||||
Swift.assertionFailure(message().formatted, file: file, line: line)
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for Swift's `assert` function that will output a log message even when assertions
|
||||
* are disabled.
|
||||
*
|
||||
* - Parameters:
|
||||
* - condition: The condition to test. Unlike `Swift.assert`, `condition` is always evaluated,
|
||||
* even when assertions are disabled.
|
||||
* - message: A string to log (using `DDLogError`) if `condition` evaluates to `false`.
|
||||
* The default is an empty string.
|
||||
*/
|
||||
@inlinable
|
||||
@available(*, deprecated, message: "Use an interpolated message.")
|
||||
public func DDAssert(_ condition: @autoclosure () -> Bool,
|
||||
_ message: @autoclosure () -> String = "",
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
file: StaticString = #file,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous async: Bool? = nil,
|
||||
ddlog: DDLog = DDLog.sharedInstance) {
|
||||
if !condition() {
|
||||
DDLogError(message(),
|
||||
level: level,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: async,
|
||||
ddlog: ddlog)
|
||||
Swift.assertionFailure(message(), file: file, line: line)
|
||||
}
|
||||
}
|
||||
@@ -44,7 +126,24 @@ public func DDAssert(_ condition: @autoclosure () -> Bool, _ message: @autoclosu
|
||||
* - message: A string to log (using `DDLogError`). The default is an empty string.
|
||||
*/
|
||||
@inlinable
|
||||
public func DDAssertionFailure(_ message: @autoclosure () -> String = "", level: DDLogLevel = DDDefaultLogLevel, context: Int = 0, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, tag: Any? = nil, asynchronous async: Bool = false, ddlog: DDLog = DDLog.sharedInstance) {
|
||||
DDLogError(message(), level: level, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
|
||||
@available(*, deprecated, message: "Use an interpolated message.")
|
||||
public func DDAssertionFailure(_ message: @autoclosure () -> String = "",
|
||||
level: DDLogLevel = DDDefaultLogLevel,
|
||||
context: Int = 0,
|
||||
file: StaticString = #file,
|
||||
function: StaticString = #function,
|
||||
line: UInt = #line,
|
||||
tag: Any? = nil,
|
||||
asynchronous async: Bool? = nil,
|
||||
ddlog: DDLog = DDLog.sharedInstance) {
|
||||
DDLogError(message(),
|
||||
level: level,
|
||||
context: context,
|
||||
file: file,
|
||||
function: function,
|
||||
line: line,
|
||||
tag: tag,
|
||||
asynchronous: async,
|
||||
ddlog: ddlog)
|
||||
Swift.assertionFailure(message(), file: file, line: line)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
@@ -15,15 +15,76 @@
|
||||
|
||||
#if arch(arm64) || arch(x86_64)
|
||||
#if canImport(Combine)
|
||||
import Combine
|
||||
|
||||
public import Combine
|
||||
#if SWIFT_PACKAGE
|
||||
import CocoaLumberjack
|
||||
import CocoaLumberjackSwiftSupport
|
||||
public import CocoaLumberjack
|
||||
#endif
|
||||
|
||||
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
||||
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
||||
extension DDLog {
|
||||
// MARK: - Subscription
|
||||
private final class Subscription<S: Subscriber>: NSObject, DDLogger, Combine.Subscription
|
||||
where S.Input == DDLogMessage
|
||||
{ // swiftlint:disable:this opening_brace
|
||||
private var subscriber: S?
|
||||
private weak var log: DDLog?
|
||||
|
||||
/// Not used but ``DDLogger`` requires it.
|
||||
/// The preferred way to achieve this is to use the `map` Combine operator of the publisher.
|
||||
/// Example:
|
||||
/// ```
|
||||
/// DDLog.sharedInstance.messagePublisher()
|
||||
/// .map { message in /* format message */ }
|
||||
/// .sink(receiveValue: { formattedMessage in /* process formattedMessage */ })
|
||||
/// ```
|
||||
var logFormatter: (any DDLogFormatter)?
|
||||
|
||||
init(log: DDLog, with logLevel: DDLogLevel, subscriber: S) {
|
||||
self.subscriber = subscriber
|
||||
self.log = log
|
||||
|
||||
super.init()
|
||||
|
||||
log.add(self, with: logLevel)
|
||||
}
|
||||
|
||||
func request(_ demand: Subscribers.Demand) {
|
||||
// The log messages are endless until canceled, so we won't do any demand management.
|
||||
// Combine operators can be used to deal with it as needed.
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
log?.remove(self)
|
||||
subscriber = nil
|
||||
}
|
||||
|
||||
func log(message logMessage: DDLogMessage) {
|
||||
_ = subscriber?.receive(logMessage)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Publisher
|
||||
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
||||
public struct MessagePublisher: Combine.Publisher {
|
||||
public typealias Output = DDLogMessage
|
||||
public typealias Failure = Never
|
||||
|
||||
private let log: DDLog
|
||||
private let logLevel: DDLogLevel
|
||||
|
||||
public init(log: DDLog, with logLevel: DDLogLevel) {
|
||||
self.log = log
|
||||
self.logLevel = logLevel
|
||||
}
|
||||
|
||||
public func receive<S>(subscriber: S)
|
||||
where S: Subscriber, S.Failure == Failure, S.Input == Output
|
||||
{ // swiftlint:disable:this opening_brace
|
||||
let subscription = Subscription(log: log, with: logLevel, subscriber: subscriber)
|
||||
subscriber.receive(subscription: subscription)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a message publisher.
|
||||
*
|
||||
@@ -40,73 +101,15 @@ extension DDLog {
|
||||
* - Returns: A MessagePublisher that emits LogMessages filtered by the specified logLevel
|
||||
**/
|
||||
public func messagePublisher(with logLevel: DDLogLevel = .all) -> MessagePublisher {
|
||||
return MessagePublisher(log: self, with: logLevel)
|
||||
}
|
||||
|
||||
// MARK: - MessagePublisher
|
||||
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
||||
public struct MessagePublisher: Combine.Publisher {
|
||||
public typealias Output = DDLogMessage
|
||||
public typealias Failure = Never
|
||||
|
||||
private let log: DDLog
|
||||
private let logLevel: DDLogLevel
|
||||
|
||||
public init(log: DDLog, with logLevel: DDLogLevel) {
|
||||
self.log = log
|
||||
self.logLevel = logLevel
|
||||
}
|
||||
|
||||
public func receive<S>(subscriber: S) where S: Subscriber, S.Failure == Failure, S.Input == Output {
|
||||
let subscription = Subscription(log: log, with: logLevel, subscriber: subscriber)
|
||||
subscriber.receive(subscription: subscription)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Subscription
|
||||
private final class Subscription<S: Subscriber>: NSObject, DDLogger, Combine.Subscription where S.Input == DDLogMessage {
|
||||
private var subscriber: S?
|
||||
private weak var log: DDLog?
|
||||
|
||||
//Not used but DDLogger requires it. The preferred way to achieve this is to use the `map()` Combine operator of the publisher.
|
||||
//ie:
|
||||
// DDLog.sharedInstance.messagePublisher()
|
||||
// .map { [format log message] }
|
||||
// .sink(receiveValue: { [process log message] })
|
||||
//
|
||||
var logFormatter: DDLogFormatter?
|
||||
|
||||
init(log: DDLog, with logLevel: DDLogLevel, subscriber: S) {
|
||||
self.subscriber = subscriber
|
||||
self.log = log
|
||||
|
||||
super.init()
|
||||
|
||||
log.add(self, with: logLevel)
|
||||
}
|
||||
|
||||
func request(_ demand: Subscribers.Demand) {
|
||||
//The log messages are endless until canceled, so we won't do any demand management.
|
||||
//Combine operators can be used to deal with it as needed.
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
log?.remove(self)
|
||||
subscriber = nil
|
||||
}
|
||||
|
||||
func log(message logMessage: DDLogMessage) {
|
||||
_ = subscriber?.receive(logMessage)
|
||||
}
|
||||
MessagePublisher(log: self, with: logLevel)
|
||||
}
|
||||
}
|
||||
|
||||
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
||||
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
|
||||
extension Publisher where Output == DDLogMessage {
|
||||
public func formatted(with formatter: DDLogFormatter) -> Publishers.CompactMap<Self, String> {
|
||||
return compactMap { formatter.format(message: $0) }
|
||||
public func formatted(with formatter: any DDLogFormatter) -> Publishers.CompactMap<Self, String> {
|
||||
compactMap { formatter.format(message: $0) }
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Software License Agreement (BSD License)
|
||||
//
|
||||
// Copyright (c) 2010-2021, Deusty, LLC
|
||||
// Copyright (c) 2010-2026, Deusty, LLC
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use of this software in source and binary forms,
|
||||
|
||||
Reference in New Issue
Block a user