There are many third-party good tools for the collection of crashes, such as bugly. However, if you want to collect the crash log yourself (for example, for applications that are published internally within the intranet), there is a natural way to do it.
Here are two ways to crawl the crash stack information, and if you find a problem, I hope to enlighten you. Make a note of yourself, too. :-)
Method One: Call the C function to grab the stack information, say no more, the code to
#import <Foundation/Foundation.h>
extern nsstring *const Sksappexceptioninfo;
@interface Sksexceptionrecord:nsobject
+ (void) Startexceptionhandler;
@end
#import "SKSExceptionRecord.h"
#include <execinfo.h>
NSString *const sksappexceptioninfo = @ "Sksappexceptioninfo";
static int s_fatal_signals[] = {
SIGABRT,
Sigbus,
SIGFPE,
Sigill,
SIGSEGV,
SIGTRAP,
SIGTERM,
SIGKILL,
};
static const char* s_fatal_signal_names[] = {
"SIGABRT",
"Sigbus",
"SIGFPE",
"Sigill",
"SIGSEGV",
"SIGTRAP",
"SIGTERM",
"SIGKILL",
};
static int s_fatal_signal_num = sizeof (s_fatal_signals)/sizeof (s_fatal_signals[0]);
Signal processing functions
void Signalhandler (int signal) {
for (int i = 0; i < S_fatal_signal_num; ++i) {
if (signal = = S_fatal_signals[i]) {
Signal exception does not upload log, but also need to capture, or exception exception is not uploaded
[Sksexceptionrecord handleexception:[nsstring stringwithformat:@ "%s", S_fatal_signal_names[i]] description:[ Sksexceptionrecord BackTrace]];
Break
}
}
}
void Exceptionhandler (NSException *exception) {
[Sksexceptionrecord handleexception:[exception reason] description:[exception callstacksymbols];
}
@implementation Sksexceptionrecord
+ (Nsarray *) BackTrace {
void *callstack[128];
int frames = BackTrace (callstack, 128);
Char **strs = Backtrace_symbols (callstack, frames);
Nsmutablearray *backtrace = [Nsmutablearray arraywithcapacity:frames];
for (int i = 0; i < frames; ++i) {
[BackTrace addobject:[nsstring Stringwithutf8string:strs[i]];
}
Free (STRs);
return backtrace;
}
+ (void) Startcrashhandler
{
1 Linux error signal capture
for (int i = 0; i < S_fatal_signal_num; ++i) {
Signal (S_fatal_signals[i], signalhandler);
}
2 objective-c Catch of uncaught exception
Nssetuncaughtexceptionhandler (&exceptionhandler);
}
+ (void) HandleException: (NSString *) reason description: (ID) description
{
This throws the message, the application can listen to the message as needed, to do the corresponding crash processing, such as uploading to the server
Nsdictionary *dicinfo = [nsdictionary Dictionarywithobjectsandkeys:reason, @ "Reason", description, @ "description", nil ];
[[Nsnotificationcenter Defaultcenter] Postnotificationname:sksappexceptioninfo object:nil UserInfo:dicInfo];
[Self keepappsurvive];
}
+ (void) keepappsurvive
//{
Cfrunloopref Runloop = Cfrunloopgetcurrent ();
Cfarrayref allmodes = Cfrunloopcopyallmodes (Runloop);
//
BOOL dismissed = NO;
while (YES)
// {
For (NSString *mode in (__bridge Nsarray *) allmodes)
// {
Cfrunloopruninmode ((__bridge cfstringref) mode, 0.001, false);
// }
Sleep (2);
dismissed = YES;
// }
//
Cfrelease (Allmodes);
//}
@end
The flaw of this method, if the symbol table is disable, then the crawled information will not be readable, just a pure memory stack.
Method Two: Using Kscrash, the advantage is that the crash stack can be parsed directly into a readable character. First you need to go to git to download the Kscrash, add the source directory to the app project, or add the Kscrash project directly to the app. After adding the basic need to expand their own methods to handle the crash information, because the methods already included (such as mail) may not be the long-term crash tracking method you want.
Here's how I defined the crash log collection:
#import <Foundation/Foundation.h>
#import "KSCrashInstallation.h"
#import "KSCRASH.H"
#import "KSCrashAdvanced.h"
@interface Skscrashmanager:nsobject
+ (Skscrashmanager *) Sharedmanager;
-(void) Checklocalcrashlogs: (kscrashreportfiltercompletion) block;
@end
#import "SKSCrashManager.h"
#import "Kscrashinstallation+private.h"
#import "KSSingleton.h"
#import "KSCrashReportFilterAppleFmt.h"
#import "SkySeaManager.h"
#import "SKSEncrypt.h"
NSString *const Sksappexceptionwithkscrash = @ "Sksappexceptionwithkscrash";
-----------------Skscrashreportsink----------------------------------------------
@interface Skscrashreportsink:nsobject <KSCrashReportFilter>
-(ID <KSCrashReportFilter>) Defaultcrashreportfilterset;
@end
@implementation Skscrashreportsink
-(ID <KSCrashReportFilter>) defaultcrashreportfilterset
{
This method is important to ksapplereportstylesymbolicated this format to return a readable crash log
return [Kscrashreportfilterpipeline filterwithfilters:
[Kscrashreportfilterapplefmt filterwithreportstyle:ksapplereportstylesymbolicated],
Self
NIL];
}
-(void) Filterreports: (nsarray*) reports
Oncompletion: (kscrashreportfiltercompletion) oncompletion
{
Nsdictionary *dicinfo = [nsdictionary dictionarywithobjectsandkeys:reports, @ "reports", Oncompletion, @ "callback", nil ];
[[Nsnotificationcenter Defaultcenter] Postnotificationname:sksappexceptionwithkscrash object:nil UserInfo:dicInfo] ;
}
@end
--------------------skscrashinstallation-----------------------------------------
@interface skscrashinstallation:kscrashinstallation
+ (skscrashinstallation*) sharedinstance;
@end
@implementation Skscrashinstallation
Implement_exclusive_shared_instance (skscrashinstallation)
-(ID) init
{
if (self = [super Initwithrequiredproperties:nil])
{
}
return self;
}
-(id<kscrashreportfilter>) sink
{
skscrashreportsink* sink = [[Skscrashreportsink alloc] init];
return [Kscrashreportfilterpipeline Filterwithfilters:[sink Defaultcrashreportfilterset], nil];
}
@end
static Skscrashmanager *g_crashmanager = NULL;
@interface Skscrashmanager ()
@property (Strong, nonatomic) kscrashinstallation* crashinstallation;
@end
@implementation Skscrashmanager
+ (Skscrashmanager *) Sharedmanager {
Static dispatch_once_t Oncetoken;
Dispatch_once (&oncetoken, ^{
if (G_crashmanager = = NULL) {
G_crashmanager = [[Skscrashmanager alloc] init];
[G_crashmanager Installcrashhandler];
}
});
return g_crashmanager;
}
-(void) dealloc
{
[[Nsnotificationcenter Defaultcenter] removeobserver:self];
}
-(void) Installcrashhandler
{
[Self configureadvancedsettings];
Self.crashinstallation = [Skscrashinstallation sharedinstance];
[Self.crashinstallation install];
[[Nsnotificationcenter Defaultcenter] addobserver:self selector: @selector (uploadexceptionlog:) Name: Sksappexceptionwithkscrash Object:nil];
}
static void Advanced_crash_callback (const kscrashreportwriter* writer)
{
You can add extra user data at crash time if you want.
Writer->addbooleanelement (writer, "Some_bool_value", NO);
}
-(void) configureadvancedsettings
{
kscrash* handler = [Kscrash sharedinstance];
Handler.deletebehavioraftersendall = kscdeleteonsucess;
Handler.zombiecachesize = 16384*4;
Handler.deadlockwatchdoginterval = 0;
Handler.userinfo = @{@ "Somekey": @ "somevalue"};
Handler.oncrash = Advanced_crash_callback;
Handler.printtracetostdout = NO;
Handler.searchthreadnames = YES;
Handler.searchqueuenames = YES;
Handler.handlingcrashtypes = Kscrashtypeall;
}
-(void) Checklocalcrashlogs: (kscrashreportfiltercompletion) Block {
[Self.crashinstallation Sendallreportswithcompletion:block];
}
-(void) Uploadexceptionlog: (nsnotification *) Note
{
Here to do the corresponding crash processing
}
@end
All of these are thrown after a crash, throw a message, and then you can do a crash in any place. Can be changed according to their own architectural requirements.
Crash Collection in iOS