private void ValidateEventArgs(ETWEvent entry) { if (entry.ProviderID != TestLogger.Write.Guid || entry.ID == (ushort)DynamicTraceEventParser.ManifestEventID) { return; } ++this.eventsRead; switch (entry.ID) { case 1: Assert.IsTrue(entry.EventName == "String"); Assert.AreEqual(EventLevel.Verbose, entry.Level); Assert.AreEqual(EventKeywords.None, (EventKeywords)entry.Keywords); Assert.AreEqual(1, entry.Parameters.Count); Assert.IsNotNull(entry.Parameter <string>(0)); Assert.IsTrue("a string draws near" == entry.Parameters["message"] as string); break; case 2: Assert.IsTrue(entry.EventName == "Int"); Assert.AreEqual(EventLevel.Informational, entry.Level); Assert.AreEqual((int)EventOpcode.Info, entry.OpCode); Assert.AreEqual(1, entry.Parameters.Count); Assert.AreEqual(42, entry.Parameter <int>("message")); break; case 3: Assert.IsTrue(entry.EventName == "First"); Assert.AreEqual(EventLevel.Informational, entry.Level); Assert.AreEqual(TestLogger.Keywords.FirstKeyword, (EventKeywords)entry.Keywords); Assert.AreEqual(1, entry.Parameters.Count); Assert.IsNotNull(entry.Parameter <string>(0)); Assert.IsTrue("base" == entry.Parameter <string>("message")); break; case 5: Assert.IsTrue(entry.EventName == "OnlyTask/Extension"); // combo of task+opcode Assert.AreEqual(EventLevel.Informational, entry.Level); Assert.AreEqual((int)EventOpcode.Extension, entry.OpCode); Assert.AreEqual(5, entry.Parameters.Count); Assert.AreEqual(0x86, entry.Parameter <byte>(0)); Assert.AreEqual(0x86, entry.Parameter <byte>("wind")); Assert.AreEqual(75309, entry.Parameter <int>(1)); Assert.AreEqual(75309, entry.Parameter <int>("water")); Assert.IsTrue("Jenny" == entry.Parameter <string>(2)); Assert.IsTrue("Jenny" == entry.Parameter <string>("earth")); Assert.AreEqual(867.5309, entry.Parameter <double>(3)); Assert.AreEqual(867.5309, entry.Parameter <double>("fire")); Assert.AreEqual(true, entry.Parameter <bool>(4)); Assert.AreEqual(true, entry.Parameter <bool>("heart")); break; default: Assert.Fail("Entry with unknown ID!" + entry.ID); break; } }
private void EventProcessed(ETWEvent ev) { ProviderStatistics providerData; if (!this.statistics.TryGetValue(ev.ProviderID, out providerData)) { providerData = new ProviderStatistics(ev.ProviderID, ev.ProviderName); this.statistics[ev.ProviderID] = providerData; } providerData.ProcessEvent(ev); }
private static void ValidateEventArgs(ETWEvent entry) { if (entry.ProviderID != TestLogger.Write.Guid) { return; } switch (entry.ID) { case 1: Assert.IsTrue(entry.EventName == "String"); Assert.AreEqual(EventLevel.Verbose, entry.Level); Assert.AreEqual(EventKeywords.None, (EventKeywords)entry.Keywords); Assert.AreEqual(1, entry.Parameters.Count); Assert.IsNotNull(entry.Parameter<string>(0)); Assert.IsTrue("a string draws near" == entry.Parameters["message"] as string); break; case 2: Assert.IsTrue(entry.EventName == "Int"); Assert.AreEqual(EventLevel.Informational, entry.Level); Assert.AreEqual((int)EventOpcode.Info, entry.OpCode); Assert.AreEqual(1, entry.Parameters.Count); Assert.AreEqual(42, entry.Parameter<int>("message")); break; case 3: Assert.IsTrue(entry.EventName == "First"); Assert.AreEqual(EventLevel.Informational, entry.Level); Assert.AreEqual(TestLogger.Keywords.FirstKeyword, (EventKeywords)entry.Keywords); Assert.AreEqual(1, entry.Parameters.Count); Assert.IsNotNull(entry.Parameter<string>(0)); Assert.IsTrue("base" == entry.Parameter<string>("message")); break; case 5: Assert.IsTrue(entry.EventName == "OnlyTask/Extension"); // combo of task+opcode Assert.AreEqual(EventLevel.Informational, entry.Level); Assert.AreEqual((int)EventOpcode.Extension, entry.OpCode); Assert.AreEqual(5, entry.Parameters.Count); Assert.AreEqual(0x86, entry.Parameter<byte>(0)); Assert.AreEqual(0x86, entry.Parameter<byte>("wind")); Assert.AreEqual(75309, entry.Parameter<int>(1)); Assert.AreEqual(75309, entry.Parameter<int>("water")); Assert.IsTrue("Jenny" == entry.Parameter<string>(2)); Assert.IsTrue("Jenny" == entry.Parameter<string>("earth")); Assert.AreEqual(867.5309, entry.Parameter<double>(3)); Assert.AreEqual(867.5309, entry.Parameter<double>("fire")); Assert.AreEqual(true, entry.Parameter<bool>(4)); Assert.AreEqual(true, entry.Parameter<bool>("heart")); break; default: Assert.Fail("Entry with unknown ID!" + entry.ID); break; } }
public void ProcessEvent(ETWEvent ev) { if (ev.ID == ExpiringCompositeEventCollectionTests.StartEventID) { this.haveStart = true; } else if (ev.ID == ExpiringCompositeEventCollectionTests.EndEventID) { this.haveEnd = true; } this.LastModified = ev.Timestamp; }
private static void HandleEvent(ETWEvent ev) { // For summary runs we don't need to burn time formatting the output unless we are doing some filtering // (in which case we are interested in the filter count) if (options.Summary && filter == null && options.ProviderFilter == null) { return; } if (options.ProviderFilter != null) { if (providerIDFilter != Guid.Empty && ev.ProviderID != providerIDFilter) { return; } if (0 > ev.ProviderName.IndexOf(options.ProviderFilter, StringComparison.OrdinalIgnoreCase)) { return; } } string output; if (options.JsonOutput) { output = JsonConvert.SerializeObject(ev); } else if (options.XmlOutput) { output = ev.ToXmlString(streamBuffer); } else { output = ev.ToString(eventFormatter); } if (filter != null && !filter.IsMatch(output)) { return; } if (!options.Summary) { if (prefixWithFilename) { Console.Write("{0}:", ev.SourceFilename); } Console.WriteLine(output); } ++currentStatistics.Emitted; }
/// <summary> /// Inject an event into the processor. /// </summary> /// <param name="ev">Event to inject.</param> public void InjectEvent(ETWEvent ev) { if (ev == null) { throw new ArgumentNullException("ev"); } lock (this.injectionLock) { if (!this.stopInjecting) { this.injectedEvents.Enqueue(ev); } } }
public void CanSerializeAndDeserializeEventsProcessedInFiles() { CheckElevated(); string fullFilename = this.WriteTestFile("testSerialize.etl"); var reader = new ETWFileProcessor(fullFilename); reader.EventProcessed += this.ValidateEventArgs; reader.EventProcessed += ev => { var xmlSerializer = ETWEvent.GetXmlSerializer(); var jsonSerializer = ETWEvent.GetJsonSerializer(); var json = ev.ToJsonString(); var xml = ev.ToXmlString(); var jsonEv = jsonSerializer.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(json))) as ETWEvent; // Note that we lose some precision in serialization... just check down to ms granularity by // stripping the additional bits off. var msResolutionTimestamp = new DateTime(ev.Timestamp.Ticks - (ev.Timestamp.Ticks % TimeSpan.TicksPerMillisecond), ev.Timestamp.Kind); Assert.AreEqual(msResolutionTimestamp, jsonEv.Timestamp); Assert.AreEqual(ev.ProviderID, jsonEv.ProviderID); Assert.AreEqual(ev.ProviderName, jsonEv.ProviderName); Assert.AreEqual(ev.ActivityID, jsonEv.ActivityID); Assert.AreEqual(ev.ID, jsonEv.ID); Assert.AreEqual(ev.EventName, jsonEv.EventName); Assert.AreEqual(ev.Version, jsonEv.Version); Assert.AreEqual(ev.Level, jsonEv.Level); Assert.AreEqual(ev.OpCode, jsonEv.OpCode); Assert.AreEqual(ev.Keywords, jsonEv.Keywords); Assert.AreEqual(ev.ThreadID, jsonEv.ThreadID); Assert.AreEqual(ev.ProcessID, jsonEv.ProcessID); Assert.AreEqual(ev.Parameters.Count, jsonEv.Parameters.Count); this.ValidateEventArgs(ev); // When testing XML deserialize just check a couple fields to ensure data was copied correctly, // if JSON serialization/deserialization worked we expect no hiccups here. var xmlEv = xmlSerializer.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(xml))) as ETWEvent; Assert.AreEqual(ev.ProviderID, xmlEv.ProviderID); Assert.AreEqual(ev.ThreadID, xmlEv.ThreadID); this.ValidateEventArgs(ev); }; reader.Process(); Assert.AreEqual(12, this.eventsRead); // we validate three times per event. }
/// <summary> /// Method called to process an event for the given key. If the record does not exist yet it will be created. /// </summary> /// <param name="key">Key of the compositve event.</param> /// <param name="ev">Event to process.</param> public void ProcessEvent(TKey key, ETWEvent ev) { TValue val; if (this.incompleteRecords.TryGetValue(key, out val)) { val.ProcessEvent(ev); if (val.IsComplete) { this.incompleteRecords.Remove(key); this.completeRecords.Add(key, val); } } else if (this.completeRecords.TryGetValue(key, out val)) { val.ProcessEvent(ev); } else { val = new TValue(); val.ProcessEvent(ev); if (val.IsComplete) { this.completeRecords.Add(key, val); } else { this.incompleteRecords.Add(key, val); } } // We make no effort here to see if this was previously our oldest value. It is conceivable (though // not particularly likely) that two separate records have identical ages. This may mean that we run // expiration more frequently than desirable, but the code should be both simpler and correct in all // cases as a result. if (val.IsComplete && val.LastModified < this.oldestCompleteRecord) { this.oldestCompleteRecord = val.LastModified; } else if (!val.IsComplete && val.LastModified < this.oldestIncompleteRecord) { this.oldestIncompleteRecord = val.LastModified; } this.Expire(ev.Timestamp); }
private void ProcessEvent(TraceEvent ev) { ETWEvent processedEntry; try { processedEntry = new ETWEvent(this.TraceEventSource.LogFileName, ev); ++this.Count; } catch (Exception) { ++this.UnreadableEvents; return; } this.OnEvent(processedEntry); }
public void CanSafelyCastEnumsToIntegerTypes() { var ev = new ETWEvent(DateTime.Now, Guid.NewGuid(), "fakeProvider", 1, "fakeEvent", 1, EventKeywords.None, EventLevel.Informational, EventOpcode.Info, Guid.Empty, 867, 4309, new OrderedDictionary { { "signed", FakeSignedEnum.FakeValue }, { "unsigned", FakeUnsignedEnum.FakeValue } }); Assert.AreEqual((int)FakeSignedEnum.FakeValue, ev.Parameter <int>("signed")); Assert.AreEqual((uint)FakeSignedEnum.FakeValue, ev.Parameter <uint>("signed")); Assert.AreEqual((int)FakeUnsignedEnum.FakeValue, ev.Parameter <int>("unsigned")); Assert.AreEqual((uint)FakeUnsignedEnum.FakeValue, ev.Parameter <uint>("unsigned")); }
public void ProcessEvent(ETWEvent ev) { if (!this.eventNames.ContainsKey(ev.ID)) { this.eventNames[ev.ID] = ev.EventName; this.eventCounts[ev.ID] = 0; this.eventSizes[ev.ID] = 0; } ++this.eventCounts[ev.ID]; ulong payloadSize = 0; // Note: best effort, not always right. if (ev.Parameters != null) // Parameters is null for parameter-less events. { foreach (var value in ev.Parameters.Values) { if (value is string) { payloadSize += (ulong)((value as string).Length * 2); // always assume UTF-16. } else if (value is byte || value is sbyte) { payloadSize += 1; } else if (value is short || value is ushort) { payloadSize += 2; } else if (value is double || value is long || value is ulong) { payloadSize += 8; } else { payloadSize += 4; // int, uint, float, enums } } } this.eventSizes[ev.ID] += payloadSize; }
public void MockETWProcessorTriggersEventProcessedWithSameETWEventObjectPassedToInjectEvent() { const string anySessionName = "session"; var anyEvent = new ETWEvent(DateTime.Now, Guid.Empty, string.Empty, 0, string.Empty, 0, EventKeywords.None, EventLevel.Verbose, EventOpcode.Info, Guid.Empty, 0, 0, null); bool eventTriggered = false; using (var processor = new MockETWProcessor(anySessionName)) { processor.EventProcessed += ev => { Assert.AreSame(anyEvent, ev); eventTriggered = true; }; processor.ProcessAsync(); processor.InjectEvent(anyEvent); processor.StopProcessing(); Assert.IsTrue(eventTriggered); } }
/// <summary> /// Trigger EventProcessed. The base processor will do this with any actual session, this is primarily intended /// for mocking a processor. /// </summary> /// <param name="ev">The event to inject.</param> protected void OnEvent(ETWEvent ev) { this.EventProcessed(ev); }
/// <summary> /// Trigger EventProcessed. The base processor will do this with any actual session, this is primarily intended /// for mocking a processor. /// </summary> /// <param name="ev">The event to inject.</param> protected void OnEvent(ETWEvent ev) { this.EventProcessed?.Invoke(ev); }
public override void Write(ETWEvent ev) { try { WebRequest request = WebRequest.Create(this.serverUri); request.Method = WebRequestMethods.Http.Post; request.ContentType = "text/xml"; // We are guaranteed safe access to our serializer and its buffer, but we have to dupe the bytes off // before using async web request. It's possible we could be smarter about this with a distinct // serializer per request and use of its begin/end write code. Not trying for now. this.serializationBuffer.Position = 0; this.serializationBuffer.SetLength(0); this.serializer.WriteObject(this.serializationBuffer, ev); var postData = new byte[this.serializationBuffer.Length]; Array.Copy(this.serializationBuffer.GetBuffer(), postData, postData.Length); request.ContentLength = postData.Length; request.BeginGetRequestStream(GetPostStreamCallback, new RequestState {WebRequest = request, PostData = postData}); } catch (WebException) { } // Skip all of these since we don't currently care if the remote endpoint is down. catch (InvalidOperationException) { } catch (IOException) { } }
public string Format(ETWEvent ev) { this.builder.Clear(); if ((int)(this.Options & TextLogFormatOptions.TimeOffset) != 0) { var timeDiff = (double)(Stopwatch.GetTimestamp() - this.startTicks); timeDiff /= Stopwatch.Frequency; this.builder.Append(timeDiff.ToString("F6")); this.builder.Append(' '); } else if ((int)(this.Options & TextLogFormatOptions.Timestamp) != 0) { if ((int)(this.Options & TextLogFormatOptions.TimestampInLocalTime) != 0) { this.builder.Append(ev.Timestamp.ToString(TimeFormat)); } else { this.builder.Append(ev.Timestamp.ToUniversalTime().ToString(TimeFormat)); } this.builder.Append(' '); } if ((int)(this.Options & TextLogFormatOptions.ShowActivityID) != 0 && ev.ActivityID != Guid.Empty) { this.builder.Append('('); this.builder.Append(ev.ActivityID.ToString("N")); this.builder.Append(") "); } this.builder.Append('['); if ((int)(this.Options & TextLogFormatOptions.ProcessAndThreadData) != 0) { this.builder.Append(ev.ProcessID); this.builder.Append('/'); this.builder.Append(ev.ThreadID); this.builder.Append('/'); } this.builder.Append(ETWEvent.EventLevelToChar(ev.Level)); this.builder.Append(':'); this.builder.Append(ev.ProviderName); this.builder.Append(' '); this.builder.Append(ev.EventName); this.builder.Append(']'); if (ev.Parameters != null) { foreach (DictionaryEntry pair in ev.Parameters) { var name = pair.Key as string; object o = pair.Value; var s = o as string; var a = o as Array; if (s != null) { // strings can't be trusted, welcome to costlytown. this.builder.Append(' '); this.builder.Append(name); this.builder.Append(@"="""); foreach (var ch in s) { switch (ch) { case '\0': this.builder.Append(@"\0"); break; case '\\': this.builder.Append(@"\\"); break; case '"': this.builder.Append(@"\"""); break; case '\n': this.builder.Append(@"\n"); break; case '\r': this.builder.Append(@"\r"); break; default: this.builder.Append(ch); break; } } this.builder.Append('\"'); } else if (a != null) { // This behavior may be too basic and could be changed in the future. For example // it may be interesting to emit the raw contents of small arrays instead of the type. // This was not done at present because nobody needed it, but anybody should feel free // to make such a change if it is desirable. this.builder.Append(' '); this.builder.Append(name); this.builder.Append('='); this.builder.Append(a.GetType()); this.builder.Append('['); this.builder.Append(a.Length); this.builder.Append(']'); } else { this.builder.Append(' '); this.builder.Append(name); this.builder.Append('='); this.builder.Append(o); } } } return this.builder.ToString(); }
protected override sealed void OnEventWritten(EventWrittenEventArgs eventData) { if (eventData.EventId == (int)DynamicTraceEventParser.ManifestEventID) { return; // we do not want to write this as it's not really helpful for users } Guid currentActivityId; LogManager.GetActivityId(out currentActivityId); if (this.FilterActivityID != Guid.Empty && currentActivityId != this.FilterActivityID) { return; } LogManager.EventSourceInfo source = LogManager.GetEventSourceInfo(eventData.EventSource); LogManager.EventInfo eventInfo = source[eventData.EventId]; OrderedDictionary payload = null; if (eventInfo.Arguments != null) { payload = new OrderedDictionary(eventInfo.Arguments.Length); int argCount = 0; foreach (var o in eventData.Payload) { payload.Add(eventInfo.Arguments[argCount], o); ++argCount; } } var ev = new ETWEvent(DateTime.Now, eventData.EventSource.Guid, eventData.EventSource.Name, (ushort)eventData.EventId, eventInfo.Name, eventData.Version, eventData.Keywords, eventData.Level, eventData.Opcode, currentActivityId, LogManager.ProcessID, NativeMethods.GetCurrentWin32ThreadId(), payload); lock (this.WriterLock) { if (!this.disabled) { this.Write(ev); } } }
/// <summary> /// Called when an ETWEvent has been constructed (via <see cref="OnEventWritten"/>). /// </summary> /// <param name="ev"></param> public abstract void Write(ETWEvent ev);
public override void Write(ETWEvent ev) { this.parentProcessor.InjectEvent(ev); }
private static void SetupRealtimeProcessor() { var sessionName = string.Format("{0}-ELT-realtime", Environment.UserName); var realtimeSession = new ETWRealtimeProcessor(sessionName); bool added = false; foreach (var arg in options.Arguments) { string[] split = arg.Split('!'); Guid providerID; var providers = new List <Guid>(); var minimumSeverity = EventLevel.Informational; long keywords = 0x0; if (split[0].Equals("CLR", StringComparison.OrdinalIgnoreCase)) { providers.Add(ClrTraceEventParser.ProviderGuid); } else if (split[0].Equals("Kernel", StringComparison.OrdinalIgnoreCase)) { providers.Add(KernelTraceEventParser.ProviderGuid); } else if (!Guid.TryParse(split[0], out providerID)) { // If it's not a GUID it might be an assembly -- we can try that... if (!GetProvidersFromAssembly(split[0], providers)) { ShowErrorAndExit("{0} is not a validly formatted GUID, and not a usable assembly", split[0]); } } else { providers.Add(providerID); } // Ignore if the string is null(won't be), empty, or whitespace -- all these will just mean that we // use default severity. if (split.Length > 1 && !string.IsNullOrWhiteSpace(split[1])) { minimumSeverity = ETWEvent.CharToEventLevel(split[1][0]); } if (split.Length > 2) { string num = split[2]; if (num.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { num = num.Substring(2); } if (!long.TryParse(num, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out keywords)) { ShowErrorAndExit("Keyword value {0} is not a valid hexadecimal number", split[2]); } } foreach (var id in providers) { realtimeSession.SubscribeToProvider(id, minimumSeverity, keywords); } added = true; } if (!added) { ShowErrorAndExit("No providers given to subscribe to!"); } processor = realtimeSession; }
public override sealed void Write(ETWEvent ev) { if (this.Writer == null) { return; } string output = ev.ToString(this.formatter); if (this.Filters.Count > 0) { bool matched = false; foreach (var filter in this.Filters) { if (filter.IsMatch(output)) { matched = true; break; } } if (!matched) { return; } } if (this.Writer != null) { try { this.Writer.WriteLine(output); this.Writer.Flush(); // flush after every line -- performance? meh } catch (ObjectDisposedException) { } // finalizer may come nuke the TextWriter in some edge cases. } }
public void CanSafelyCastEnumsToIntegerTypes() { var ev = new ETWEvent(DateTime.Now, Guid.NewGuid(), "fakeProvider", 1, "fakeEvent", 1, EventKeywords.None, EventLevel.Informational, EventOpcode.Info, Guid.Empty, 867, 4309, new OrderedDictionary { {"signed", FakeSignedEnum.FakeValue}, {"unsigned", FakeUnsignedEnum.FakeValue} }); Assert.AreEqual((int)FakeSignedEnum.FakeValue, ev.Parameter<int>("signed")); Assert.AreEqual((uint)FakeSignedEnum.FakeValue, ev.Parameter<uint>("signed")); Assert.AreEqual((int)FakeUnsignedEnum.FakeValue, ev.Parameter<int>("unsigned")); Assert.AreEqual((uint)FakeUnsignedEnum.FakeValue, ev.Parameter<uint>("unsigned")); }