코드로 살펴 보는 ETW의 활성화 시점
전에 소개해 드린 ETW를 사용하는 과정에,
ETW(Event Tracing for Windows)를 C#에서 사용하는 방법
; https://www.sysnet.pe.kr/2/0/1804
문득, 궁금한 점이 생겼습니다. 자동 생성된 코드를 보면,
public static bool EventWriteEvent_MethodPerfTrace(string Context, string MethodName, ulong ExecutionTime, string ParameterInfo)
{
if (!m_provider.IsEnabled())
{
return true;
}
return m_provider.TemplateTemplate_MethodPerfTrace(ref Event_MethodPerfTrace, Context, MethodName, ExecutionTime, ParameterInfo);
}
m_provider.IsEnabled 호출로 활성/비활성 여부에 따라 ETW 로그 작업이 이뤄지게 되는데요. 혹시 IsEnabled 코드가 무겁진 않을까 하는... 걱정인 것이죠. ^^
그래서 확인해 보았습니다. IsEnabled는 자동 생성된 코드가 상속받는 (System.Core 어셈블리의) System.Diagnostics.Eventing.EventProvider 타입에 미리 구현되어 있습니다.
public bool IsEnabled()
{
if (this.m_enabled == 0)
{
return false;
}
return true;
}
단순한 필드 조회로 봐서는 다행히 IsEnabled 코드가 빠르게 실행될 것이므로 일단 안심입니다. 그렇다면 m_enabled 값은 언제 지정되는 것일까요? 이 값이 설정되는 코드를 찾아보면 callback 메서드가 나오는데,
[SecurityCritical]
private unsafe void EtwEnableCallBack([In] ref Guid sourceId, [In] int isEnabled, [In] byte setLevel, [In] long anyKeyword, [In] long allKeyword, [In] void* filterData, [In] void* callbackContext)
{
this.m_enabled = isEnabled;
this.m_level = setLevel;
this.m_anyKeywordMask = anyKeyword;
this.m_allKeywordMask = allKeyword;
}
이 메서드는 다시 EtwRegister 메서드에서 UnsafeNativeMethods.EventRegister Win32 API를 통해 윈도우 시스템에 콜백으로 등록됩니다.
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
internal static extern unsafe uint EventRegister([In] ref Guid providerId, [In] EtwEnableCallback enableCallback, [In] void* callbackContext, [In, Out] ref long registrationHandle);
[SecurityCritical]
private void EtwRegister()
{
if (s_platformNotSupported)
{
throw new PlatformNotSupportedException(SR.GetString("NotSupported_DownLevelVista"));
}
this.m_etwCallback = new UnsafeNativeMethods.EtwEnableCallback(this.EtwEnableCallBack);
uint num = UnsafeNativeMethods.EventRegister(ref this.m_providerId, this.m_etwCallback, null, ref this.m_regHandle);
if (num != 0)
{
throw new Win32Exception((int) num);
}
}
그리고 EtwRegister 메서드가 수행되는 시점은 System.Diagnostics.Eventing.EventProvider의 생성자입니다.
[SecurityCritical, PermissionSet(SecurityAction.Demand, Unrestricted=true)]
public EventProvider(Guid providerGuid)
{
this.m_providerId = providerGuid;
s_returnCodeSlot = Thread.AllocateDataSlot();
Thread.SetData(s_returnCodeSlot, 0);
this.EtwRegister();
}
오~~~ 아주 똑똑하게 설계되어 있군요. ^^ 외부에서 logman.exe를 통해 ETW Provider를 활성화시키게 되면 우리가 등록한 EtwEnableCallBack 메서드가 그 순간 불려지게 되고 이후로 호출되는 EventWriteEvent_MethodPerfTrace 메서드는 IsEnabled == true여서 m_provider.TemplateTemplate_MethodPerfTrace까지 이어지게 됩니다. (물론, 다시 logman.exe로 ETW Provider를 중지시키면 IsEnabled는 false를 반환하게 됩니다.)
실행 시에 아무런 부하 없이 로그에 대한 on/off를 할 수 있으니, 생각했던 것보다 괜찮군요. ^^ 어찌 보면, 어설픈 로그 시스템을 만들기 보다는 차라리 ETW를 이용해 로그를 남기는 것을 고려해봐도 좋겠습니다. ^^
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]