ETW - 닷넷 프레임워크 기반의 응용 프로그램을 위한 명령행 도구 etrace 소개
물론, ETW consumer를 직접 만들어도 되지만,
C# - ETW 관련 Win32 API 사용 예제 코드 (3) ETW Consumer 구현
; https://www.sysnet.pe.kr/2/0/12299
ETW(Event Tracing for Windows)를 이용한 닷넷 프로그램의 내부 이벤트 활용
; https://www.sysnet.pe.kr/2/0/12244
일반적인 목적이라면 그냥 잘 만들어진 도구를 사용해도 좋습니다. ^^
goldshtn / etrace
; https://github.com/goldshtn/etrace
예를 들어,
이전 글에 소개했던 '조용히 사라진 예외'를 파악하는 용도로 실행하려면 다음과 같은 식으로 명령행에서 실행하면 됩니다.
etrace --clr Exception --event ExceptionCatch/Start --pid 12144
여기서 미스터리한 옵션 값은 "--clr"과 "--event"인데요. 우선 "--clr" 옵션에 줄 수 있는 값은 etrace 자체에서 제공하므로 쉽게 파악할 수 있습니다.
C:\temp\etrace\bin\Debug> etrace --list CLR
Supported CLR keywords (use with --clr):
None
GC
GCHandle
Binder
Loader
Jit
NGen
StartEnumeration
StopEnumeration
Security
AppDomainResourceManagement
JitTracing
Interop
Contention
Exception
Threading
JittedMethodILToNativeMap
OverrideAndSuppressNGenEvents
SupressNGen
Type
GCHeapDump
GCSampledObjectAllocationHigh
GCHeapSurvivalAndMovement
GCHeapCollect
GCHeapAndTypeNames
GCHeapSnapshot
GCSampledObjectAllocationLow
GCAllObjectAllocation
PerfTrack
Stack
ThreadTransfer
Debugger
Monitoring
Codesymbols
Default
All
문제는 "--event" 이후에 올 문자열 조건인데요, 이것을 알기 위해서는 manifest 파일을 열어 봐야 합니다.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\CLR-ETW.man
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\CLR-ETW.man
이 파일에 보면 "CLR Exception events"라는 목록이 나오는데,
...[생략]...
<!-- CLR Exception events -->
<event value="80" version="0" level="win:Informational" opcode="win:Start" task="Exception" symbol="ExceptionThrown" message="$(string.RuntimePublisher.ExceptionExceptionThrownEventMessage)"/>
<event value="80" version="1" level="win:Error" template="Exception" keywords="ExceptionKeyword MonitoringKeyword" opcode="win:Start" task="Exception" symbol="ExceptionThrown_V1" message="$(string.RuntimePublisher.ExceptionExceptionThrown_V1EventMessage)"/>
<event value="250" version="0" level="win:Informational" template="ExceptionHandling" keywords="ExceptionKeyword" opcode="win:Start" task="ExceptionCatch" symbol="ExceptionCatchStart" message="$(string.RuntimePublisher.ExceptionExceptionHandlingEventMessage)"/>
<event value="251" version="0" level="win:Informational" keywords="ExceptionKeyword" opcode="win:Stop" task="ExceptionCatch" symbol="ExceptionCatchStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/>
<event value="252" version="0" level="win:Informational" template="ExceptionHandling" keywords="ExceptionKeyword" opcode="win:Start" task="ExceptionFinally" symbol="ExceptionFinallyStart" message="$(string.RuntimePublisher.ExceptionExceptionHandlingEventMessage)"/>
<event value="253" version="0" level="win:Informational" keywords="ExceptionKeyword" opcode="win:Stop" task="ExceptionFinally" symbol="ExceptionFinallyStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/>
<event value="254" version="0" level="win:Informational" template="ExceptionHandling" keywords="ExceptionKeyword" opcode="win:Start" task="ExceptionFilter" symbol="ExceptionFilterStart" message="$(string.RuntimePublisher.ExceptionExceptionHandlingEventMessage)"/>
<event value="255" version="0" level="win:Informational" keywords="ExceptionKeyword" opcode="win:Stop" task="ExceptionFilter" symbol="ExceptionFilterStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/>
<event value="256" version="0" level="win:Informational" keywords="ExceptionKeyword" opcode="win:Stop" task="Exception" symbol="ExceptionThrownStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/>
...[생략]...
보는 바와 같이 "task"에 해당하는 것이 "--clr"의 옵션 값이고, "symbol"에 해당하는 것이 "--event"의 옵션" 값 중 일부임을 알 수 있습니다.
task="ExceptionCatch"의 문자열을 그대로 --clr 옵션에 지정
--clr ExceptionCatch
symbol="ExceptionCatchStart"의 문자열 중 task의 문자열을 기준으로 --event 옵션에 지정
--event ExceptionCatch/Start
자, 그럼 좀 더 내려가서 해당 manifest 파일은 어떻게 구할 수 있을까요? 사실 모든 ETW Provider들이 저렇게 별도의 manifest 파일을 유지하는 것은 아닙니다. 가령 그냥 바이너리 파일의 리소스로 포함시키는 경우도 있는데 일일이 그런 정보를 찾아내야 한다는 것은 좀 말이 안 되긴 합니다. 다행히 이에 대해 검색해 보면 해결책이 나옵니다. ^^
Retrieve ETW Provider Manifest for a registered provider
; https://stackoverflow.com/questions/24804293/retrieve-etw-provider-manifest-for-a-registered-provider
그래서 원하는 ETW의 Provider 이름이나 GUID 값을 알고 있다면
perfview.exe(
https://github.com/microsoft/perfview/releases/)의 도움으로 알아내는 것이 가능합니다.
PerfView /noGui userCommand DumpRegisteredManifest {e13c0d23-ccbc-4e12-931b-d9cc2eee27e4}
PerfView /noGui userCommand DumpRegisteredManifest Microsoft-Windows-DotNETRuntime
그럼 동일한 폴더에 manifest 파일 정보를 담은 xml 파일이 생성되므로 그것을 참조해 etrace의 옵션 값으로 쓸 수 있습니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]