Wie druckt man einen Stack-Trace zur Konsole / zum Log in Cocoa aus?

293

Ich möchte die Anrufverfolgung an bestimmten Punkten protokollieren, z. B. bei fehlgeschlagenen Zusicherungen oder nicht erfassten Ausnahmen.

Robottobor
quelle

Antworten:

544
 NSLog(@"%@",[NSThread callStackSymbols]);

Dieser Code funktioniert in jedem Thread.

Smokris
quelle
14
Neu in Mac OS X 10.6, das nicht existierte, als diese Frage ursprünglich gestellt wurde. Verwenden Sie für Pre-Snow-Leopard die Funktionen backtraceund backtrace_symbols; Siehe die Manpage backtrace (3).
Peter Hosey
6
Nur unter iOS 4.0 und höher.
Danra
Vielen Dank! Gibt es eine Möglichkeit, dies so zu gestalten, dass nur die Stapelverfolgung gedruckt wird, z. B. 6 Ebenen tiefer anstatt vollständig?
Sudo
9000, backtrace/backtrace_symbolsdirekt verwenden
dymv
34

Die Antwort von n13 hat nicht ganz funktioniert - ich habe sie leicht modifiziert, um dies zu erreichen

#import <UIKit/UIKit.h>

#import "AppDelegate.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        int retval;
        @try{
            retval = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
        @catch (NSException *exception)
        {
            NSLog(@"Gosh!!! %@", [exception callStackSymbols]);
            @throw;
        }
        return retval;
    }
}
Zayin Krige
quelle
4
Gah ... Apple sollte dies zumindest bei der Entwicklung einer Anwendung zum Standard machen. Eine Reihe von Speicheradressen ist ... archaisch
Russ
Ich habe Ihre Verbesserungen in meine Antwort aufgenommen. Ich habe das vor ARC gemacht. Vielen Dank.
n13
1
Dies funktioniert nicht in allen Situationen. Dies ist ein besserer Ansatz, wenn Sie alle nicht erfassten Ausnahmen abfangen möchten: codereview.stackexchange.com/questions/56162/… (Der Code in dieser Frage ist etwas überkompliziert, kann aber auch mehr als nur die Aufrufstapelsymbole protokollieren.)
nhgrif
Sie können hinzufügen, NSLog(@"[Error] - %@ %@", exception.name, exception.reason);wenn Sie die tatsächliche Ausnahme auch möchten
Corentin S.
9

Cocoa protokolliert den Stack-Trace bereits bei nicht erfassten Ausnahmen in der Konsole, obwohl es sich nur um Rohspeicheradressen handelt. Wenn Sie symbolische Informationen in der Konsole wünschen, gibt es einen Beispielcode von Apple.

Wenn Sie an einer beliebigen Stelle in Ihrem Code eine Stapelverfolgung generieren möchten (und sich auf Leopard befinden), lesen Sie die Manpage zur Rückverfolgung. Vor Leopard mussten Sie tatsächlich den Call-Stack selbst durchsuchen.

vt.
quelle
6
Anscheinend in iOS 4 verfügbar, aber nicht in 3.2. Folgendes habe ich verwendet, schamlos von der Backtrace-Manpage kopiert: #include <execinfo.h> ... void * callstack [128]; int i, Frames = Backtrace (Callstack, 128); char ** strs = backtrace_symbols (Callstack, Frames); für (i = 0; i <Frames; ++ i) {printf ("% s \ n", strs [i]); } free (strs);
mharper
Wenn es in HandleException aufgerufen wird, schreibt es die Ablaufverfolgung der Handlerfunktion selbst zurück, während [NSException callStackSymbols] den Stapel der Stelle anzeigt, an der die Ausnahme ausgelöst wurde. Wenn Sie jedoch "backtrace (...)" durch Folgendes ersetzen: "NSArray arr = [ex callStackReturnAddresses]; int frame = arr.count; for (i = 0; i <frame; ++ i) callstack [i] = ( void) [((NSNumber *) [arr objectAtIndex: i]) intValue]; " Sie erhalten den aktuellen Exception-Stack-Trace. So funktioniert [NSException callStackSymbols], nehme ich an: Die von ihnen zurückgegebenen Traces sind gleich und werden in beiden App-Aufrufen in der Version durch _mh_execute_header ersetzt.
Tertium
6

Dies sagt Ihnen ziemlich genau, was zu tun ist.

Im Wesentlichen müssen Sie die Ausnahmebehandlung für Anwendungen für die Protokollierung einrichten.

#import <ExceptionHandling/NSExceptionHandler.h>

[[NSExceptionHandler defaultExceptionHandler] 
                  setExceptionHandlingMask: NSLogUncaughtExceptionMask | 
                                            NSLogUncaughtSystemExceptionMask | 
                                            NSLogUncaughtRuntimeErrorMask]
Max Stewart
quelle
1
Beachten Sie jedoch, dass dies nur innerhalb eines registrierten Ausnahmebehandlers funktioniert (nicht z. B. in einem @ catch-Block)
Barry Wark
1

Im schnellen Druck folgendermaßen:

print("stack trace:\(Thread.callStackSymbols)")
Deepak
quelle