성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
[공진영] 안녕하세요 좋은글 감사합니다. 현재 제가 wpf로 관제 모...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - ETW 이벤트의 Keywords에 속한 EventId 구하는 방법 (1) PInvoke</h1> <p> 일례로 예전 ETW 글에서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - (.NET Core 2.2부터 가능한) 프로세스 내부에서 CLR ETW 이벤트 수신 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12474'>https://www.sysnet.pe.kr/2/0/12474</a> </pre> <br /> <a target='tab' href='https://gist.github.com/jdu2600/e99c95d87ac20a44c47068b71caf333b'>"Microsoft-Windows-DotNETRuntime" ETW 제공자</a>의 Exception 키워드(keyword) 범주에 속하는 이벤트를,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .NET runtime exception events ; <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/fundamentals/diagnostics/runtime-exception-events'>https://docs.microsoft.com/en-us/dotnet/fundamentals/diagnostics/runtime-exception-events</a> </pre> <br /> 활성화시켰습니다. 그리고 해당 키워드에 속한 이벤트가 여러 개 있는데 그것들에도 각각 "Event ID"라는 것이 부여되어 있어 식별이 가능합니다. 가령 Exception 범주의 경우 위의 문서에 나오듯이 아래와 같은 ID로 구별되는 이벤트가 발생합니다.<br /> <br /> <ul> <li>ExceptionThrown_V1 - Event ID == 80</li> <li>ExceptionCatchStart - Event ID == 250</li> <li>ExceptionCatchStop - Event ID == 251</li> <li>ExceptionFinallyStart - Event ID == 252</li> <li>ExceptionFinallyStop - Event ID == 253</li> <li>ExceptionFilterStart - Event ID == 254</li> <li>ExceptionFilterStop - Event ID == 255</li> <li>ExceptionThrownStop - Event ID == 256</li> </ul> <br /> 사실 이 정보들은 ETW manifest 파일에 기록돼 있긴 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\Windows\Microsoft.NET\Framework\v4.0.30319\CLR-ETW.man C:\Windows\Microsoft.NET\Framework64\v4.0.30319\CLR-ETW.man </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <instrumentationManifest xmlns="http://schemas.microsoft.com/win/2004/08/events"> <instrumentation xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"> <events xmlns="http://schemas.microsoft.com/win/2004/08/events"> <!--CLR Runtime Publisher--> <provider name="Microsoft-Windows-DotNETRuntime" guid="{e13c0d23-ccbc-4e12-931b-d9cc2eee27e4}" symbol="MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER" resourceFileName="%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\clretwrc.dll" messageFileName="%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\clretwrc.dll"> <!--Keywords--> <keywords> <keyword name="GCKeyword" mask="0x1" message="$(string.RuntimePublisher.GCKeywordMessage)" symbol="CLR_GC_KEYWORD"/> ...[생략]... <keyword <span style='color: blue; font-weight: bold'>name="ExceptionKeyword" mask="0x8000"</span> message="$(string.RuntimePublisher.ExceptionKeywordMessage)" symbol="CLR_EXCEPTION_KEYWORD"/> ...[생략]... </keywords> ..[생략]... <events> <!-- CLR GC events, value reserved from 0 to 39 and 200 to 239 --> <!-- Note the opcode's for GC events do include 0 to 9 for backward compatibility, even though they don't mean what those predefined opcodes are supposed to mean --> <event value="1" version="0" level="win:Informational" template="GCStart" keywords="GCKeyword" opcode="win:Start" task="GarbageCollection" symbol="GCStart" message="$(string.RuntimePublisher.GCStartEventMessage)"/> ..[생략]... <!-- CLR Exception events --> <event value="80" version="0" level="win:Informational" opcode="win:Start" task="Exception" symbol="ExceptionThrown" message="$(string.RuntimePublisher.ExceptionExceptionThrownEventMessage)"/> <event <span style='color: blue; font-weight: bold'>value="80"</span> version="1" level="win:Error" template="Exception" <span style='color: blue; font-weight: bold'>keywords="ExceptionKeyword MonitoringKeyword"</span> opcode="win:Start" task="Exception" symbol="ExceptionThrown_V1" message="$(string.RuntimePublisher.ExceptionExceptionThrown_V1EventMessage)"/> <event <span style='color: blue; font-weight: bold'>value="250"</span> version="0" level="win:Informational" template="ExceptionHandling" <span style='color: blue; font-weight: bold'>keywords="ExceptionKeyword"</span> opcode="win:Start" task="ExceptionCatch" symbol="ExceptionCatchStart" message="$(string.RuntimePublisher.ExceptionExceptionHandlingEventMessage)"/> <event <span style='color: blue; font-weight: bold'>value="251"</span> version="0" level="win:Informational" <span style='color: blue; font-weight: bold'>keywords="ExceptionKeyword"</span> opcode="win:Stop" task="ExceptionCatch" symbol="ExceptionCatchStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/> <event <span style='color: blue; font-weight: bold'>value="252"</span> version="0" level="win:Informational" template="ExceptionHandling" <span style='color: blue; font-weight: bold'>keywords="ExceptionKeyword"</span> opcode="win:Start" task="ExceptionFinally" symbol="ExceptionFinallyStart" message="$(string.RuntimePublisher.ExceptionExceptionHandlingEventMessage)"/> <event <span style='color: blue; font-weight: bold'>value="253"</span> version="0" level="win:Informational" <span style='color: blue; font-weight: bold'>keywords="ExceptionKeyword"</span> opcode="win:Stop" task="ExceptionFinally" symbol="ExceptionFinallyStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/> <event <span style='color: blue; font-weight: bold'>value="254"</span> version="0" level="win:Informational" template="ExceptionHandling" <span style='color: blue; font-weight: bold'>keywords="ExceptionKeyword"</span> opcode="win:Start" task="ExceptionFilter" symbol="ExceptionFilterStart" message="$(string.RuntimePublisher.ExceptionExceptionHandlingEventMessage)"/> <event <span style='color: blue; font-weight: bold'>value="255"</span> version="0" level="win:Informational" <span style='color: blue; font-weight: bold'>keywords="ExceptionKeyword"</span> opcode="win:Stop" task="ExceptionFilter" symbol="ExceptionFilterStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/> <event <span style='color: blue; font-weight: bold'>value="256"</span> version="0" level="win:Informational" <span style='color: blue; font-weight: bold'>keywords="ExceptionKeyword"</span> opcode="win:Stop" task="Exception" symbol="ExceptionThrownStop" message="$(string.RuntimePublisher.ExceptionExceptionHandlingNoneEventMessage)"/> <!-- CLR Contention events --> ..[생략]... </events> </provider> ..[생략]... </resources> </localization> </instrumentationManifest> </pre> <br /> 그래서 Event ID 목록을 man 파일로부터 구하는 것이 가능하지만, 혹시 프로그래밍으로도 가능할까요? 아쉽게도 "<a target='tab' href='https://www.sysnet.pe.kr/2/0/12474'>C# - (.NET Core 2.2부터 가능한) 프로세스 내부에서 CLR ETW 이벤트 수신</a>" 글에서 사용한 EventSource 타입으로는 해당 이벤트 목록을 구할 수 공식적인 방법이 없습니다.<br /> <br /> 대안으로 생각해 볼 수 있는 것이 지난 글의,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - ETW 관련 Win32 API 사용 예제 코드 (1) ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/12292#trace_event_cs'>https://www.sysnet.pe.kr/2/0/12292#trace_event_cs</a> </pre> <br /> TraceEventSession.cs 파일처럼 P/Invoke 호출을 해보는 건데요, 그래서 아래의 함수를 더 추가하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > TdhEnumerateManifestProviderEvents function (tdh.h) ; <a target='tab' href='https://docs.microsoft.com/en-us/windows/win32/api/tdh/nf-tdh-tdhenumeratemanifestproviderevents'>https://docs.microsoft.com/en-us/windows/win32/api/tdh/nf-tdh-tdhenumeratemanifestproviderevents</a> TRACE_PROVIDER_INFO structure (tdh.h) ; <a target='tab' href='https://docs.microsoft.com/en-us/windows/win32/api/tdh/ns-tdh-trace_provider_info'>https://docs.microsoft.com/en-us/windows/win32/api/tdh/ns-tdh-trace_provider_info</a> EVENT_DESCRIPTOR structure (evntprov.h) ; <a target='tab' href='https://docs.microsoft.com/en-us/windows/win32/api/evntprov/ns-evntprov-event_descriptor'>https://docs.microsoft.com/en-us/windows/win32/api/evntprov/ns-evntprov-event_descriptor</a> </pre> <br /> 다음과 같이 코딩해 특정 Keyword에 해당하는 이벤트 ID 목록을 구하는 것이 가능합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > EVENT_DESCRIPTOR[] eventDescs = GetEventProviders(guid); // guid == e13c0d23-ccbc-4e12-931b-d9cc2eee27e4 ("Microsoft-Windows-DotNETRuntime") Console.WriteLine("EventIDs at Keyword == Exception: "); foreach (EVENT_DESCRIPTOR desc in eventDescs) { if ((desc.Keyword & 0x8000) == 0x8000) // 0x8000 == Exception keyword mask { Console.WriteLine("\t" + desc); } } /* 출력 결과 EventIDs at Keyword == Exception: 250 at 32768 251 at 32768 252 at 32768 253 at 32768 254 at 32768 255 at 32768 256 at 32768 80 at 8589967360 */ private static EVENT_DESCRIPTOR[] GetEventProviders(Guid guid) { uint bufSize = 0; int result = 0; IntPtr ptr = IntPtr.Zero; try { do { if (bufSize != 0) { ptr = Marshal.AllocHGlobal((int)bufSize); } result = NativeMethods.TdhEnumerateManifestProviderEvents(ref guid, ptr, ref bufSize); if (ptr != IntPtr.Zero && result != 0) { Marshal.FreeHGlobal(ptr); ptr = IntPtr.Zero; } } while (result == (int)TDHSTATUS.<a target='tab' href='https://www.sysnet.pe.kr/2/0/13206#17132'>ERROR_INSUFFICIENT_BUFFER</a>); /* PROVIDER_EVENT_INFO */ int offset = 0; uint numberOfEvents = (uint)Marshal.ReadInt32(ptr, 0); offset += sizeof(uint); // unused // uint reserved = (uint)Marshal.ReadInt32(ptr, offset); offset += sizeof(uint); EVENT_DESCRIPTOR[] descs = new EVENT_DESCRIPTOR[numberOfEvents]; int descSize = Marshal.SizeOf(descs[0]); int nDesc = (int)((bufSize - offset) / descSize); Debug.Assert(numberOfEvents == nDesc); for (int i = 0; i < nDesc; i++) { descs[i] = (EVENT_DESCRIPTOR)<a target='tab' href='https://www.sysnet.pe.kr/2/0/12445'>Marshal.PtrToStructure</a>(ptr + (offset + i * descSize), typeof(EVENT_DESCRIPTOR)); } return descs; } finally { if (ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); } } } </pre> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1751&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, PowerShell의 <a target='tab' href='https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.diagnostics/get-winevent'>Get-WinEvent</a>를 명령어를 이용해서도 구할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > PS C:\temp> (Get-WinEvent -ListProvider Microsoft-Windows-DotNETRuntime).Events | Format-Table ID, Keywords Id Keywords -- -------- ...[생략]... 80 {MonitoringKeyword, ExceptionKeyword} ...[생략]... 250 {ExceptionKeyword} 251 {ExceptionKeyword} 252 {ExceptionKeyword} 253 {ExceptionKeyword} 254 {ExceptionKeyword} 255 {ExceptionKeyword} 256 {ExceptionKeyword} </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
4173
(왼쪽의 숫자를 입력해야 합니다.)