Skip to content

Commit 0989d21

Browse files
committed
[DotnetTrace] Update collect to new provider unifier
1 parent 5f19a04 commit 0989d21

File tree

2 files changed

+84
-60
lines changed

2 files changed

+84
-60
lines changed

src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs

Lines changed: 31 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private static void ConsoleWriteLine(string str)
5454
/// <param name="stoppingEventPayloadFilter">A string, parsed as [payload_field_name]:[payload_field_value] pairs separated by commas, that will stop the trace upon hitting an event with a matching payload. Requires `--stopping-event-provider-name` and `--stopping-event-event-name` to be set.</param>
5555
/// <param name="rundown">Collect rundown events.</param>
5656
/// <returns></returns>
57-
private static async Task<int> Collect(CancellationToken ct, CommandLineConfiguration cliConfig, int processId, FileInfo output, uint buffersize, string providers, string profile, TraceFileFormat format, TimeSpan duration, string clrevents, string clreventlevel, string name, string diagnosticPort, bool showchildio, bool resumeRuntime, string stoppingEventProviderName, string stoppingEventEventName, string stoppingEventPayloadFilter, bool? rundown, string dsrouter)
57+
private static async Task<int> Collect(CancellationToken ct, CommandLineConfiguration cliConfig, int processId, FileInfo output, uint buffersize, string[] providers, string[] profile, TraceFileFormat format, TimeSpan duration, string clrevents, string clreventlevel, string name, string diagnosticPort, bool showchildio, bool resumeRuntime, string stoppingEventProviderName, string stoppingEventEventName, string stoppingEventPayloadFilter, bool? rundown, string dsrouter)
5858
{
5959
bool collectionStopped = false;
6060
bool cancelOnEnter = true;
@@ -111,34 +111,35 @@ private static async Task<int> Collect(CancellationToken ct, CommandLineConfigur
111111
if (profile.Length == 0 && providers.Length == 0 && clrevents.Length == 0)
112112
{
113113
ConsoleWriteLine("No profile or providers specified, defaulting to trace profile 'dotnet-common'");
114-
profile = "dotnet-common";
114+
profile = new[] { "dotnet-common" };
115115
}
116116

117-
Dictionary<string, string> enabledBy = new();
118-
119-
List<EventPipeProvider> providerCollection = ProviderUtils.ToProviders(providers);
120-
foreach (EventPipeProvider providerCollectionProvider in providerCollection)
121-
{
122-
enabledBy[providerCollectionProvider.Name] = "--providers ";
123-
}
124-
125-
long rundownKeyword = EventPipeSession.DefaultRundownKeyword;
117+
long rundownKeyword = 0;
126118
RetryStrategy retryStrategy = RetryStrategy.NothingToRetry;
127119

128120
if (profile.Length != 0)
129121
{
130-
Profile selectedProfile = ListProfilesCommandHandler.DotNETRuntimeProfiles
131-
.FirstOrDefault(p => p.Name.Equals(profile, StringComparison.OrdinalIgnoreCase));
132-
if (selectedProfile == null)
122+
foreach (string prof in profile)
133123
{
134-
Console.Error.WriteLine($"Invalid profile name: {profile}");
135-
return (int)ReturnCode.ArgumentError;
136-
}
124+
Profile selectedProfile = ListProfilesCommandHandler.DotNETRuntimeProfiles
125+
.FirstOrDefault(p => p.Name.Equals(prof, StringComparison.OrdinalIgnoreCase));
126+
if (selectedProfile == null)
127+
{
128+
Console.Error.WriteLine($"Invalid profile name: {prof}");
129+
return (int)ReturnCode.ArgumentError;
130+
}
137131

138-
rundownKeyword = selectedProfile.RundownKeyword;
139-
retryStrategy = selectedProfile.RetryStrategy;
132+
rundownKeyword |= selectedProfile.RundownKeyword;
133+
if (selectedProfile.RetryStrategy > retryStrategy)
134+
{
135+
retryStrategy = selectedProfile.RetryStrategy;
136+
}
137+
}
138+
}
140139

141-
ProviderUtils.MergeProfileAndProviders(selectedProfile, providerCollection, enabledBy);
140+
if (rundownKeyword == 0)
141+
{
142+
rundownKeyword = EventPipeSession.DefaultRundownKeyword;
142143
}
143144

144145
if (rundown.HasValue)
@@ -155,31 +156,13 @@ private static async Task<int> Collect(CancellationToken ct, CommandLineConfigur
155156
}
156157
}
157158

158-
// Parse --clrevents parameter
159-
if (clrevents.Length != 0)
160-
{
161-
// Ignore --clrevents if CLR event provider was already specified via --profile or --providers command.
162-
if (enabledBy.ContainsKey(ProviderUtils.CLREventProviderName))
163-
{
164-
ConsoleWriteLine($"The argument --clrevents {clrevents} will be ignored because the CLR provider was configured via either --profile or --providers command.");
165-
}
166-
else
167-
{
168-
EventPipeProvider clrProvider = ProviderUtils.ToCLREventPipeProvider(clrevents, clreventlevel);
169-
providerCollection.Add(clrProvider);
170-
enabledBy[ProviderUtils.CLREventProviderName] = "--clrevents";
171-
}
172-
}
173-
174-
159+
List<EventPipeProvider> providerCollection = ProviderUtils.ToProviders(providers, clrevents, clreventlevel, profile, !IsQuiet);
175160
if (providerCollection.Count <= 0)
176161
{
177162
Console.Error.WriteLine("No providers were specified to start a trace.");
178163
return (int)ReturnCode.ArgumentError;
179164
}
180165

181-
PrintProviders(providerCollection, enabledBy);
182-
183166
// Validate and parse stoppingEvent parameters: stoppingEventProviderName, stoppingEventEventName, stoppingEventPayloadFilter
184167

185168
bool hasStoppingEventProviderName = !string.IsNullOrEmpty(stoppingEventProviderName);
@@ -524,20 +507,6 @@ private static async Task<int> Collect(CancellationToken ct, CommandLineConfigur
524507
return ret;
525508
}
526509

527-
private static void PrintProviders(IReadOnlyList<EventPipeProvider> providers, Dictionary<string, string> enabledBy)
528-
{
529-
ConsoleWriteLine("");
530-
ConsoleWriteLine(string.Format("{0, -40}", "Provider Name") + string.Format("{0, -20}", "Keywords") +
531-
string.Format("{0, -20}", "Level") + "Enabled By"); // +4 is for the tab
532-
foreach (EventPipeProvider provider in providers)
533-
{
534-
ConsoleWriteLine(string.Format("{0, -80}", $"{GetProviderDisplayString(provider)}") + $"{enabledBy[provider.Name]}");
535-
}
536-
ConsoleWriteLine("");
537-
}
538-
private static string GetProviderDisplayString(EventPipeProvider provider) =>
539-
string.Format("{0, -40}", provider.Name) + string.Format("0x{0, -18}", $"{provider.Keywords:X16}") + string.Format("{0, -8}", provider.EventLevel.ToString() + $"({(int)provider.EventLevel})");
540-
541510
private static string GetSize(long length)
542511
{
543512
if (length > 1e9)
@@ -585,14 +554,18 @@ public static Command CollectCommand()
585554
collectCommand.TreatUnmatchedTokensAsErrors = false; // see the logic in Program.Main that handles UnmatchedTokens
586555
collectCommand.Description = "Collects a diagnostic trace from a currently running process or launch a child process and trace it. Append -- to the collect command to instruct the tool to run a command and trace it immediately. When tracing a child process, the exit code of dotnet-trace shall be that of the traced process unless the trace process encounters an error.";
587556

588-
collectCommand.SetAction((parseResult, ct) => Collect(
557+
collectCommand.SetAction((parseResult, ct) => {
558+
string providersValue = parseResult.GetValue(CommonOptions.ProvidersOption) ?? string.Empty;
559+
string profileValue = parseResult.GetValue(CommonOptions.ProfileOption) ?? string.Empty;
560+
561+
return Collect(
589562
ct,
590563
cliConfig: parseResult.Configuration,
591564
processId: parseResult.GetValue(CommonOptions.ProcessIdOption),
592565
output: parseResult.GetValue(CommonOptions.OutputPathOption),
593566
buffersize: parseResult.GetValue(CircularBufferOption),
594-
providers: parseResult.GetValue(CommonOptions.ProvidersOption) ?? string.Empty,
595-
profile: parseResult.GetValue(CommonOptions.ProfileOption) ?? string.Empty,
567+
providers: providersValue.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries),
568+
profile: profileValue.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries),
596569
format: parseResult.GetValue(CommonOptions.FormatOption),
597570
duration: parseResult.GetValue(CommonOptions.DurationOption),
598571
clrevents: parseResult.GetValue(CommonOptions.CLREventsOption) ?? string.Empty,
@@ -605,7 +578,8 @@ public static Command CollectCommand()
605578
stoppingEventEventName: parseResult.GetValue(StoppingEventEventNameOption),
606579
stoppingEventPayloadFilter: parseResult.GetValue(StoppingEventPayloadFilterOption),
607580
rundown: parseResult.GetValue(RundownOption),
608-
dsrouter: parseResult.GetValue(DSRouterOption)));
581+
dsrouter: parseResult.GetValue(DSRouterOption));
582+
});
609583

610584
return collectCommand;
611585
}

src/Tools/dotnet-trace/ProviderUtils.cs

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ internal static class ProviderUtils
6464
{ "allocationsampling", 0x80000000000 },
6565
};
6666

67+
private enum ProviderSource
68+
{
69+
ProvidersArg = 1,
70+
CLREventsArg = 2,
71+
ProfileArg = 4,
72+
}
73+
6774
public static void MergeProfileAndProviders(Profile selectedProfile, List<EventPipeProvider> providerCollection, Dictionary<string, string> enabledBy)
6875
{
6976
List<EventPipeProvider> profileProviders = new();
@@ -144,16 +151,18 @@ public static List<EventPipeProvider> ToProviders(string providersRawInput)
144151
return providers.ToList();
145152
}
146153

147-
public static List<EventPipeProvider> ToProviders(string[] providersArg, string clreventsArg, string clreventlevel, string[] profiles)
154+
public static List<EventPipeProvider> ToProviders(string[] providersArg, string clreventsArg, string clreventlevel, string[] profiles, bool shouldPrintProviders)
148155
{
149156
Dictionary<string, EventPipeProvider> merged = new(StringComparer.OrdinalIgnoreCase);
157+
Dictionary<string, int> providerSources = new(StringComparer.OrdinalIgnoreCase);
150158

151159
foreach (string providerArg in providersArg)
152160
{
153161
EventPipeProvider provider = ToProvider(providerArg);
154162
if (!merged.TryGetValue(provider.Name, out EventPipeProvider existing))
155163
{
156164
merged[provider.Name] = provider;
165+
providerSources[provider.Name] = (int)ProviderSource.ProvidersArg;
157166
}
158167
else
159168
{
@@ -169,10 +178,12 @@ public static List<EventPipeProvider> ToProviders(string[] providersArg, string
169178
if (!merged.TryGetValue(provider.Name, out EventPipeProvider existing))
170179
{
171180
merged[provider.Name] = provider;
181+
providerSources[provider.Name] = (int)ProviderSource.CLREventsArg;
172182
}
173183
else
174184
{
175185
merged[provider.Name] = MergeProviderConfigs(existing, provider);
186+
providerSources[provider.Name] |= (int)ProviderSource.CLREventsArg;
176187
}
177188
}
178189
}
@@ -190,12 +201,21 @@ public static List<EventPipeProvider> ToProviders(string[] providersArg, string
190201
IEnumerable<EventPipeProvider> profileProviders = dotnetProfile.Providers;
191202
foreach (EventPipeProvider provider in profileProviders)
192203
{
193-
merged.TryAdd(provider.Name, provider);
204+
if (merged.TryAdd(provider.Name, provider))
205+
{
206+
providerSources[provider.Name] = (int)ProviderSource.ProfileArg;
207+
}
194208
// Prefer providers set through --providers and --clrevents over implicit profile configuration
195209
}
196210
}
197211

198-
return merged.Values.ToList();
212+
List<EventPipeProvider> unifiedProviders = merged.Values.ToList();
213+
if (shouldPrintProviders)
214+
{
215+
PrintProviders(unifiedProviders, providerSources);
216+
}
217+
218+
return unifiedProviders;
199219
}
200220

201221
private static EventPipeProvider MergeProviderConfigs(EventPipeProvider providerConfigA, EventPipeProvider providerConfigB)
@@ -214,6 +234,36 @@ private static EventPipeProvider MergeProviderConfigs(EventPipeProvider provider
214234
return new EventPipeProvider(providerConfigA.Name, level, providerConfigA.Keywords | providerConfigB.Keywords, providerConfigA.Arguments ?? providerConfigB.Arguments);
215235
}
216236

237+
private static void PrintProviders(IReadOnlyList<EventPipeProvider> providers, Dictionary<string, int> enabledBy)
238+
{
239+
Console.WriteLine("");
240+
Console.WriteLine(string.Format("{0, -40}", "Provider Name") + string.Format("{0, -20}", "Keywords") +
241+
string.Format("{0, -20}", "Level") + "Enabled By"); // +4 is for the tab
242+
foreach (EventPipeProvider provider in providers)
243+
{
244+
List<string> providerSources = new();
245+
if (enabledBy.TryGetValue(provider.Name, out int source))
246+
{
247+
if ((source & (int)ProviderSource.ProvidersArg) == (int)ProviderSource.ProvidersArg)
248+
{
249+
providerSources.Add("--providers");
250+
}
251+
if ((source & (int)ProviderSource.CLREventsArg) == (int)ProviderSource.CLREventsArg)
252+
{
253+
providerSources.Add("--clrevents");
254+
}
255+
if ((source & (int)ProviderSource.ProfileArg) == (int)ProviderSource.ProfileArg)
256+
{
257+
providerSources.Add("--profile");
258+
}
259+
}
260+
Console.WriteLine(string.Format("{0, -80}", $"{GetProviderDisplayString(provider)}") + string.Join(", ", providerSources));
261+
}
262+
Console.WriteLine("");
263+
}
264+
private static string GetProviderDisplayString(EventPipeProvider provider) =>
265+
string.Format("{0, -40}", provider.Name) + string.Format("0x{0, -18}", $"{provider.Keywords:X16}") + string.Format("{0, -8}", provider.EventLevel.ToString() + $"({(int)provider.EventLevel})");
266+
217267
public static EventPipeProvider ToCLREventPipeProvider(string clreventslist, string clreventlevel)
218268
{
219269
if (clreventslist == null || clreventslist.Length == 0)

0 commit comments

Comments
 (0)