Source/Tx.Windows/EtwNative/EtwObservable.cs (109 lines of code) (raw):

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Reactive; using System.Text; using System.Threading; namespace Tx.Windows { /// <summary> /// Factory for creating raw ETW (Event Tracing for Windows) observable sources /// </summary> public static class EtwObservable { /// <summary> /// Creates a reader for one or more .etl (Event Trace Log) files /// </summary> /// <param name="etlFiles">up to 63 files to read</param> /// <returns>sequence of events ordered by timestamp</returns> public static IObservable<EtwNativeEvent> FromFiles(params string[] etlFiles) { if (etlFiles == null) throw new ArgumentNullException("etlFiles"); if (etlFiles.Length == 0 || etlFiles.Length > 63) throw new ArgumentException("the supported count of files is from 1 to 63"); return new NonDetachObservable<EtwNativeEvent>(o => new EtwFileReader(o, etlFiles)); } /// <summary> /// Creates a reader for one or more .etl (Event Trace Log) files /// </summary> /// <param name="startTime">start time of sequence of events</param> /// <param name="endTime">end time of sequence of events</param> /// <param name="etlFiles">up to 63 files to read</param> /// <returns>sequence of events ordered by timestamp</returns> public static IObservable<EtwNativeEvent> FromFiles(DateTime startTime, DateTime endTime, params string[] etlFiles) { if (etlFiles == null) throw new ArgumentNullException("etlFiles"); if (etlFiles.Length == 0 || etlFiles.Length > 63) throw new ArgumentException("the supported count of files is from 1 to 63"); return new NonDetachObservable<EtwNativeEvent>(o => new EtwFileReader(o, false, startTime, endTime, etlFiles)); } /// <summary> /// Creates a reader for one or more .etl (Event Trace Log) files /// </summary> /// <param name="etlFiles">Unlimited number of ETL files containing events ordered by timestamp</param> /// <returns>sequence of events ordered by timestamp</returns> public static IObservable<EtwNativeEvent> FromSequentialFiles(params string[] etlFiles) { if (etlFiles == null) throw new ArgumentNullException("etlFiles"); if (etlFiles.Length == 0) throw new ArgumentException("the supported count of files is atleast one file"); return new NonDetachObservable<EtwNativeEvent>(o => new EtwFileReader(o, true, etlFiles)); } /// <summary> /// Creates a reader for one or more .etl (Event Trace Log) files /// </summary> /// <param name="startTime">start time of sequence of events</param> /// <param name="endTime">end time of sequence of events</param> /// <param name="etlFiles">Unlimited number of ETL files containing events ordered by timestamp</param> /// <returns>sequence of events ordered by timestamp</returns> public static IObservable<EtwNativeEvent> FromSequentialFiles(DateTime startTime, DateTime endTime, params string[] etlFiles) { if (etlFiles == null) throw new ArgumentNullException("etlFiles"); if (etlFiles.Length == 0) throw new ArgumentException("the supported count of files is atleast one file"); return new NonDetachObservable<EtwNativeEvent>(o => new EtwFileReader(o, true, startTime, endTime, etlFiles)); } /// <summary> /// Creates a listener to ETW real-time session /// </summary> /// <param name="sessionName">session name</param> /// <returns>events received from the session</returns> public static IObservable<EtwNativeEvent> FromSession(string sessionName) { if (sessionName == null) throw new ArgumentNullException("sessionName"); return new NonDetachObservable<EtwNativeEvent>(o => new EtwListener(o, sessionName)); } /// <summary> /// Extracts manifest from .etl file that was produced using System.Diagnostics.Tracing.EventSource /// </summary> /// <param name="etlFile">Trace file</param> /// <returns></returns> public static string[] ExtractManifests(string etlFile) { IObservable<EtwNativeEvent> all = FromFiles(etlFile); var manifests = new Dictionary<Guid, ManifestReassembly>(); var evt = new ManualResetEvent(false); IDisposable d = all.Subscribe(e => { if (e.Id != 0xfffe) // 65534 { return; } byte format = e.ReadByte(); if (format != 1) throw new Exception("Unsuported manifest format found in EventSource event" + format); byte majorVersion = e.ReadByte(); byte minorVersion = e.ReadByte(); byte magic = e.ReadByte(); if (magic != 0x5b) throw new Exception("Unexpected content in EventSource event that was supposed to have manifest"); ushort totalChunks = e.ReadUInt16(); ushort chunkNumber = e.ReadUInt16(); string chunk = e.ReadAnsiString(); ManifestReassembly ra = null; if (!manifests.TryGetValue(e.ProviderId, out ra)) { ra = new ManifestReassembly { Totalchunks = totalChunks, LastChunkNumber = chunkNumber, Manifest = new StringBuilder(chunk) }; manifests.Add(e.ProviderId, ra); return; } if (chunkNumber <= ra.LastChunkNumber) return; else if (chunkNumber == ra.LastChunkNumber + 1) { ra.LastChunkNumber = chunkNumber; ra.Manifest.Append(chunk); } else throw new Exception("Missing chunks when trying to concatenate the manifest for provider " + e.ProviderId); }, () => evt.Set()); evt.WaitOne(); d.Dispose(); var result = new List<string>(); foreach (ManifestReassembly ra in manifests.Values) result.Add(ra.Manifest.ToString()); var r = result.ToArray(); return r; } class ManifestReassembly { public int Totalchunks { get; set; } public int LastChunkNumber { get; set; } public StringBuilder Manifest { get; set; } } } }