-
Notifications
You must be signed in to change notification settings - Fork 721
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Missing TraceEventParser for EventSource "Microsoft-Diagnostics-DiagnosticSource" #2010
Comments
I gave it a try and this is what I was able to come up with: using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.Diagnostics.Tracing;
internal class MicrosoftDiagnosticSourceEventParser : TraceEventParser
{
public static readonly string ProviderName = "Microsoft-Diagnostics-DiagnosticSource";
// {adb401e1-5296-51f8-c125-5fda75826144}
public static readonly Guid ProviderGuid = new Guid(unchecked((int)0xadb401e1), unchecked((short)0x5296), unchecked((short)0x51f8), 0xc1, 0x25, 0x5f, 0xda, 0x75, 0x82, 0x61, 0x44);
public MicrosoftDiagnosticSourceEventParser(TraceEventSource source) : base(source) { }
public event Action<CoreActivityTraceData> CoreActivityStop
{
add
{
RegisterTemplate(new CoreActivityTraceData(value, eventID: 65277, task: default, taskName: "CoreActivity", taskGuid: default, opcode: 2, "Stop", ProviderGuid, ProviderName));
}
remove
{
source.UnregisterEventTemplate(value, 1, ProviderGuid);
}
}
public event Action<FrameworkActivityTraceData> FrameworkActivityStop
{
add
{
RegisterTemplate(new FrameworkActivityTraceData(value, eventID: 65276, task: default, taskName: "FrameworkActivity", taskGuid: default, opcode: 2, "Stop", ProviderGuid, ProviderName));
}
remove
{
source.UnregisterEventTemplate(value, 1, ProviderGuid);
}
}
protected override string GetProviderName() => ProviderName;
private static volatile TraceEvent[]? s_templates;
protected override void EnumerateTemplates(Func<string, string, EventFilterResponse> eventsToObserve, Action<TraceEvent> callback)
{
if (s_templates == null)
{
// TODO ActivityStart should be pretty easy to do
var templates = new TraceEvent[2];
templates[0] = new CoreActivityTraceData(null!, eventID: 65277, task: default, taskName: "CoreActivity", taskGuid: default, opcode: 2, "Stop", ProviderGuid, ProviderName);
templates[1] = new FrameworkActivityTraceData(null!, eventID: 65276, task: default, taskName: "FrameworkActivity", taskGuid: default, opcode: 2, "Stop", ProviderGuid, ProviderName);
s_templates = templates;
}
foreach (var template in s_templates)
{
if (eventsToObserve == null || eventsToObserve(template.ProviderName, template.EventName) == EventFilterResponse.AcceptEvent)
{
callback(template);
}
}
}
private void RegisterTemplate(TraceEvent template)
{
Debug.Assert(template.ProviderGuid == MicrosoftDiagnosticSourceEventParser.ProviderGuid);
source.RegisterEventTemplate(template);
}
}
public sealed class CoreActivityTraceData : ActivityTraceData
{
public override string SourceName => GetUnicodeStringAt(0);
public override string ActivityName => GetUnicodeStringAt(SkipUnicodeString(0));
public override KeyValuePair<string, string>[] Arguments
{
get
{
int offset = SkipUnicodeString(0, 2);
int count = GetInt16At(offset);
offset += 2;
var arr = new KeyValuePair<string, string>[count];
for (int i = 0; i < count; i++)
{
var key = GetUnicodeStringAt(offset);
offset = SkipUnicodeString(offset);
var value = GetUnicodeStringAt(offset);
offset = SkipUnicodeString(offset);
arr[i] = new KeyValuePair<string, string>(key, value);
}
return arr;
}
}
internal string GetFixedUnicodeStringAt(int charCount, int offset)
{
// You could do fancy unsafe stuff here, but im ok with the StringBuilder for now
StringBuilder sb = new StringBuilder(charCount);
for (int i = 0; i < charCount; i++)
{
char c = (char)GetInt16At(offset + i * 2);
if (c == 0)
{
break;
}
sb.Append(c);
}
return sb.ToString();
}
internal CoreActivityTraceData(Action<CoreActivityTraceData> action, int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
: base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
{
Action = action;
}
protected override void Dispatch()
{
Action(this);
}
protected override Delegate Target
{
get { return Action; }
set { Action = (Action<CoreActivityTraceData>)value; }
}
private event Action<CoreActivityTraceData> Action;
}
public abstract class ActivityTraceData : TraceEvent
{
protected ActivityTraceData(int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
: base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
{
}
public abstract string SourceName { get; }
public abstract string ActivityName { get; }
public abstract KeyValuePair<string, string>[] Arguments { get; }
public override StringBuilder ToXml(StringBuilder sb)
{
Prefix(sb);
XmlAttrib(sb, "SourceName", SourceName);
XmlAttrib(sb, "ActivityName", ActivityName);
sb.AppendLine(">");
foreach (var kv in Arguments)
{
sb.Append("<Argument");
XmlAttrib(sb, "Name", kv.Key);
XmlAttrib(sb, "Value", kv.Value);
sb.Append("/>");
sb.AppendLine();
}
sb.Append("</Event>");
return sb;
}
public override string[] PayloadNames
{
get
{
if (payloadNames == null)
{
payloadNames = new string[] { "SourceName", "ActivityName", "Arguments" };
}
return payloadNames;
}
}
public override object PayloadValue(int index)
{
switch (index)
{
case 0:
return SourceName;
case 1:
return ActivityName;
case 2:
return Arguments;
default:
Debug.Assert(false, "Bad field index");
return null;
}
}
}
public sealed class FrameworkActivityTraceData : ActivityTraceData
{
public override string SourceName => GetFixedUnicodeStringAt(GetInt16At(0) / 2, 2);
public override string ActivityName
{
get
{
int offset = 2 + GetInt16At(0); // length + string
var length = GetInt16At(offset) / 2;
return GetFixedUnicodeStringAt(length, offset + 2);
}
}
public override KeyValuePair<string, string>[] Arguments
{
get
{
int offset = 2 + GetInt16At(0); // Skip first string
offset += 2 + GetInt16At(offset); // Skip second string
int count = GetInt16At(offset);
offset += 2;
var arr = new KeyValuePair<string, string>[count];
for (int i = 0; i < count; i++)
{
int length = GetInt16At(offset);
offset += 2;
var key = GetFixedUnicodeStringAt(length / 2, offset);
offset += length;
length = GetInt16At(offset);
offset += 2;
var value = GetFixedUnicodeStringAt(length / 2, offset);
offset += length;
arr[i] = new KeyValuePair<string, string>(key, value);
}
return arr;
}
}
internal string GetFixedUnicodeStringAt(int charCount, int offset)
{
// You could do fancy unsafe stuff here, but im ok with the StringBuilder for now
StringBuilder sb = new StringBuilder(charCount);
for (int i = 0; i < charCount; i++)
{
char c = (char)GetInt16At(offset + i * 2);
if (c == 0)
{
break;
}
sb.Append(c);
}
return sb.ToString();
}
internal FrameworkActivityTraceData(Action<FrameworkActivityTraceData> action, int eventID, int task, string taskName, Guid taskGuid, int opcode, string opcodeName, Guid providerGuid, string providerName)
: base(eventID, task, taskName, taskGuid, opcode, opcodeName, providerGuid, providerName)
{
Action = action;
}
protected override void Dispatch()
{
Action(this);
}
protected override Delegate Target
{
get { return Action; }
set { Action = (Action<FrameworkActivityTraceData>)value; }
}
private event Action<FrameworkActivityTraceData> Action;
} |
@ps-weber, you're right that there isn't a manifest for
It is certainly reasonable to write code like what you've written above to parse these events instead of using You are right on the documentation bug - thanks for reporting this. I have posted #2014. |
Ok, this resolve it for me. What I meant by "nested collection" is that I wanted to recover the elements of the collection I collected via |
Thanks for clarifying. Yes, I would expect this to require an issue in https://github.com/dotnet/runtime. |
I want to parse events emitted by the
ActivitySource
class from the Nuget packageSystem.Diagnostics.DiagnosticSource
as described here. Recording the events via TraceEvent/PerfView works and I can see all the data in PerfView.However, I can not read all fields via TraceEvent. The default
DynamicTraceEventParser
can not parse nested collections (These are created using*Enumerate
). I tried generating a TraceEventParser according to the tutorial, but do not get a manifest forMicrosoft-Diagnostics-DiagnosticSource
. I can only find the manifest for "System.Diagnostics.Metrics" which I also use.Also I think there is a small mistake in the tutorial, when i try the command
PerfView /onlyProviders=*Microsoft-Diagnostics-DiagnosticSource EventSource collect
I get an error "Error EventSource not a perfView command"
The text was updated successfully, but these errors were encountered: