private static void _StartTracing(EventProvider ep) { try { // N.B. Not using Util.Assert here, since Util.Assert traces. Debug.Assert(!String.IsNullOrEmpty(sm_logFile), "Must have a log file to start tracing."); sm_maxLogFileSizeMB = RegistryUtils.GetRegValue("MaxTraceFileSizeMB", 8, (v) => Math.Max(1, v)); // If we are doing "low-priority" tracing, let's use a smaller file. And for // testing logging, we'll make it so we can wrap around a little quicker if (sm_useLowPriFile || !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("_DBGSHELL_TEST_MIN_TRACE_FILE_SIZE"))) { sm_maxLogFileSizeMB = 1; } int bufSizeKb = 0; string bufSizeStr = Environment.GetEnvironmentVariable("_DBGSHELL_TEST_BUF_SIZE"); if (!String.IsNullOrEmpty(bufSizeStr)) { if (Int32.TryParse(bufSizeStr, out bufSizeKb)) { if (bufSizeKb < 0) { // N.B. Not using Util.Fail here, since Util.Fail traces. Debug.Fail("need a value >= 0"); bufSizeKb = 0; } } } int bufsPerProc = 0; string bufsPerProcStr = Environment.GetEnvironmentVariable("_DBGSHELL_TEST_BUFS_PER_PROC"); if (!String.IsNullOrEmpty(bufsPerProcStr)) { if (Int32.TryParse(bufsPerProcStr, out bufsPerProc)) { if (bufsPerProc < 0) { // N.B. Not using Util.Fail here, since Util.Fail traces. Debug.Fail("need a value >= 0"); bufsPerProc = 0; } } } sm_etp = new EventTraceProperties(DbgProviderEtwProviderGuid, sm_logFile, sm_maxLogFileSizeMB, bufSizeKb, bufsPerProc); int err = NativeMethods.StartTrace(out sm_traceHandle, "Microsoft.DbgProvider.TraceSession", sm_etp); if (0 != err) { var e = new Win32Exception(err); e.Data["sm_logFile"] = sm_logFile; throw e; } Guid tmp = DbgProviderEtwProviderGuid; err = NativeMethods.EnableTraceEx2(sm_traceHandle, ref tmp, ControlCode.ENABLE_PROVIDER, TraceLevel.Verbose, 0, // matchAnyKeyword 0, // matchAllKeyword 0, // timeout, zero means trace async IntPtr.Zero); if (0 != err) { throw new Win32Exception(err); } FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location); lock (sm_syncRoot) if (!sm_shuttingDown) { // Can't call Trace directly because this code is called in the code path that // lazily initializes the sm_eventProvider field. ep.WriteMessageEvent("=========================================================="); ep.WriteMessageEvent(Util.Sprintf("DbgProvider version {0}", fvi.FileVersion)); ep.WriteMessageEvent(Util.Sprintf("CurrentCulture/CurrentUICulture: {0} / {1}", CultureInfo.CurrentCulture.Name, CultureInfo.CurrentUICulture.Name)); ep.WriteMessageEvent(Util.Sprintf("Process ID: {0} (0x{0:x4})", NativeMethods.GetCurrentProcessId())); ep.WriteMessageEvent(Util.Sprintf("Process command line: {0}", Environment.CommandLine)); ep.WriteMessageEvent(Util.Sprintf("User type: {0}, interactive: {1}", _GetUserType(), Environment.UserInteractive)); ep.WriteMessageEvent(Util.Sprintf("Current machine: {0}", Environment.MachineName)); Flush(); } } catch (Win32Exception w32e) { MulticulturalString mcsErrMsg = Util.McSprintf(Resources.ErrMsgTraceFailureFmt, sm_logFile, Util.GetExceptionMessages(w32e)); Exception e2 = Util.TryConvertWin32ExceptionToIOException(w32e, mcsErrMsg); if (null != e2) { throw e2; } else { throw; } } } // end _StartTracing()
public static void SaveLogFile(string copyToFile, bool overwrite) { lock ( sm_syncRoot ) { Trace("(saving log to \"{0}\")", copyToFile); if (null == sm_logFile) { throw new DbgProviderException(Resources.ErrMsgTracingFailed, "FailedToSaveTraceTracingDisabled", ErrorCategory.OpenError); } Exception e = null; // If we stop the trace session, the tracing won't be cumulative (because // ETW does not support "appending" to a circular file, so when you // restart tracing, the old contents get wiped out). We don't want that, // so we're just going to copy the "live" trace file. // // Improvements in the ProcessTrace function in Win8 have made it tolerant // of un-finalized circular files (alexbe). But if we want to inspect such // trace files on down-level machines, we'll need to finalize them // ourselves. // // I'll preserve the old behavior, switched by a reg value, "just in // case". if (0 == RegistryUtils.GetRegValue("RestartTracing", 0)) { Trace("(not stopping tracing)"); Flush(); string errorId = "FailedToSaveTrace"; e = Util.TryWin32IO(() => { File.Copy(sm_logFile, copyToFile, overwrite); errorId = "FailedToFinalizeTrace"; _FinalizeTraceFile(copyToFile); }); if (null != e) { ErrorCategory ec = Util.GetErrorCategoryForException(e); throw new DbgProviderException(Util.McSprintf(Resources.ErrMsgCouldNotSaveTraceFmt, copyToFile, Util.GetExceptionMessages(e)), errorId, ec, e); } } else { Trace("========================= Stopping trace at {0} =========================", DateTime.Now); Util.TryWin32IO(() => { int err = NativeMethods.ControlTrace(sm_traceHandle, null, sm_etp, EventTraceControl.Stop); if ((0 == err) || (ERROR_MORE_DATA == err)) { File.Copy(sm_logFile, copyToFile, overwrite); _StartTracing(sm_eventProvider.Value); } else { // N.B. Not using Util.Fail here, since Util.Fail traces. Debug.Fail(Util.Sprintf("This call should not fail: {0}.", err)); } }); if (null != e) { ErrorCategory ec = Util.GetErrorCategoryForException(e); throw new DbgProviderException(Util.McSprintf(Resources.ErrMsgCouldNotSaveTraceFmt, copyToFile, Util.GetExceptionMessages(e)), "FailedToSaveTrace", ec, e); } } // end else( we want to stop and restart the trace ) } // end lock( sm_syncRoot ) } // end SaveLogFile()
private static EventProvider _InitDebugTraceEventProvider() { sm_onInitPath = true; EventProvider ep = new EventProvider(DbgProviderEtwProviderGuid); // This won't make it into the log. But in case the EventProvider // constructor ever decides to do lazy registration, we'll trace // this so that our provider GUID will be sure to be registered // before we call StartTrace. ep.WriteMessageEvent("(starting session)"); Exception e = null; foreach (string potentialLogFile in _ChooseLogFilePath()) { e = Util.TryWin32IO(() => { sm_logFile = potentialLogFile; _StartTracing(ep); }); if (null == e) { break; } } if (null != e) { sm_logFile = null; // N.B. Not using Util.Fail here, since Util.Fail traces. Debug.Fail(Util.Sprintf("Could not start tracing: {0}", e)); if (0 == RegistryUtils.GetRegValue("TolerateLoggingFailure", 0)) { throw new DbgProviderException(Util.McSprintf(Resources.ErrMsgCouldNotStartLoggingFmt, Util.GetExceptionMessages(e)), "StartTracingFailed", ErrorCategory.OpenError, e); } } else { AppDomain.CurrentDomain.UnhandledException += _UnhandledExceptionHappened; // The following is to attempt to workaround things taking too long during // finalization at process exit--the CLR gives up and stops finalizing // stuff after 2 seconds. If the EventProvider finalizer does not get a // chance to run, then it has a callback that does not get unregistered, // which can get called after the CLR has been torn down, causing a crash. AppDomain.CurrentDomain.ProcessExit += _Shutdown; // We also want to shutdown when our appdomain gets unloaded. This is for // "hosted" scenarios (the DomainUnload event does not get raised for the // default domain). AppDomain.CurrentDomain.DomainUnload += _Shutdown; } sm_onInitPath = false; if (null != sm_preTracingTracing) { _WriteToEventProvider(ep, "(Begin trace messages generated while setting up tracing.)"); foreach (string preTrace in sm_preTracingTracing) { _WriteToEventProvider(ep, preTrace); } _WriteToEventProvider(ep, "(End trace messages generated while setting up tracing.)"); sm_preTracingTracing = null; } return(ep); } // end _InitDebugTraceEventProvider()