디버깅은 소프트웨어 개발의 모든 분야에서 필수적이며, 블록체인도 예외는 아닙니다. Rust 디버깅을 위해 사용되는 대부분의 도구는 Substrate에도 적용됩니다.
로깅 유틸리티
Rust의 로깅 API를 사용하여 런타임을 디버깅할 수 있습니다. 이를 위해 debug와 info를 포함한 여러 매크로를 사용할 수 있습니다.
예를 들어, 팔렛의 Cargo.toml 파일을 log 크레이트로 업데이트한 후에는 log::info!를 사용하여 콘솔에 로그를 남길 수 있습니다:
pubfndo_something(origin) ->DispatchResult {let who =ensure_signed(origin)?;let my_val:u32=777;Something::put(my_val); log::info!("called by {:?}", who); Self::deposit_event(RawEvent::SomethingStored(my_val, who));Ok(())}
Printable trait
Printable trait은 no_std와 std에서 런타임에서 출력하는 방법을 제공합니다. print 함수는 Printable trait를 구현한 모든 타입과 함께 작동합니다. Substrate는 기본적으로 몇 가지 타입 (u8, u32, u64, usize, &[u8], &str)에 대해 이 trait을 구현합니다. 또한 사용자 정의 타입에 대해서도 구현할 수 있습니다. 다음은 노드 템플릿을 기반으로 한 팔렛의 Error 타입에 대한 구현 예시입니다.
use sp_runtime::traits::Printable;use sp_runtime::print;
#[frame_support::pallet]pubmod pallet {// 팔렛의 에러들 #[pallet::error]pubenumError<T> {/// 값이 None인 경우NoneValue,/// 값이 최대치에 도달하여 더 이상 증가할 수 없는 경우StorageOverflow, }impl<T:Config> PrintableforError<T> {fnprint(&self) {match self {Error::NoneValue=>"잘못된 값".print(),Error::StorageOverflow=>"값이 초과되어 오버플로우 발생".print(), _ =>"잘못된 에러 케이스".print(), } } }}
/// 매개변수를 받지 않고, 스토리지 값을 증가시키려고 시도하고, 오류가 발생할 수 있음pubfncause_error(origin) -> dispatch::DispatchResult {// 서명된 것인지 확인하고 서명자를 가져옴. ensure_root와 ensure_none도 참고let _who =ensure_signed(origin)?;print!("내 테스트 메시지");matchSomething::get() {None=> {print(Error::<T>::NoneValue);Err(Error::<T>::NoneValue)? }Some(old) => {let new = old.checked_add(1).ok_or( {print(Error::<T>::StorageOverflow); Error::<T>::StorageOverflow })?;Something::put(new);Ok(()) }, }}
2020-01-01 tokio-blocking-driver DEBUG runtime 내 테스트 메시지 <-- str은 기본적으로 Printable을 구현합니다2020-01-01 tokio-blocking-driver DEBUG runtime 잘못된 값 <-- NoneValue의 사용자 정의 문자열2020-01-01 tokio-blocking-driver DEBUG runtime DispatchError2020-01-01 tokio-blocking-driver DEBUG runtime 82020-01-01 tokio-blocking-driver DEBUG runtime 0<--Errorenum 정의에서의 인덱스 값2020-01-01 tokio-blocking-driver DEBUG runtime NoneValue<-- 에러의 식별자 이름을 담고 있는 str
런타임에 출력 함수를 추가하면 디버그 코드가 포함된 Rust 및 Wasm 바이너리의 크기가 증가하므로 프로덕션에서는 필요하지 않습니다.
Substrate의 자체 Print 함수
레거시 사용 사례에 대해 Substrate는 Print 디버깅(또는 추적)을 위한 추가 도구를 제공합니다. print 함수를 사용하여 런타임 실행 상태를 로깅할 수 있습니다.
use sp_runtime::print;// --snip--pubfndo_something(origin) ->DispatchResult {print!("do_something 실행");let who =ensure_signed(origin)?;let my_val:u32=777;Something::put(my_val);print!("my_val 저장 후"); Self::deposit_event(RawEvent::SomethingStored(my_val, who));Ok(())}// --snip--