Пример #1
0
        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()
Пример #2
0
        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()
Пример #3
0
        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()