ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] StackTrace 읽기
    우아한 테크코스/테크코스 2020. 3. 5. 13:05
    반응형

    Stack Trace란?

     응용 프로그램(Application)이 시작된 시점부터 프로그램 내에서 현재 실행 위치까지의 메서드 호출 목록

     예외가 발생했을 때까지 프로그램의 위치와 진행정도를 나타내기 위해 예외가 발생하면 JVM에 의해 자동으로 생성

     가장 최근의 메서드 호출이 목록에 맨 위에 있음

    printStackTrace

     예외의 메서드를 호출하여 StackTrace를 표준 오류로 인쇄할 수 있음

    public class Throwable implements Serializable {
        // 전략 ...
        public void printStackTrace() {
            printStackTrace(System.err);
        }
        // 후략 ...
    }

     StackTrace는 java.lang.StackTraceElement 클래스 배열로 캡슐화됨(JDK 1.4 ~)

    - java.lang.StackTraceElement 클래스 배열 : Throwable.getStackTrace()로 반환된 StackTrace 요소 배열

        > 각 요소는 단일 스택 프레임

        > 스택의 상단에 있는 것을 제외한 모든 스택 프레임은 메서드 호출

        > 스택 상단 프레임은 스택 추적이 생성된 실행 지점 - 일반적으로 throwable이 생성된 지점

    public class Throwable implements Serializable {
        // 전략 ...
        public void printStackTrace(PrintStream s) {
            printStackTrace(new WrappedPrintStream(s));
        }
        
        private void printStackTrace(PrintStreamOrWriter s) {
            // Guard against malicious overrides of Throwable.equals by
            // using a Set with identity equality semantics.
            Set<Throwable> dejaVu =
                Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
            dejaVu.add(this);
    
            synchronized (s.lock()) {
                // Print our stack trace
                s.println(this);
                StackTraceElement[] trace = getOurStackTrace();
                for (StackTraceElement traceElement : trace)
                    s.println("\tat " + traceElement);
    
                // Print suppressed exceptions, if any
                for (Throwable se : getSuppressed())
                    se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
    
                // Print cause, if any
                Throwable ourCause = getCause();
                if (ourCause != null)
                    ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
            }
        }
        
        // 중략 ...
        
        public StackTraceElement[] getStackTrace() {
            return getOurStackTrace().clone();
        }
    
        private synchronized StackTraceElement[] getOurStackTrace() {
            // Initialize stack trace field with information from
            // backtrace if this is the first call to this method
            if (stackTrace == UNASSIGNED_STACK ||
                (stackTrace == null && backtrace != null) /* Out of protocol state */) {
                int depth = getStackTraceDepth();
                stackTrace = new StackTraceElement[depth];
                for (int i=0; i < depth; i++)
                    stackTrace[i] = getStackTraceElement(i);
            } else if (stackTrace == null) {
                return UNASSIGNED_STACK;
            }
            return stackTrace;
        }
        /// 후략 ...
    }

     java.lang.StackTraceElement 클래스 : StackTrace 요소

    - 지정된 실행 지점을 나타내는 스택 추적 요소 생성

    public final class StackTraceElement implements java.io.Serializable {
        // Normally initialized by VM (public constructor added in 1.5)
        private String declaringClass;
        private String methodName;
        private String fileName;
        private int    lineNumber;
        
        public StackTraceElement(String declaringClass, String methodName,
                                 String fileName, int lineNumber) {
            this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null");
            this.methodName     = Objects.requireNonNull(methodName, "Method name is null");
            this.fileName       = fileName;
            this.lineNumber     = lineNumber;
        }
        // 후략 ...
    }

    StackTrace를 String으로 변환

     디버깅 목적으로 StackTrace를 String 로그 파일에 기록할 수 있도록 변환하기

    import java.io.PrintWriter;
    import java.io.StringWriter;
    
    // 생략
        try {
            // 생략
        } catch(Exception e) {
            StringWriter outError = new StringWriter();
            e.printStackTrace(new PrintWriter(outError));
            String errorString = outError.toString();
            // Do whatever you want with the errorString
        }
    // 생략

    StackTrace 추적해보기

    import java.util.ArrayList;
    import java.util.List;
    import org.junit.jupiter.api.Test;
    
    public class jamieTest {
    
        @Test
        void stacktrace() {
            try {
                List<String> stringList = new ArrayList<>();
                stringList.get(1);	// 13번째 줄
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

     해석해보자면 run을 하고, jamieTest.java의 13번째 줄을 호출했고, ArrayList get 메서드를 호출해서 rangeCheck를 하다가 IndexOutOfBoundsException이 발생!

    // 인텔리제이 보정(접어두기)
    java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
        at java.util.ArrayList.rangeCheck(ArrayList.java:657)
        at java.util.ArrayList.get(ArrayList.java:433)
        at jamie.domain.jamieTest.stacktrace(jamieTest.java:13)
        at java.util.ArrayList.forEach(ArrayList.java:1257)
        at java.util.ArrayList.forEach(ArrayList.java:1257)
        at java.lang.Thread.run(Thread.java:748)
    
    // 전체
    java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
        at java.util.ArrayList.rangeCheck(ArrayList.java:657)
        at java.util.ArrayList.get(ArrayList.java:433)
        at jamie.domain.jamieTest.stacktrace(jamieTest.java:13)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
        at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
        at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
        at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
        at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
        at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
        at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
        at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:205)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:201)
        at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
        at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
        at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
        at java.util.ArrayList.forEach(ArrayList.java:1257)
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
        at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
        at java.util.ArrayList.forEach(ArrayList.java:1257)
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
        at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
        at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:92)
        at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$100(JUnitPlatformTestClassProcessor.java:77)
        at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:73)
        at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
        at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
        at com.sun.proxy.$Proxy2.stop(Unknown Source)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:131)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:155)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:137)
        at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
        at java.lang.Thread.run(Thread.java:748)

    출처 : https://en.wikibooks.org/wiki/Java_Programming/Stack_trace

     

     

    반응형

    댓글

Designed by Tistory.