Merge branch 'charlesmchen/debugLogs' into hotfix/2.20.1

pull/1/head
Matthew Chen 7 years ago
commit de5d17a396

@ -46,6 +46,7 @@
#import <SignalServiceKit/TSStorageManager+Calling.h> #import <SignalServiceKit/TSStorageManager+Calling.h>
#import <SignalServiceKit/TextSecureKitEnv.h> #import <SignalServiceKit/TextSecureKitEnv.h>
#import <YapDatabase/YapDatabaseCryptoUtils.h> #import <YapDatabase/YapDatabaseCryptoUtils.h>
#import <sys/sysctl.h>
@import WebRTC; @import WebRTC;
@import Intents; @import Intents;
@ -324,7 +325,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"SETTINGS_ADVANCED_SUBMIT_DEBUGLOG", nil) [controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"SETTINGS_ADVANCED_SUBMIT_DEBUGLOG", nil)
style:UIAlertActionStyleDefault style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) { handler:^(UIAlertAction *_Nonnull action) {
[Pastelog submitLogsWithShareCompletion:^{ [Pastelog submitLogsWithCompletion:^{
DDLogInfo( DDLogInfo(
@"%@ exiting after sharing debug logs.", self.logTag); @"%@ exiting after sharing debug logs.", self.logTag);
[DDLog flushLog]; [DDLog flushLog];
@ -396,6 +397,15 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
if (languageCode.length > 0) { if (languageCode.length > 0) {
DDLogInfo(@"Language Code: %@", languageCode); DDLogInfo(@"Language Code: %@", languageCode);
} }
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *machine = malloc(size);
sysctlbyname("hw.machine", machine, &size, NULL, 0);
NSString *platform = [NSString stringWithUTF8String:machine];
free(machine);
DDLogInfo(@"iPhone Version: %@", platform);
} }
- (UIViewController *)loadingRootViewController - (UIViewController *)loadingRootViewController

@ -7,7 +7,6 @@
#import "OWSTableViewController.h" #import "OWSTableViewController.h"
#import "Signal-Swift.h" #import "Signal-Swift.h"
#import "ThreadUtil.h" #import "ThreadUtil.h"
#import <AFNetworking/AFNetworking.h>
#import <AxolotlKit/PreKeyBundle.h> #import <AxolotlKit/PreKeyBundle.h>
#import <Curve25519Kit/Randomness.h> #import <Curve25519Kit/Randomness.h>
#import <SignalMessaging/Environment.h> #import <SignalMessaging/Environment.h>

@ -10,7 +10,6 @@
#import "RegistrationViewController.h" #import "RegistrationViewController.h"
#import "Signal-Swift.h" #import "Signal-Swift.h"
#import "ThreadUtil.h" #import "ThreadUtil.h"
#import <AFNetworking/AFNetworking.h>
#import <AxolotlKit/PreKeyBundle.h> #import <AxolotlKit/PreKeyBundle.h>
#import <SignalMessaging/AttachmentSharing.h> #import <SignalMessaging/AttachmentSharing.h>
#import <SignalMessaging/Environment.h> #import <SignalMessaging/Environment.h>

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import "DebugUISyncMessages.h" #import "DebugUISyncMessages.h"
@ -7,7 +7,6 @@
#import "OWSTableViewController.h" #import "OWSTableViewController.h"
#import "Signal-Swift.h" #import "Signal-Swift.h"
#import "ThreadUtil.h" #import "ThreadUtil.h"
#import <AFNetworking/AFNetworking.h>
#import <AxolotlKit/PreKeyBundle.h> #import <AxolotlKit/PreKeyBundle.h>
#import <Curve25519Kit/Randomness.h> #import <Curve25519Kit/Randomness.h>
#import <SignalMessaging/Environment.h> #import <SignalMessaging/Environment.h>

@ -2,14 +2,17 @@
// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
NS_ASSUME_NONNULL_BEGIN
typedef void (^SubmitDebugLogsCompletion)(void);
@interface Pastelog : NSObject @interface Pastelog : NSObject
typedef void (^DebugLogsUploadedBlock)(NSError *error, NSString *urlString); - (instancetype)init NS_UNAVAILABLE;
typedef void (^DebugLogsSharedBlock)(void);
+(void)submitLogs; + (void)submitLogs;
+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)block; + (void)submitLogsWithCompletion:(nullable SubmitDebugLogsCompletion)completion;
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block;
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block forFileLogger:(DDFileLogger *)fileLogger;
@end @end
NS_ASSUME_NONNULL_END

@ -5,6 +5,7 @@
#import "Pastelog.h" #import "Pastelog.h"
#import "Signal-Swift.h" #import "Signal-Swift.h"
#import "ThreadUtil.h" #import "ThreadUtil.h"
#import <SSZipArchive/SSZipArchive.h>
#import <SignalMessaging/DebugLogger.h> #import <SignalMessaging/DebugLogger.h>
#import <SignalMessaging/Environment.h> #import <SignalMessaging/Environment.h>
#import <SignalServiceKit/AppContext.h> #import <SignalServiceKit/AppContext.h>
@ -12,251 +13,426 @@
#import <SignalServiceKit/TSContactThread.h> #import <SignalServiceKit/TSContactThread.h>
#import <SignalServiceKit/TSStorageManager.h> #import <SignalServiceKit/TSStorageManager.h>
#import <SignalServiceKit/Threading.h> #import <SignalServiceKit/Threading.h>
#import <sys/sysctl.h>
@interface Pastelog () <NSURLConnectionDelegate, NSURLConnectionDataDelegate, UIAlertViewDelegate> NS_ASSUME_NONNULL_BEGIN
typedef void (^UploadDebugLogsSuccess)(NSURL *url);
typedef void (^UploadDebugLogsFailure)(NSString *localizedErrorMessage);
#pragma mark -
@class DebugLogUploader;
typedef void (^DebugLogUploadSuccess)(DebugLogUploader *uploader, NSURL *url);
typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error);
@interface DebugLogUploader : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
@property (nonatomic) UIAlertController *loadingAlert;
@property (nonatomic) NSMutableData *responseData; @property (nonatomic) NSMutableData *responseData;
@property (nonatomic) DebugLogsUploadedBlock block; @property (nonatomic, nullable) DebugLogUploadSuccess success;
@property (nonatomic, nullable) DebugLogUploadFailure failure;
@end @end
#pragma mark - #pragma mark -
@implementation Pastelog @implementation DebugLogUploader
+(void)submitLogs { - (void)dealloc
[self submitLogsWithShareCompletion:nil]; {
DDLogVerbose(@"Dealloc: %@", self.logTag);
} }
+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)shareCompletionParam - (void)uploadFileWithURL:(NSURL *)fileUrl success:(DebugLogUploadSuccess)success failure:(DebugLogUploadFailure)failure
{ {
DebugLogsSharedBlock shareCompletion = ^{ OWSAssert(fileUrl);
if (shareCompletionParam) { OWSAssert(success);
// Wait a moment. If PasteLog opens a URL, it needs a moment to complete. OWSAssert(failure);
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), shareCompletionParam);
}
};
[self submitLogsWithUploadCompletion:^(NSError *error, NSString *urlString) { self.success = success;
if (!error) { self.failure = failure;
UIAlertController *alert = [UIAlertController self.responseData = [NSMutableData new];
alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", @"Title of the debug log alert.")
message:NSLocalizedString(
@"DEBUG_LOG_ALERT_MESSAGE", @"Message of the debug log alert.")
preferredStyle:UIAlertControllerStyleAlert];
[alert
addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_EMAIL",
@"Label for the 'email debug log' option of the the debug log alert.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[Pastelog.sharedManager submitEmail:urlString];
shareCompletion();
}]];
[alert addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_COPY_LINK",
@"Label for the 'copy link' option of the the debug log alert.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
UIPasteboard *pb = [UIPasteboard generalPasteboard];
[pb setString:urlString];
shareCompletion();
}]];
#ifdef DEBUG
[alert addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF",
@"Label for the 'send to self' option of the the debug log alert.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[Pastelog.sharedManager sendToSelf:urlString];
}]];
[alert addAction:[UIAlertAction
actionWithTitle:
NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_LAST_THREAD",
@"Label for the 'send to last thread' option of the the debug log alert.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[Pastelog.sharedManager sendToMostRecentThread:urlString];
}]];
#endif
[alert addAction:
[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_BUG_REPORT",
@"Label for the 'Open a Bug Report' option of the the debug log alert.")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[Pastelog.sharedManager prepareRedirection:urlString
shareCompletion:shareCompletion];
}]];
UIViewController *presentingViewController
= UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
[presentingViewController presentViewController:alert animated:NO completion:nil];
} else{
UIAlertView *alertView =
[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"DEBUG_LOG_FAILURE_ALERT_TITLE",
@"Title of the alert indicating the debug log upload failed.")
message:error.localizedDescription
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil];
[alertView show];
}
}];
}
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block NSURL *url = [NSURL URLWithString:@"https://filebin.net"];
{
[self submitLogsWithUploadCompletion:block forFileLogger:[[DDFileLogger alloc] init]]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
[request setHTTPMethod:@"POST"];
[request addValue:fileUrl.lastPathComponent forHTTPHeaderField:@"filename"];
[request addValue:@"application/zip" forHTTPHeaderField:@"Content-Type"];
NSData *_Nullable data = [NSData dataWithContentsOfURL:fileUrl];
if (!data) {
[self failWithError:[NSError errorWithDomain:@"PastelogKit"
code:10002
userInfo:@{ NSLocalizedDescriptionKey : @"Could not load data." }]];
return;
}
// TODO:
[request setHTTPBody:data];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
} }
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block forFileLogger:(DDFileLogger *)fileLogger #pragma mark - Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{ {
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
[self sharedManager].block = block; [self.responseData appendData:data];
}
[self sharedManager].loadingAlert = - (void)connectionDidFinishLoading:(NSURLConnection *)connection
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ACTIVITY_INDICATOR", {
@"Message indicating that the debug log is being uploaded.") DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
message:nil
preferredStyle:UIAlertControllerStyleAlert];
UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
[presentingViewController presentViewController:[self sharedManager].loadingAlert animated:NO completion:nil];
NSArray<NSString *> *logFilePaths = DebugLogger.sharedLogger.allLogFilePaths; NSError *error;
NSDictionary *_Nullable dict = [NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error];
if (error) {
DDLogError(@"%@ response length: %zd", self.logTag, self.responseData.length);
[self failWithError:error];
return;
}
NSMutableDictionary *gistFiles = [NSMutableDictionary new]; if (![dict isKindOfClass:[NSDictionary class]]) {
DDLogError(@"%@ response (1): %@", self.logTag, dict);
[self failWithError:[NSError errorWithDomain:@"PastelogKit"
code:10003
userInfo:@{ NSLocalizedDescriptionKey : @"Malformed response (root)." }]];
return;
}
for (NSString *logFilePath in logFilePaths) { NSArray<id> *_Nullable links = [dict objectForKey:@"links"];
NSError *error; if (![links isKindOfClass:[NSArray class]]) {
NSString *logContents = DDLogError(@"%@ response (2): %@", self.logTag, dict);
[NSString stringWithContentsOfFile:logFilePath encoding:NSUTF8StringEncoding error:&error]; [self failWithError:[NSError errorWithDomain:@"PastelogKit"
if (error) { code:10004
OWSFail(@"%@ Error loading log file contents: %@", self.logTag, error); userInfo:@{ NSLocalizedDescriptionKey : @"Malformed response (links)." }]];
return;
}
NSString *_Nullable urlString = nil;
for (NSDictionary *linkMap in links) {
if (![linkMap isKindOfClass:[NSDictionary class]]) {
DDLogError(@"%@ response (2): %@", self.logTag, dict);
[self failWithError:[NSError
errorWithDomain:@"PastelogKit"
code:10005
userInfo:@{ NSLocalizedDescriptionKey : @"Malformed response (linkMap)." }]];
return;
}
NSString *_Nullable linkRel = [linkMap objectForKey:@"rel"];
if (![linkRel isKindOfClass:[NSString class]]) {
DDLogError(@"%@ response (linkRel): %@", self.logTag, dict);
continue;
}
if (![linkRel isEqualToString:@"file"]) {
DDLogError(@"%@ response (linkRel value): %@", self.logTag, dict);
continue; continue;
} }
gistFiles[logFilePath.lastPathComponent] = @{ NSString *_Nullable linkHref = [linkMap objectForKey:@"href"];
@"content" : logContents, if (![linkHref isKindOfClass:[NSString class]]) {
}; DDLogError(@"%@ response (linkHref): %@", self.logTag, dict);
continue;
}
urlString = linkHref;
break;
} }
[self succeedWithUrl:[NSURL URLWithString:urlString]];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSInteger statusCode = httpResponse.statusCode;
// We'll accept any 2xx status code.
NSInteger statusCodeClass = statusCode - (statusCode % 100);
if (statusCodeClass != 200) {
DDLogError(@"%@ statusCode: %zd, %zd", self.logTag, statusCode, statusCodeClass);
DDLogError(@"%@ headers: %@", self.logTag, httpResponse.allHeaderFields);
[self failWithError:[NSError errorWithDomain:@"PastelogKit"
code:10001
userInfo:@{ NSLocalizedDescriptionKey : @"Invalid response code." }]];
}
}
NSDictionary *gistDict = @{@"description":[self gistDescription], @"files":gistFiles}; - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
NSData *postData = [NSJSONSerialization dataWithJSONObject:gistDict options:0 error:nil]; [self failWithError:error];
}
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:@"https://api.github.com/gists"] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:30]; - (void)failWithError:(NSError *)error
{
OWSAssert(error);
[[self sharedManager] setResponseData:[NSMutableData data]]; DDLogError(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, error);
[[self sharedManager] setBlock:block];
[request setHTTPMethod:@"POST"]; DispatchMainThreadSafe(^{
[request setHTTPBody:postData]; // Call the completions exactly once.
if (self.failure) {
self.failure(self, error);
}
self.success = nil;
self.failure = nil;
});
}
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:[self sharedManager]]; - (void)succeedWithUrl:(NSURL *)url
{
OWSAssert(url);
[connection start]; DDLogVerbose(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, url);
DispatchMainThreadSafe(^{
// Call the completions exactly once.
if (self.success) {
self.success(self, url);
}
self.success = nil;
self.failure = nil;
});
} }
+(Pastelog*)sharedManager { @end
#pragma mark -
@interface Pastelog () <UIAlertViewDelegate>
@property (nonatomic) UIAlertController *loadingAlert;
@property (nonatomic) DebugLogUploader *currentUploader;
@end
#pragma mark -
@implementation Pastelog
+ (instancetype)sharedManager
{
static Pastelog *sharedMyManager = nil; static Pastelog *sharedMyManager = nil;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init]; sharedMyManager = [[self alloc] initDefault];
}); });
return sharedMyManager; return sharedMyManager;
} }
-(instancetype)init { - (instancetype)initDefault
if (self = [super init]) { {
self.responseData = [NSMutableData data]; self = [super init];
OWSSingletonAssert(); if (!self) {
return self;
} }
OWSSingletonAssert();
return self; return self;
} }
+(NSString*)gistDescription{ + (void)submitLogs
size_t size; {
sysctlbyname("hw.machine", NULL, &size, NULL, 0); [self submitLogsWithCompletion:nil];
char *machine = malloc(size); }
sysctlbyname("hw.machine", machine, &size, NULL, 0);
NSString *platform = [NSString stringWithUTF8String:machine];
free(machine);
NSString *gistDesc = [NSString stringWithFormat:@"iPhone Version: %@, iOS Version: %@", platform,[UIDevice currentDevice].systemVersion]; + (void)submitLogsWithCompletion:(nullable SubmitDebugLogsCompletion)completionParam
{
SubmitDebugLogsCompletion completion = ^{
if (completionParam) {
// Wait a moment. If PasteLog opens a URL, it needs a moment to complete.
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), completionParam);
}
};
return gistDesc; [self uploadLogsWithSuccess:^(NSURL *url) {
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", @"Title of the debug log alert.")
message:NSLocalizedString(@"DEBUG_LOG_ALERT_MESSAGE", @"Message of the debug log alert.")
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_EMAIL",
@"Label for the 'email debug log' option of the the debug log alert.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[Pastelog.sharedManager submitEmail:url];
completion();
}]];
[alert addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_COPY_LINK",
@"Label for the 'copy link' option of the the debug log alert.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
UIPasteboard *pb = [UIPasteboard generalPasteboard];
[pb setString:url.absoluteString];
completion();
}]];
#ifdef DEBUG
[alert addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF",
@"Label for the 'send to self' option of the the debug log alert.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[Pastelog.sharedManager sendToSelf:url];
}]];
[alert
addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_LAST_THREAD",
@"Label for the 'send to last thread' option of the the debug log alert.")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[Pastelog.sharedManager sendToMostRecentThread:url];
}]];
#endif
[alert
addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_BUG_REPORT",
@"Label for the 'Open a Bug Report' option of the the debug log alert.")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[Pastelog.sharedManager prepareRedirection:url completion:completion];
}]];
UIViewController *presentingViewController
= UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
[presentingViewController presentViewController:alert animated:NO completion:nil];
}];
} }
#pragma mark Network delegates + (void)uploadLogsWithSuccess:(nullable UploadDebugLogsSuccess)success
{
OWSAssert(success);
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ [[self sharedManager] uploadLogsWithSuccess:success
[self.responseData appendData:data]; failure:^(NSString *localizedErrorMessage) {
[Pastelog showFailureAlertWithMessage:localizedErrorMessage];
}];
} }
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { - (void)uploadLogsWithSuccess:(nullable UploadDebugLogsSuccess)successParam failure:(UploadDebugLogsFailure)failureParam
[self.loadingAlert {
dismissViewControllerAnimated:NO OWSAssert(successParam);
completion:^{ OWSAssert(failureParam);
NSError *error;
NSDictionary *dict = // Ensure that we call the completions on the main thread.
[NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error]; UploadDebugLogsSuccess success = ^(NSURL *url) {
if (!error) { if (successParam) {
self.block(nil, [dict objectForKey:@"html_url"]); DispatchMainThreadSafe(^{
} else { successParam(url);
DDLogError(@"Error on debug response: %@", error); });
self.block(error, nil); }
} };
}]; UploadDebugLogsFailure failure = ^(NSString *localizedErrorMessage) {
self.loadingAlert = nil; DispatchMainThreadSafe(^{
} failureParam(localizedErrorMessage);
});
};
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { // Phase 1. Make a local copy of all of the log files.
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setLocale:[NSLocale currentLocale]];
[dateFormatter setDateFormat:@"yyyy.MM.dd hh.mm.ss"];
NSString *dateString = [dateFormatter stringFromDate:[NSDate new]];
NSString *logsName = [[dateString stringByAppendingString:@" "] stringByAppendingString:NSUUID.UUID.UUIDString];
NSString *tempDirectory = NSTemporaryDirectory();
NSString *zipFilePath =
[tempDirectory stringByAppendingPathComponent:[logsName stringByAppendingPathExtension:@"zip"]];
NSString *zipDirPath = [tempDirectory stringByAppendingPathComponent:logsName];
[OWSFileSystem ensureDirectoryExists:zipDirPath];
[OWSFileSystem protectFileOrFolderAtPath:zipDirPath];
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; NSArray<NSString *> *logFilePaths = DebugLogger.sharedLogger.allLogFilePaths;
if (logFilePaths.count < 1) {
failure(NSLocalizedString(@"DEBUG_LOG_ALERT_NO_LOGS", @"Error indicating that no debug logs could be found."));
return;
}
if ( [httpResponse statusCode] != 201) { for (NSString *logFilePath in logFilePaths) {
DDLogError(@"Failed to submit debug log: %@", httpResponse.debugDescription); NSString *copyFilePath = [zipDirPath stringByAppendingPathComponent:logFilePath.lastPathComponent];
[self.loadingAlert NSError *error;
dismissViewControllerAnimated:NO [[NSFileManager defaultManager] copyItemAtPath:logFilePath toPath:copyFilePath error:&error];
completion:^{ if (error) {
[connection cancel]; failure(NSLocalizedString(
self.block([NSError errorWithDomain:@"PastelogKit" code:10001 userInfo:@{}], nil); @"DEBUG_LOG_ALERT_COULD_NOT_COPY_LOGS", @"Error indicating that the debug logs could not be copied."));
}]; return;
self.loadingAlert = nil; }
[OWSFileSystem protectFileOrFolderAtPath:copyFilePath];
}
// Phase 2. Zip up the log files.
BOOL zipSuccess =
[SSZipArchive createZipFileAtPath:zipFilePath withContentsOfDirectory:zipDirPath withPassword:nil];
if (!zipSuccess) {
failure(NSLocalizedString(
@"DEBUG_LOG_ALERT_COULD_NOT_PACKAGE_LOGS", @"Error indicating that the debug logs could not be packaged."));
return;
} }
[OWSFileSystem protectFileOrFolderAtPath:zipFilePath];
[OWSFileSystem deleteFile:zipDirPath];
// Phase 3. Upload the log files.
__weak Pastelog *weakSelf = self;
self.currentUploader = [DebugLogUploader new];
[self.currentUploader uploadFileWithURL:[NSURL fileURLWithPath:zipFilePath]
success:^(DebugLogUploader *uploader, NSURL *url) {
if (uploader != weakSelf.currentUploader) {
// Ignore events from obsolete uploaders.
return;
}
[OWSFileSystem deleteFile:zipFilePath];
success(url);
}
failure:^(DebugLogUploader *uploader, NSError *error) {
if (uploader != weakSelf.currentUploader) {
// Ignore events from obsolete uploaders.
return;
}
[OWSFileSystem deleteFile:zipFilePath];
failure(NSLocalizedString(
@"DEBUG_LOG_ALERT_ERROR_UPLOADING_LOG", @"Error indicating that a debug log could not be uploaded."));
}];
} }
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + (void)showFailureAlertWithMessage:(NSString *)message
[self.loadingAlert dismissViewControllerAnimated:NO {
completion:^{ UIAlertController *alert = [UIAlertController
DDLogError(@"Uploading logs failed with error: %@", error); alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE",
self.block(error, nil); @"Title of the alert shown for failures while uploading debug logs.")
}]; message:message
self.loadingAlert = nil; preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"")
style:UIAlertActionStyleDefault
handler:nil]];
UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
[presentingViewController presentViewController:alert animated:NO completion:nil];
} }
#pragma mark Logs submission #pragma mark Logs submission
- (void)submitEmail:(NSString*)url { - (void)submitEmail:(NSURL *)url
{
NSString *emailAddress = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LOGS_EMAIL"]; NSString *emailAddress = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LOGS_EMAIL"];
NSString *urlString = [NSString stringWithString: [[NSString stringWithFormat:@"mailto:%@?subject=iOS%%20Debug%%20Log&body=", emailAddress] stringByAppendingString:[[NSString stringWithFormat:@"Log URL: %@ \n Tell us about the issue: ", url]stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]]; NSString *urlString = [NSString stringWithString: [[NSString stringWithFormat:@"mailto:%@?subject=iOS%%20Debug%%20Log&body=", emailAddress] stringByAppendingString:[[NSString stringWithFormat:@"Log URL: %@ \n Tell us about the issue: ", url]stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]];
[UIApplication.sharedApplication openURL: [NSURL URLWithString: urlString]]; [UIApplication.sharedApplication openURL:[NSURL URLWithString:urlString]];
} }
- (void)prepareRedirection:(NSString *)url shareCompletion:(DebugLogsSharedBlock)shareCompletion - (void)prepareRedirection:(NSURL *)url completion:(SubmitDebugLogsCompletion)completion
{ {
OWSAssert(shareCompletion); OWSAssert(completion);
UIPasteboard *pb = [UIPasteboard generalPasteboard]; UIPasteboard *pb = [UIPasteboard generalPasteboard];
[pb setString:url]; [pb setString:url.absoluteString];
UIAlertController *alert = UIAlertController *alert =
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_GITHUB_ISSUE_ALERT_TITLE", [UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_GITHUB_ISSUE_ALERT_TITLE",
@ -272,13 +448,13 @@
openURL:[NSURL URLWithString:[[NSBundle mainBundle] openURL:[NSURL URLWithString:[[NSBundle mainBundle]
objectForInfoDictionaryKey:@"LOGS_URL"]]]; objectForInfoDictionaryKey:@"LOGS_URL"]]];
shareCompletion(); completion();
}]]; }]];
UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts; UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
[presentingViewController presentViewController:alert animated:NO completion:nil]; [presentingViewController presentViewController:alert animated:NO completion:nil];
} }
- (void)sendToSelf:(NSString *)url - (void)sendToSelf:(NSURL *)url
{ {
if (![TSAccountManager isRegistered]) { if (![TSAccountManager isRegistered]) {
return; return;
@ -292,14 +468,14 @@
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
}]; }];
[ThreadUtil sendMessageWithText:url inThread:thread messageSender:messageSender]; [ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender];
}); });
// Also copy to pasteboard. // Also copy to pasteboard.
[[UIPasteboard generalPasteboard] setString:url]; [[UIPasteboard generalPasteboard] setString:url.absoluteString];
} }
- (void)sendToMostRecentThread:(NSString *)url - (void)sendToMostRecentThread:(NSURL *)url
{ {
if (![TSAccountManager isRegistered]) { if (![TSAccountManager isRegistered]) {
return; return;
@ -312,11 +488,13 @@
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:[TSThread collection]]; thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:[TSThread collection]];
}]; }];
[ThreadUtil sendMessageWithText:url inThread:thread messageSender:messageSender]; [ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender];
}); });
// Also copy to pasteboard. // Also copy to pasteboard.
[[UIPasteboard generalPasteboard] setString:url]; [[UIPasteboard generalPasteboard] setString:url.absoluteString];
} }
@end @end
NS_ASSUME_NONNULL_END

@ -499,12 +499,21 @@
/* The day before today. */ /* The day before today. */
"DATE_YESTERDAY" = "Yesterday"; "DATE_YESTERDAY" = "Yesterday";
/* Message indicating that the debug log is being uploaded. */ /* Error indicating that the debug logs could not be copied. */
"DEBUG_LOG_ACTIVITY_INDICATOR" = "Sending Debug Log..."; "DEBUG_LOG_ALERT_COULD_NOT_COPY_LOGS" = "Could not copy logs.";
/* Error indicating that the debug logs could not be packaged. */
"DEBUG_LOG_ALERT_COULD_NOT_PACKAGE_LOGS" = "Could not package logs.";
/* Error indicating that a debug log could not be uploaded. */
"DEBUG_LOG_ALERT_ERROR_UPLOADING_LOG" = "Could not upload logs.";
/* Message of the debug log alert. */ /* Message of the debug log alert. */
"DEBUG_LOG_ALERT_MESSAGE" = "What would you like to do with the link to your debug log?"; "DEBUG_LOG_ALERT_MESSAGE" = "What would you like to do with the link to your debug log?";
/* Error indicating that no debug logs could be found. */
"DEBUG_LOG_ALERT_NO_LOGS" = "Could not find any logs.";
/* Label for the 'Open a Bug Report' option of the the debug log alert. */ /* Label for the 'Open a Bug Report' option of the the debug log alert. */
"DEBUG_LOG_ALERT_OPTION_BUG_REPORT" = "Open a Bug Report"; "DEBUG_LOG_ALERT_OPTION_BUG_REPORT" = "Open a Bug Report";
@ -520,12 +529,10 @@
/* Label for the 'send to self' option of the the debug log alert. */ /* Label for the 'send to self' option of the the debug log alert. */
"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF" = "Send to Self"; "DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF" = "Send to Self";
/* Title of the debug log alert. */ /* Title of the alert shown for failures while uploading debug logs.
Title of the debug log alert. */
"DEBUG_LOG_ALERT_TITLE" = "One More Step"; "DEBUG_LOG_ALERT_TITLE" = "One More Step";
/* Title of the alert indicating the debug log upload failed. */
"DEBUG_LOG_FAILURE_ALERT_TITLE" = "Failed to Submit Debug Log";
/* Message of the alert before redirecting to Github Issues. */ /* Message of the alert before redirecting to Github Issues. */
"DEBUG_LOG_GITHUB_ISSUE_ALERT_MESSAGE" = "The gist link was copied in your clipboard. You are about to be redirected to the GitHub issue list."; "DEBUG_LOG_GITHUB_ISSUE_ALERT_MESSAGE" = "The gist link was copied in your clipboard. You are about to be redirected to the GitHub issue list.";

@ -7,7 +7,6 @@
#import "NSString+OWS.h" #import "NSString+OWS.h"
#import "OWSUserProfile.h" #import "OWSUserProfile.h"
#import "UIImage+OWS.h" #import "UIImage+OWS.h"
#import <AFNetworking/AFNetworking.h>
#import <SignalMessaging/SignalMessaging-Swift.h> #import <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalServiceKit/AppContext.h> #import <SignalServiceKit/AppContext.h>
#import <SignalServiceKit/Cryptography.h> #import <SignalServiceKit/Cryptography.h>

@ -1,9 +1,11 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import <CocoaLumberjack/DDFileLogger.h> #import <CocoaLumberjack/DDFileLogger.h>
NS_ASSUME_NONNULL_BEGIN
@interface DebugLogger : NSObject @interface DebugLogger : NSObject
+ (instancetype)sharedLogger; + (instancetype)sharedLogger;
@ -19,3 +21,5 @@
- (NSArray<NSString *> *)allLogFilePaths; - (NSArray<NSString *> *)allLogFilePaths;
@end @end
NS_ASSUME_NONNULL_END

@ -11,9 +11,13 @@
#pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging. #pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging.
#import <CocoaLumberjack/DDTTYLogger.h> #import <CocoaLumberjack/DDTTYLogger.h>
NS_ASSUME_NONNULL_BEGIN
const NSUInteger kMaxDebugLogFileSize = 1024 * 1024 * 3;
@interface DebugLogger () @interface DebugLogger ()
@property (nonatomic) DDFileLogger *fileLogger; @property (nonatomic, nullable) DDFileLogger *fileLogger;
@end @end
@ -66,9 +70,8 @@
// 24 hour rolling. // 24 hour rolling.
self.fileLogger.rollingFrequency = kDayInterval; self.fileLogger.rollingFrequency = kDayInterval;
// Keep last 3 days of logs - or last 3 logs (if logs rollover due to max file size). // Keep last 3 days of logs - or last 3 logs (if logs rollover due to max file size).
self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3; self.fileLogger.logFileManager.maximumNumberOfLogFiles = 24;
// Raise the max file size per log file to 3 MB. self.fileLogger.maximumFileSize = kMaxDebugLogFileSize;
self.fileLogger.maximumFileSize = 1024 * 1024 * 3;
self.fileLogger.logFormatter = [OWSScrubbingLogFormatter new]; self.fileLogger.logFormatter = [OWSScrubbingLogFormatter new];
[DDLog addLogger:self.fileLogger]; [DDLog addLogger:self.fileLogger];
@ -133,3 +136,5 @@
} }
@end @end
NS_ASSUME_NONNULL_END

Loading…
Cancel
Save