public void Start()
        {
            try
            {
                m_TraceEventSession = new TraceEventSession(SessionName, null);
                m_TraceEventSession.EnableKernelProvider(GetKeyEvents());

                m_TraceEventSource = new ETWTraceEventSource(SessionName, TraceEventSourceType.Session);
                m_TraceEventSource.Kernel.All += new Action<TraceEvent>(Kernel_All);

                Running = true;
            }
            catch (Exception ex)
            {
                Stop();
                throw;
            }
        }
Example #2
0
        /// <summary>
        /// Once started, event sessions will persist even after the process that created them dies. They are
        /// only stoped by this explicit Stop() API.  If you used both kernel and user events, consider
        /// using the code:StopUserAndKernelSession API instead. 
        /// </summary>
        public void Stop()
        {
            if (stopped)
                return;
            stopped = true;
            int hr = TraceEventNativeMethods.ControlTrace(0UL, sessionName,
                ToUnmanagedBuffer(properties, null), TraceEventNativeMethods.EVENT_TRACE_CONTROL_STOP);

            // TODO enumerate providers in session and turn them off
            #if false
            string regKeyName = @"Software\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + providerGuid + "}";
            Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(regKeyName, true);
            regKey.DeleteValue("ControllerData", false);
            regKey.Close();
            #endif

            if (hr != 4201)     // Instance name not found.  This means we did not start
                Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(hr));

            if (kernelSession != null)
            {
                kernelSession.Stop();
                kernelSession = null;
            }
        }
Example #3
0
        /// <summary>
        /// TraceEventSessions may have both a kernel session and a user session turned on.  To simplify
        /// error handling, call code:StopSession to stop both.  This is equivalent it attaching to the
        /// combined session and calling Stop, but also works in all error cases (if it was possible to stop
        /// the sessions they are stopped), and is silent if the sessions are already stopped.  
        /// </summary>
        /// <param name="userSessionName">The name of the user session to stop</param>
        public static void StopUserAndKernelSession(string userSessionName)
        {
            Exception eToThow = null;
            try
            {
                TraceEventSession kernelSession = new TraceEventSession(KernelTraceEventParser.KernelSessionName);
                kernelSession.Stop();
            }
            catch (COMException e)
            {
                if ((uint)e.ErrorCode != 0x80071069)        // Could not find provider, that is OK.
                    eToThow = e;
            }
            catch (Exception e)
            {
                eToThow = e;                                // we will throw this later.
            }

            try
            {
                TraceEventSession userSession = new TraceEventSession(userSessionName);
                userSession.Stop();
            }
            catch (COMException e)
            {
                if ((uint)e.ErrorCode != 0x80071069)      // Could not find provider, that is OK
                    throw;
            }

            // If we got an error closing down the kernel provider, throw it here.
            if (eToThow != null)
                throw eToThow;
        }
Example #4
0
        /// <summary>
        /// #EnableKernelProvider
        /// Enable the kernel provider for the session. If the session name is 'NT Kernel Session' then it
        /// operates on that.   This can be used to manipuate the kernel session.   If the name is not 'NT
        /// Kernel Session' AND it is a moduleFile based session, then it tries to approximate attaching the
        /// kernel session by creating another session logs to [basename].kernel.etl.  There is support in
        /// ETWTraceEventSource for looking for these files automatically, which give a good illusion that
        /// you can have a session that has both kernel and user events turned on.  
        /// <param name="flags">
        /// Specifies the particular kernel events of interest</param>
        /// <param name="stackCapture">
        /// Specifies which events should have their eventToStack traces captured too (VISTA only)</param>
        /// <returns>Returns true if the session had existed before and is now restarted</returns>
        /// </summary>
        public unsafe bool EnableKernelProvider(KernelTraceEventParser.Keywords flags, KernelTraceEventParser.Keywords stackCapture)
        {
            if (sessionName != KernelTraceEventParser.KernelSessionName)
            {
                if (kernelSession != null)
                    throw new Exception("A kernel session is already active.");
                if (string.IsNullOrEmpty(FileName))
                    throw new Exception("Cannot enable kernel events to a real time session unless it is named " + KernelTraceEventParser.KernelSessionName);
                string kernelFileName = System.IO.Path.ChangeExtension(FileName, ".kernel.etl");
                kernelSession = new TraceEventSession(KernelTraceEventParser.KernelSessionName, kernelFileName);
                return kernelSession.EnableKernelProvider(flags, stackCapture);
            }
            if (sessionHandle != TraceEventNativeMethods.INVALID_HANDLE_VALUE)
                throw new Exception("The kernel provider must be enabled as the only provider.");

            properties.Wnode.Guid = KernelTraceEventParser.ProviderGuid;
            if (Environment.OSVersion.Version.Major <= 5)
            {
                // TODO should we fail, or should we silently ignore?
                if (stackCapture != KernelTraceEventParser.Keywords.None)
                    throw new Exception("Stack trace capture only available on Windows 6 (VISTA) and above.");

                KernelTraceEventParser.Keywords vistaOnlyFlags =
                    KernelTraceEventParser.Keywords.ProcessCounters |
                    KernelTraceEventParser.Keywords.ContextSwitch |
                    KernelTraceEventParser.Keywords.Interrupt |
                    KernelTraceEventParser.Keywords.DiskIOInit |
                    KernelTraceEventParser.Keywords.Driver |
                    KernelTraceEventParser.Keywords.Profile |
                    KernelTraceEventParser.Keywords.FileIO |
                    KernelTraceEventParser.Keywords.FileIOInit |
                    KernelTraceEventParser.Keywords.Dispatcher |
                    KernelTraceEventParser.Keywords.VirtualAlloc;
                KernelTraceEventParser.Keywords setVistaFlags = flags & vistaOnlyFlags;
                if (setVistaFlags != KernelTraceEventParser.Keywords.None)
                    throw new Exception("A Kernel Event Flags {" + setVistaFlags.ToString() + "} specified that is not supported on Pre-VISTA OSes.");

                properties.EnableFlags = (uint) flags;
                return StartTrace();
            }

            // Initialize the stack collecting information
            const int stackTracingIdsMax = 96;
            int curID = 0;
            var stackTracingIds = stackalloc TraceEventNativeMethods.STACK_TRACING_EVENT_ID[stackTracingIdsMax];
            #if DEBUG
            // Try setting all flags, if we overflow an assert in SetStackTraceIds will fire.
            SetStackTraceIds((KernelTraceEventParser.Keywords)(-1), stackTracingIds, stackTracingIdsMax);
            #endif
            if (stackCapture != KernelTraceEventParser.Keywords.None)
                curID = SetStackTraceIds(stackCapture, stackTracingIds, stackTracingIdsMax);

            // The Profile event requires the SeSystemProfilePrivilege to succeed, so set it.
            if ((flags & KernelTraceEventParser.Keywords.Profile) != 0)
                TraceEventNativeMethods.SetSystemProfilePrivilege();

            bool ret = false;
            properties.EnableFlags = (uint)flags;

            int dwErr;
            try
            {
                dwErr = TraceEventNativeMethods.StartKernelTrace(out sessionHandle, ToUnmanagedBuffer(properties, fileName), stackTracingIds, curID);
                if (dwErr == 0xB7) // STIERR_HANDLEEXISTS
                {
                    ret = true;
                    Stop();
                    Thread.Sleep(100);  // Give it some time to stop.
                    dwErr = TraceEventNativeMethods.StartKernelTrace(out sessionHandle, ToUnmanagedBuffer(properties, fileName), stackTracingIds, curID);
                }
            }
            catch (BadImageFormatException)
            {
                // We use a small native DLL called KernelTraceControl that needs to be
                // in the same directory as the EXE that used TraceEvent.dll.  Unlike IL
                // Native DLLs are specific to a processor type (32 or 64 bit) so the easiest
                // way to insure this is that the EXE that uses TraceEvent is built for 32 bit
                // and that you use the 32 bit version of KernelTraceControl.dll
                throw new BadImageFormatException("Could not load KernelTraceControl.dll (likely 32-64 bit process mismatch)");
            }
            catch (DllNotFoundException)
            {
                // In order to start kernel session, we need a support DLL called KernelTraceControl.dll
                // This DLL is available by downloading the XPERF.exe tool (see
                // http://msdn.microsoft.com/en-us/performance/cc825801.aspx for instructions)
                // It is recommended that you get the 32 bit version of this (it works on 64 bit machines)
                // and build your EXE that uses TraceEvent to launch as a 32 bit application (This is
                // the default for VS 2010 projects).
                throw new DllNotFoundException("KernelTraceControl.dll missing from distribution.");
            }
            if (dwErr == 5 && Environment.OSVersion.Version.Major > 5)      // On Vista and we get a 'Accessed Denied' message
                throw new UnauthorizedAccessException("Error Starting ETW:  Access Denied (Administrator rights required to start ETW)");
            Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(dwErr));

            return ret;
        }
Example #5
0
        /// <summary>
        /// Open an existing Windows Event Tracing Session, with name 'sessionName'.
        /// 
        /// If you are opening a new session use TraceEventSession(string, string).
        ///  
        /// To support the illusion that you can have a session with both kernel and user events,
        /// TraceEventSession might start up both a kernel and a user session.   When you want to 'attach'
        /// to such a combined session, the constructor needs to know if you want to control the kernel
        /// session or not.  If attachKernelSession is true, then it opens both sessions (and thus 'Close'
        /// will operation on both sessions.
        /// </summary>
        public TraceEventSession(string sessionName, bool attachKernelSession)
        {
            Init(sessionName);
            int hr = TraceEventNativeMethods.ControlTrace(0UL, sessionName, ToUnmanagedBuffer(properties, null), TraceEventNativeMethods.EVENT_TRACE_CONTROL_QUERY);
            Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(hr));
            isActive = true;
            properties = (TraceEventNativeMethods.EVENT_TRACE_PROPERTIES)Marshal.PtrToStructure(unmanagedPropertiesBuffer, typeof(TraceEventNativeMethods.EVENT_TRACE_PROPERTIES));
            if (properties.LogFileNameOffset != 0)
                fileName = Marshal.PtrToStringUni((IntPtr)(unmanagedPropertiesBuffer.ToInt64() + properties.LogFileNameOffset));

            if (attachKernelSession)
            {
                bool success = false;
                try
                {
                    kernelSession = new TraceEventSession(KernelTraceEventParser.KernelSessionName);
                    success = true;
                }
                finally
                {
                    if (!success)
                        Stop();
                }
            }
        }