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.

Antworten:


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

Dieser Code funktioniert in jedem Thread.


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;
    }
}

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.


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]

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)")
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.