성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
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'>ETW(Event Tracing for Windows)를 C#에서 사용하는 방법</h1> <p> 윈도우 환경에서 사용할 수 있는 고속 로깅 방법이 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Application Analysis with Event Tracing for Windows (ETW) ; <a target='tab' href='http://www.codeproject.com/Articles/570690/Application-Analysis-with-Event-Tracing-for-Window'>http://www.codeproject.com/Articles/570690/Application-Analysis-with-Event-Tracing-for-Window</a> </pre> <br /> 오늘은 위의 글을 따라하면서 ETW를 C#에서 어떻게 사용할 수 있는지 간략하게 정리해 보겠습니다. ^^<br /> <br /> 우선, ETW 이벤트를 생산하는 측(Producer)을 Provider라 하고, ETW 이벤트를 사용하는 측(Consumer)과 해당 공급자의 로깅 기능을 on/off하라는 지시를 내리는 Controller가 있습니다. 여기서 Provider 작성은 2가지로 나뉘는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > - Classic provider: XP 윈도우도 지원 - Manifest-based provider: 비스타 이상에서만 지원 Writing Manifest-based Events ; <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/etw/writing-manifest-based-events'>https://learn.microsoft.com/en-us/windows/win32/etw/writing-manifest-based-events</a> </pre> <br /> 이 글에서는 비스타 이상에서만 가능한 매니페스트 기반의 제공자(provider) 유형으로 ETW를 사용해 볼텐데, 그 전에 준비물은 다음과 같습니다.<br /> <br /> <ul> <li>Visual Studio 2012 이상 (이 글에서는 2013으로 실습)</li> <li>Windows SDK 8.0 이상 (해당 SDK 내에 있는 Windows Performance Toolkit 설치)</li> </ul> <br /> 자, 그럼 시작해 볼까요? ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> 우선, 우리가 실습할 ETW 이벤트 유형은 단순히 메서드의 수행 시간을 남기는 것으로 하겠습니다. 대략 로그에 남길 속성을 정의하면 이 정도입니다.<br /> <br /> <ul> <li>[string] Context</li> <li>[string] MethodName</li> <li>[long] ExecutionTime</li> <li>[string] ParameterInfo</li> </ul> <br /> 물론, 여러분 나름대로 더 정의해서 써도 됩니다.<br /> <br /> 로그를 남길 사양을 준비했으니, 이를 명시해 주는 "Manifest" 파일을 작성해야 합니다. 일반적으로 확장자가 man으로 지정하는 XML 유형의 파일인데, 이를 손쉽게 GUI 상에서 만들어 줄 수 있는 도구가 "Windows Performance Toolkit"에 ecmangen.exe(Instrumentation manifest generation tool) 파일로 포함되어 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\Program Files (x86)\Windows Kits\8.1\bin\x64\ecmangen.exe C:\Program Files (x86)\Windows Kits\8.1\bin\x86\ecmangen.exe </pre> <br /> ecmangen 프로그램으로 만들어진 manifest 파일을 한번 보면 좀 더 이해가 빠를 수 있는데요. "<a target='tab' href='http://www.codeproject.com/Articles/570690/Application-Analysis-with-Event-Tracing-for-Window'>Application Analysis with Event Tracing for Windows (ETW)</a>" 글의 소스코드를 다운로드 받고 "\appanalysis_src\appanalysis_src\Common" 폴더에 보면 "FirstETW.man" 파일이 있으므로 이것을 ecmangen.exe에 로드해서 살펴보면 됩니다.<br /> <br /> ecmangen 프로그램에서 manifest 파일을 만드는 좀 더 자세한 설명은 그 프로그램의 "Help" / "Help Topic" 메뉴를 선택하면 "C:\Users\[사용자 계정]\AppData\Local\Temp\ECMangenReference.mht" 파일이 생성과 함께 열리면서 대략적인 실습 시나리오를 위주로 "Quick Start Guide"로 설명하고 있으니 이를 참고하시면 됩니다.<br /> <br /> 간단하게 우리가 원하는 메서드의 수행 시간을 로그로 남기는 manifest를 정의해 보면, "Events Section" 노드를 마우스 우측 버튼을 눌러 "New" / "Provider"를 선택해 다음의 정보를 입력합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Name: MyETWSampleProvider Symbol: Sample_Perf (여기 입력한 이름은 나중에 C# 클래스 명으로 사용됨) GUID: [이 예제에서는 {223f223d-b390-4126-a1c8-3926d1e5b891} 사용] Decoding file locations: Resources: sample.exe Messages: sample.exe </pre> <br /> 저장하면 다음과 같이 Provider노드가 생성되고,<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='etw_sample_1.png' src='/SysWebRes/bbs/etw_sample_1.png' /><br /> <br /> 생성된 "MyETWSampleProvider" 노드를 다시 마우스 우측 버튼을 눌러 "New" / "Template"을 선택해 다음의 정보를 입력하고 저장합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Name: Template_MethodPerfTrace Field attributes: Name: Context InType: win:UnicodeString OutType: xs:string Name: MethodName InType: win:UnicodeString OutType: xs:string Name: ExecutionTime InType: win:UInt64 OutType: xs:unsignedLong Name: ParameterInfo InType: win:UnicodeString OutType: xs:string </pre> <br /> 템플릿을 만들었으니, 이에 기반한 이벤트를 만드는데 역시 "MyETWSampleProvider" 노드를 마우스 우측 버튼을 눌러 "New" / "Event"를 선택해 다음의 정보를 입력하고 저장합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Symbol: Event_MethodPerfTrace Event ID: (임의의 값: 여기서는 1을 입력) Channel: [default 또는 적정한 값 선택, 예제에서는 default] Level: [default 또는 적정한 값 선택, 예제에서는 Informational] Task: [default 또는 적정한 값 선택, 예제에서는 default] Opcode: [default 또는 적정한 값 선택, 예제에서는 default] Template: [Provider에 포함된 Template 값, 여기서는 이전에 생성해 둔 Template_MethodPerfTrace 선택] </pre> <br /> manifest에 정의될 수 있는 값들의 관계를 간단하게 정리해 보면,<br /> <br /> <ul> <li>Provider 1개당 n개의 Template, Event 가능</li> <li>Event는 1:1로 Template과 매칭</li> <li>Event는 Template에 대한 매칭 뿐만 아니라, Channel, Level, Keywords, Opcodes를 할당할 수 있는데 그 정보들 역시 Provider에서 사용자 정의 가능</li> </ul> <br /> 여기서는 실습을 간단히 하기 위해 Channel, Level, Keywords, Opcodes는 생략하고 최소 정보인 Template과 Event만 정의해 본 것입니다.<br /> <br /> 여기까지 실습하고 etw_sample.man 파일로 저장하면 다음의 내용이 포함됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="UTF-16"?> <instrumentationManifest xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd" xmlns="http://schemas.microsoft.com/win/2004/08/events" xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:trace="http://schemas.microsoft.com/win/2004/08/events/trace"> <instrumentation> <events> <provider name="MyETWSampleProvider" guid="{223F223D-B390-4126-A1C8-3926D1E5B891}" symbol="Sample_Perf" resourceFileName="sample.exe" messageFileName="sample.exe"> <events> <event symbol="Event_MethodPerfTrace" value="1" version="0" level="win:Informational" template="Template_MethodPerfTrace"> </event> </events> <levels> </levels> <templates> <template tid="Template_MethodPerfTrace"> <data name="Context" inType="win:UnicodeString" outType="xs:string"> </data> <data name="MethodName" inType="win:UnicodeString" outType="xs:string"> </data> <data name="ExecutionTime" inType="win:UInt64" outType="xs:unsignedLong"> </data> <data name="ParameterInfo" inType="win:UnicodeString" outType="xs:string"> </data> </template> </templates> </provider> </events> </instrumentation> <localization> <resources culture="en-US"> <stringTable> <string id="level.Informational" value="Information"> </string> </stringTable> </resources> </localization> </instrumentationManifest> </pre> <br /> 생성된 manifest 파일은 "Message Compiler"를 통해 컴파일할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > mc etw_sample.man </pre> <br /> 위와 같이 실행하면, C/C++ 용의 헤더 파일과 함께 리소스 파일들이 생성됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > etw_sample.h etw_sample.rc etw_sampleTEMP.BIN MSG00001.bin </pre> <br /> 리소스 파일인 etw_sample.rc 파일은 내부적으로 etw_sampleTEMP.BIN, MSG00001.bin 파일을 포함합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > LANGUAGE 0x9,0x1 1 11 "MSG00001.bin" 1 WEVT_TEMPLATE "etw_sampleTEMP.BIN" </pre> <br /> 따라서, Resource Compiler를 이용해서 etw_sample.rc 파일을 컴파일하면 etw_sampleTEMP.BIN, MSG00001.bin 파일을 포함하는 바이너리 유형의 res 리소스 파일(여기서는 etw_sample.res)이 생성됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > rc etw_sample.rc </pre> <br /> 하지만, 우리는 C/C++이 아닌 C#으로 실습할 것이기 때문에 "Message Compiler"에 "-css" 옵션을 추가해 C# 네임스페이스를 지정해 컴파일해 줍니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > mc -css MyETWSampleProvider.PerfTrace etw_sample.man </pre> <br /> 그럼, etw_sample.h 파일 대신 etw_sample.cs 파일이 생성된다는 차이만 있을 뿐 그 외의 파일은 "-css" 옵션이 없을 때와 동일하게 생성됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > etw_sample.cs etw_sample.rc etw_sampleTEMP.BIN MSG00001.bin </pre> <br /> 생성된 cs 파일에는 친절하게도 ETW 로그를 남길 수 있는 public 접근 권한의 static 메서드를 포함하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ...[주석 영역 생략]... namespace <span style='color: blue; font-weight: bold'>MyETWSampleProvider.PerfTrace</span> { using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Diagnostics.Eventing; using Microsoft.Win32; using System.Runtime.InteropServices; using System.Security.Principal; public static class Sample_Perf { // // Provider MyETWSampleProvider Event Count 1 // internal static EventProviderVersionTwo m_provider = new EventProviderVersionTwo(new Guid("223f223d-b390-4126-a1c8-3926d1e5b891")); // // Task : eventGUIDs // // // Event Descriptors // private static EventDescriptor Event_MethodPerfTrace; static Sample_Perf() { unchecked { Event_MethodPerfTrace = new EventDescriptor(0x1, 0x0, 0x0, 0x4, 0x0, 0x0, (long)0x0); } } // // Event method for Event_MethodPerfTrace // <span style='color: blue; font-weight: bold'>public static bool EventWriteEvent_MethodPerfTrace(string Context, string MethodName, ulong ExecutionTime, string ParameterInfo)</span> { if (!m_provider.IsEnabled()) { return true; } return m_provider.TemplateTemplate_MethodPerfTrace(ref Event_MethodPerfTrace, Context, MethodName, ExecutionTime, ParameterInfo); } } internal class EventProviderVersionTwo : EventProvider { internal EventProviderVersionTwo(Guid id) : base(id) {} [StructLayout(LayoutKind.Explicit, Size = 16)] private struct EventData { [FieldOffset(0)] internal UInt64 DataPointer; [FieldOffset(8)] internal uint Size; [FieldOffset(12)] internal int Reserved; } internal unsafe bool TemplateTemplate_MethodPerfTrace( ref EventDescriptor eventDescriptor, string Context, string MethodName, ulong ExecutionTime, string ParameterInfo ) { int argumentCount = 4; bool status = true; if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords)) { byte* userData = stackalloc byte[sizeof(EventData) * argumentCount]; EventData* userDataPtr = (EventData*)userData; userDataPtr[0].Size = (uint)(Context.Length + 1)*sizeof(char); userDataPtr[1].Size = (uint)(MethodName.Length + 1)*sizeof(char); userDataPtr[2].DataPointer = (UInt64)(&ExecutionTime); userDataPtr[2].Size = (uint)(sizeof(long) ); userDataPtr[3].Size = (uint)(ParameterInfo.Length + 1)*sizeof(char); fixed (char* a0 = Context, a1 = MethodName, a2 = ParameterInfo) { userDataPtr[0].DataPointer = (ulong)a0; userDataPtr[1].DataPointer = (ulong)a1; userDataPtr[3].DataPointer = (ulong)a2; status = WriteEvent(ref eventDescriptor, argumentCount, (IntPtr)(userData)); } } return status; } } } </pre> <br /> 생성된 코드에 unsafe 키워드가 있기 때문에 이 코드를 사용할 프로젝트의 속성 창에서 unsafe 예약어를 허용(Allow unsafe code)해야 합니다. 또한, 다음과 같이 리소스 파일로 etw_sample.res를 포함하는 것도 잊으면 안 됩니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='etw_sample_2.png' src='/SysWebRes/bbs/etw_sample_2.png' /><br /> <br /> 이렇게 준비하면 남은 작업은 단지 로그를 남겨주는 정적 메서드를 호출하는 것으로 ETW 로깅을 수행할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Diagnostics; using System.Threading; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { CallTestMethod(2000); CallTestMethod(300); } private static void CallTestMethod(int sleep) { Guid guidContext = Guid.NewGuid(); Stopwatch st = new Stopwatch(); st.Start(); try { Thread.Sleep(sleep); } finally { st.Stop(); Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ", " + AppDomain.GetCurrentThreadId() + ", " + st.ElapsedMilliseconds); <span style='color: blue; font-weight: bold'>MyETWSampleProvider.PerfTrace.Sample_Perf.EventWriteEvent_MethodPerfTrace(guidContext.ToString(), "CallTestMethod", (ulong)st.ElapsedMilliseconds, "");</span> } } } } </pre> <br /> <hr style='width: 50%' /><br /> <br /> 이 상태에서 예제 프로젝트를 실행하면 MyETWSampleProvider.PerfTrace.Sample_Perf.EventWriteEvent_MethodPerfTrace의 코드에서 IsEnabled 메서드의 반환값이 false가 나오면서 아무런 이벤트도 기록하지 않습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public static bool EventWriteEvent_MethodPerfTrace(string Context, string MethodName, ulong ExecutionTime, string ParameterInfo) { if (!<span style='color: blue; font-weight: bold'>m_provider.IsEnabled()</span>) { return true; } return m_provider.TemplateTemplate_MethodPerfTrace(ref Event_MethodPerfTrace, Context, MethodName, ExecutionTime, ParameterInfo); } </pre> <br /> 즉, ETW 로깅 환경이 갖춰지지 않는 경우 응용 프로그램에 거의 부하가 없음을 의미합니다. ETW가 동작하려면 해당 EXE 프로그램이 동작하는 환경에 2가지 조건을 갖춰야 합니다.<br /> <br /> <span style='text-decoration: line-through'>우선, MyETWSampleProvider.PerfTrace.Sample_Perf 클래스를 사용하는 EXE 파일의 위치가 정확하게 설정된 etw_sample.man 파일이 필요합니다.</span> <br /> 우선, etw_sample.rc 파일이 컴파일된 etw_sample.res 리소스를 포함하는 모듈의 위치가 정확하게 설정된 etw_sample.man 파일이 필요합니다. (이글에서는 etw_sample.res 리소스를 ConsoleApplication1.exe에 포함시켰기 때문에 그 파일의 경로를 지정합니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="UTF-16"?> <instrumentationManifest ...[생략]...> <instrumentation> <events> <provider name="MyETWSampleProvider" guid="{223F223D-B390-4126-A1C8-3926D1E5B891}" symbol="Sample_Perf" <span style='color: blue; font-weight: bold'>resourceFileName="...[경로]\ConsoleApplication1.exe" messageFileName="...[경로]\ConsoleApplication1.exe"</span>> <events> <event symbol="Event_MethodPerfTrace" value="1" version="0" level="win:Informational" template="Template_MethodPerfTrace"> </event> </events> ...[생략]... </provider> </events> </instrumentation> ...[생략]... </instrumentationManifest> </pre> <br /> ETW를 사용하는 프로그램은 설치 시에 man 파일을 보유하고 있다가 위의 resourceFileName/messageFileName의 값을 (리소스를 포함한) 모듈이 있는 경로로 바꿔준 후 (비스타 이후부터 기본 설치된) wevutil.exe 프로그램을 이용해 (관리자 권한으로) 다음과 같이 ETW Provider를 등록해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [등록] wevtutil.exe im etw_sample.man [확인] xperf -providers | findstr "My" 223f223d-b390-4126-a1c8-3926d1e5b891 : MyETWSampleProvider [제거] wevtutil.exe um etw_sample.man </pre> <br /> 이렇게 등록해도 소스코드의 m_provider.IsEnabled는 여전히 false를 반환합니다. 왜냐하면 ETW는 해당 이벤트를 수집하도록 윈도우 시스템에 알려야 하기 때문입니다. 즉, ETW Controller가 Provider에게 로그를 남기라는 on/off 지시를 해야 하는 것입니다. 이를 위해 "Performance Analyzer"인 xperf.exe 프로그램을 다음과 같은 옵션으로 실행할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > xperf.exe -start [원하는 이름] -on [NameOfYourRegisteredProvider] E:\temp>xperf.exe -start MyETW -on MyETWSampleProvider </pre> <br /> 이렇게 시작하면 기본적으로 xperf.exe가 수행된 드라이브의 루트 드라이브에 user.etl 파일이 생성됩니다. (참고로, user.etl 파일은 잠기지 않습니다.) 기본 경로를 변경하고 싶다면, -f 옵션과 함께 명시할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > xperf.exe -start MyETW -on MyETWSampleProvider -f E:\temp\etw\user.etl </pre> <br /> 이렇게까지 해줘야 이제 비로소 "m_provider.IsEnabled" 코드는 true를 반환하게 되고 ETW에 로그를 남기게 됩니다. 그리고, ETW 로깅이 필요없어지면 다음과 같이 윈도우 시스템에 그 사실을 알려줍니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > E:\ConsoleApplication1\bin\Debug>xperf -stop MyETW The trace you have just captured "E:\temp\etw\user.etl" may contain personally identifiable information, including but not necessarily limit ed to paths to files accessed, paths to registry accessed and process names. Exa ct information depends on the events that were logged. Please be aware of this w hen sharing out this trace with other people. </pre> <br /> 생성된 etl 파일은 wpa.exe, (C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit 폴더에 있는) xperfview.exe 등을 이용해 볼 수 있습니다.<br /> <br /> <a name='perfview'></a> 여기서는 PerfView.exe를 이용할 텐데요. 다음의 경로에서 다운로드 받을 수 있습니다. (단일 exe 프로그램이므로 설치가 필요없습니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > PerfView (1.7.0) ; <a target='tab' href='http://www.microsoft.com/en-us/download/details.aspx?id=28567'>http://www.microsoft.com/en-us/download/details.aspx?id=28567</a> </pre> <br /> 실행하고 user.etl 파일을 열면 다음과 같이 예제 프로그램에서 남긴 ETW 로그를 확인할 수 있습니다. ^^<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='etw_sample_3.png' src='/SysWebRes/bbs/etw_sample_3.png' /><br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=899&boardid=331301885'>첨부 파일은 이 글의 실습 프로젝트를 포함</a>합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <a name='logman'></a> <br /> 기본 설치된 Vista 이상의 윈도우에는 xperf 프로그램이 없기 때문에, 이때는 간단하게 logman.exe를 사용할 수 있습니다. 다음은 logman.exe로 MyETWSampleProvider를 동작시키고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\><span style='color: blue; font-weight: bold'>logman start my -p {223f223d-b390-4126-a1c8-3926d1e5b891} -o mytest.etl -ets</span> The command completed successfully. </pre> <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:\><span style='color: blue; font-weight: bold'>logman stop my -ets</span> The command completed successfully. </pre> <br /> 역시 기본 설치된 Vista 이상의 윈도우에는 wpa.exe나 perfview.exe가 없으므로 내장된 tracerpt.exe를 통해 다음과 같이 분석할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp><span style='color: blue; font-weight: bold'>tracerpt mytest.etl</span> Input ---------------- File(s): mytest.etl 100.00% Output ---------------- DumpFile: dumpfile.xml Summary: summary.txt The command completed successfully. </pre> <br /> 그럼, 대략적인 정보를 알 수 있는 summary.txt와 모든 이벤트 로그를 포함한 dumpfile.xml이 생성됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> (지금부터는 시행착오에 대한 내용입니다.)<br /> <br /> ETW 코드를 호출하는 프로그램을 Windows Server 2003에서 실행하는 경우 다음과 같은 오류가 발생한다는 점을 잊으시면 안됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > D:\temp>ConsoleApplication1.exe 1, 4948, 1988 Unhandled Exception: System.TypeInitializationException: The type initializer for 'MyETWSampleProvider.PerfTrace.Sample_Perf' threw an exception. ---> System.PlatformNotSupportedException: This functionality is only supported in Windows Vista and above. at System.Diagnostics.Eventing.EventProvider.EtwRegister() at System.Diagnostics.Eventing.EventProvider..ctor(Guid providerGuid) at MyETWSampleProvider.PerfTrace.EventProviderVersionTwo..ctor(Guid id) at MyETWSampleProvider.PerfTrace.Sample_Perf..cctor() --- End of inner exception stack trace --- at MyETWSampleProvider.PerfTrace.Sample_Perf.EventWriteEvent_MethodPerfTrace(String Context, String MethodName, UInt64 ExecutionTime, String ParameterInfo) at ConsoleApplication1.Program.CallTestMethod(Int32 sleep) at ConsoleApplication1.Program.Main(String[] args) </pre> <br /> 자동 생성 코드인 Sample_Perf 클래스의 정적 생성자(cctor)에서 오류가 발생하기 때문에 2003에서도 실행되어야 하는 프로그램이라면 아예 Sample_Perf 자체를 접근하지 않도록 하는 예비 코드가 필요합니다.<br /> <br /> 아울러, 자동 생성 코드의 기반 클래스인 EventProvider 타입의 공식 지원은 .NET Framework 3.5부터라는 점도 잊지 마시고!<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .NET Framework Supported in: 4.5, 4, 3.5 .NET Framework Client Profile Supported in: 4, 3.5 SP1 </pre> <br /> <hr style='width: 50%' /><br /> <br /> PerfView.exe를 통해 etl 내용을 확인할 때 만약 다음과 같이 필드 값이 나오지 않는다면? (DataLength로만 사용자 로그 데이터의 길이를 보여주고 있습니다.)<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='etw_sample_4.png' src='/SysWebRes/bbs/etw_sample_4.png' /><br /> <br /> 이것은 "wevtutil.exe" 프로그램을 "im" 옵션으로 *.man 파일 등록 시 resourceFileName, messageFileName의 값에 리소스 파일이 포함된 모듈의 경로를 올바르지 않게 등록한 경우입니다.<br /> <br /> <span style='text-decoration: line-through'>참고로, etw_sample.cs 파일을 EXE 프로젝트가 아닌 DLL 유형의 클래스 라이브러리로 분리하는 경우라면 어떤 경로를 resourceFileName, messageFileName의 값에 설정해야 할까요? 이런 경우에도 여전히 중요한 경로는 EXE 파일입니다. 다른 경로를 적으시면 안됩니다. 즉, 여러분이 ETW를 사용한 라이브러리 성격의 프레임워크를 만들었다면 man 파일의 resourceFileName, messageFileName은 나중에 EXE를 만드는 개발자가 별도로 설정해 줘야 합니다. </span><br /> <br /> <hr style='width: 50%' /><br /> <br /> 간혹 ETW 로그를 남기는 ConsoleApplication1.exe 파일이 프로세스가 (비정상 종료된 경우) 종료되었는데도 불구하고 잠기는 경우가 있습니다. 왜냐하면, man 파일 내에 provider의 resource/message 파일명으로 해당 EXE를 지정했기 때문에 ETW 서비스는 이 EXE를 로드하기 때문입니다.<br /> <br /> ETW를 관장하는 서비스 프로세스는 윈도우에서 사용되는 svchost.exe이기 때문에 구분이 어려운데 그중에서 "EventLog(Windows Event Log)" 서비스를 호스팅하는 것을 찾으면 됩니다. (Process Explorer에서 찾는다면, 자식 프로세스로 audiodg.exe가 등록된 svchost.exe입니다.) 물론, 작업 관리자에서 강제 종료하지 마시고 그냥 NT 서비스 관리자에서 "Windows Event Log"를 재시작하시면 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> xperf로 provider의 등록 여부를 "xperf -providers | findstr "My"와 같이 실행하면 된다고 했는데요. Vista에서는 xperf.exe가 기본적으로 없으므로 이때는 내장 프로그램인 wevtutil.exe를 gp 옵션으로 사용하면 됩니다. 그런데, 다음과 같이 "Failed to..." 메시지가 나오면 정상적으로 등록되지 않은 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\Users\testusr> <span style='color: blue; font-weight: bold'>wevtutil gp MyETWSampleProvider</span> name: MyETWSampleProvider guid: 223f223d-b390-4126-a1c8-3926d1e5b891 helpLink: resourceFileName: c:\temp\bin\ConsoleApplication1.exe messageFileName: c:\temp\bin\ConsoleApplication1.exe Failed to get message property. The system cannot find the file specified. </pre> <br /> 즉, *.man 파일에 지정된 resourceFileName과 messageFileName의 파일명 경로가 잘못된 것입니다. 다시 잘 확인하고, "wevtutil.exe im ...." 옵션으로 등록해 주시면 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그 외에 참고할만한 링크를 정리해 봤습니다.<br /> <br /> man 파일의 경로를 EXE 프로젝트마다 바꿔주어야 하는 불편함이 있는데, 아래의 글에서는 msbuild에 이 과정을 자동화해주는 방법을 소개하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Creating Strongly-Typed C# Event Tracing for Windows (ETW) Assemblies with Visual Studio ; <a target='tab' href='http://maximelabelle.wordpress.com/2012/09/05/creating-strongly-typed-c-event-tracing-for-windows-etw-assemblies-with-visual-studio/'>http://maximelabelle.wordpress.com/2012/09/05/creating-strongly-typed-c-event-tracing-for-windows-etw-assemblies-with-visual-studio/</a> </pre> <br /> ETW가 매력적인 것은, 다른 ETW Provider와 조합해서 로깅 데이터를 분석할 수 있다는 점인데요. 이에 대한 간단한 실습 과정이 아래의 글에 나와 있습니다. 자신의 provider와 함께 .NET Framework의 clr 관련 ETW Provider를 이용해 로그를 남긴 것을 합쳐서 분석하는 과정을 보여주고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Using .NET 4.0 Event Tracing for Windows (ETW) along with application ETW ; <a target='tab' href='http://naveensrinivasan.com/2010/03/17/using-clr-4-0-event-tracing-for-windows-etw-along-with-application-etw/'>http://naveensrinivasan.com/2010/03/17/using-clr-4-0-event-tracing-for-windows-etw-along-with-application-etw/</a> </pre> <br /> 아울러, NuGet 패키지로 등록된 EventTraceWatcher 클래스를 이용해서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > EventTraceWatcher ; <a target='tab' href='http://nugetmusthaves.com/Package/EventTraceWatcher'>http://nugetmusthaves.com/Package/EventTraceWatcher</a> </pre> <br /> 실시간으로 ETW 이벤트를 받아 처리할 수 있는 프로그램을 만드는 방법을 소개하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > How to consume ETW events from C# (<a target='tab' href='https://www.sysnet.pe.kr/2/0/12292#etw_src'>내부 링크</a>) ; <a target='tab' href='https://learn.microsoft.com/en-us/archive/blogs/danielvl/how-to-consume-etw-events-from-c'>https://learn.microsoft.com/en-us/archive/blogs/danielvl/how-to-consume-etw-events-from-c</a> </pre> <br /> 이 글의 실습을 해보고 나서, 아래의 글에 실린 "그림 1 ETW 아키텍처"를 보니 이제 좀 이해가 되는군요. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ETW를 사용한 디버깅 및 성능 조정 개선 ; <a target='tab' href='https://learn.microsoft.com/ko-kr/archive/msdn-magazine/2007/april/event-tracing-improve-debugging-and-performance-tuning-with-etw'>https://learn.microsoft.com/ko-kr/archive/msdn-magazine/2007/april/event-tracing-improve-debugging-and-performance-tuning-with-etw</a> </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
2158
(왼쪽의 숫자를 입력해야 합니다.)