Backtrace — 예외까지 이어지는 동적 호출 스택
Backtrace — 예외까지 이어지는 동적 호출 스택
프로그램에서 예외가 터졌을 때 '어디를 거쳐 여기까지 왔는지'를 알려주는 게 백트레이스(backtrace)예요. Raku의 Backtrace 타입은 예외가 발생한 지점까지 이어지는 동적 호출 스택을 담고 있어요. Backtrace::Frame 객체들의 리스트로 구성되죠.
class Backtrace {}
본문
Backtrace는 동적 호출 스택을 담아요. 보통 예외가 던져진 지점까지의 호출 경로를 말하고, Backtrace::Frame 객체들의 리스트예요. 기본 문자열화는 불필요하거나 혼란스러운 프레임(예: &die 같은 루틴)을 숨겨요. 리스트이므로 개별 요소에도 접근할 수 있어요.
sub zipi { { { die "Something bad happened" }() }() };
try {
zipi;
}
if ($!) {
say $!.backtrace[*-1].raku;
}
이 코드는 리스트의 마지막 프레임, 즉 사건이 일어난 지점을 가리키는 프레임을 출력해요.
메서드
method new
multi method new()
multi method new(Int:D $offset)
multi method new(Mu \ex)
multi method new(Mu \ex, Int:D $offset)
multi method new(List:D $bt)
multi method new(List:D $bt, Int:D $offset)
호출 위치를 백트레이스의 출발점으로 삼아 새 백트레이스를 만들어요. $offset을 넘기면 그 오프셋을 사용해요. 객체나 리스트(이미 리스트 형태의 백트레이스를 담은)를 넘기면 현재 코드 대신 그 값을 사용해요.
my $backtrace = Backtrace.new;
method gist
multi method gist(Backtrace:D:)
"Backtrace(42 frames)" 형태의 문자열을 돌려줘요. 숫자는 list 메서드로 얻을 수 있는 프레임 수를 나타내요.
method Str
multi method Str(Backtrace:D:)
백트레이스의 간결한 문자열 표현을 돌려줘요. is hidden-from-backtrace로 표시된 루틴과, 구현에 따라서는 setting의 일부 루틴도 생략해요.
my $backtrace = Backtrace.new;
say $backtrace.Str;
method next-interesting-index
method next-interesting-index(Backtrace:D: Int $idx = 0, :$named, :$noproto, :$setting)
숨겨진 프레임과 기타 설정을 고려한 뒤, 다음 '흥미로운' 프레임의 인덱스를 돌려줘요. $named는 이름이 있는 것만, $noproto는 proto를 숨기고, $setting은 setting으로 간주되는 것을 숨겨요.
sub zipi { { { die "Something bad happened" }() }() };
try zipi;
say $!.backtrace.next-interesting-index; # OUTPUT: «2»
say $!.backtrace.next-interesting-index( :named ); # OUTPUT: «4»
method outer-caller-idx
method outer-caller-idx(Backtrace:D: Int $startidx)
현재 프레임을 부른 프레임들의 인덱스를 리스트로 돌려줘요.
sub zipi { { { die "Something bad happened" }() }() };
try zipi;
say $!.backtrace.outer-caller-idx( 4 ); # OUTPUT: «[6]»
method nice
method nice(Backtrace:D: :$oneline)
백트레이스를 흥미로운 프레임들의 리스트로 돌려줘요. :$oneline이 설정되면 첫 프레임에서 멈춰요.
sub zipi { { { die "Something bad happened" }() }() };
try zipi;
say $!.backtrace.nice( :oneline ) if $!;
# OUTPUT: « in sub zipi at /tmp/... line 1»
method full
multi method full(Backtrace:D:)
숨겨진 프레임, 컴파일러 특유 프레임, setting 프레임까지 포함한 전체 문자열 표현을 돌려줘요.
method list
multi method list(Backtrace:D:)
이 백트레이스의 Backtrace::Frame 객체 리스트를 돌려줘요.
method summary
method summary(Backtrace:D: --> Str:D)
!.is-hidden && (.is-routine || !.is-setting) 필터를 적용한 요약 문자열 표현을 돌려줘요.
sub inner { say Backtrace.new.summary }
sub outer { inner; }
outer;
이 프로그램의 결과는 아래와 같아요:
in method new at SETTING::src/core.c/Backtrace.rakumod line 85
in sub inner at test.raku line 1
in sub outer at test.raku line 2
in block <unit> at test.raku line 3
method concise
method concise(Backtrace:D:)
!.is-hidden && .is-routine && !.is-setting 필터를 적용한 간결한 문자열 표현을 돌려줘요. summary보다 더 엄격하게 루틴만 남겨요.
sub inner { say Backtrace.new.concise }
sub outer { inner; }
outer;
결과:
in sub inner at test.raku line 1
in sub outer at test.raku line 2
method map
multi method map(Backtrace:D: &block --> Seq:D)
각 요소에 대해 &block을 호출하고 반환값을 시퀀스로 모아 돌려줘요.
sub inner { Backtrace.new.map({ say "{$_.file}: {$_.line}" }); }
sub outer { inner; }
outer;
결과:
SETTING::src/core.c/Backtrace.rakumod: 85
SETTING::src/core.c/Backtrace.rakumod: 85
test.raku: 1
test.raku: 2
test.raku: 3
test.raku: 1
method flat
multi method flat(Backtrace:D:)
list와 동일한 백트레이스를 돌려줘요.