Skip to content

Commit eff3e5f

Browse files
committed
[DotnetTrace][CollectLinux] Add ProgressStatus and output file to tests
1 parent 208086f commit eff3e5f

File tree

2 files changed

+146
-122
lines changed

2 files changed

+146
-122
lines changed

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

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,6 @@ private byte[] BuildRecordTraceArgs(CollectLinuxArgs args, out string scriptPath
135135
scriptPath = null;
136136
List<string> recordTraceArgs = new();
137137

138-
string resolvedOutput = ResolveOutputPath(args.Output);
139-
recordTraceArgs.Add($"--out");
140-
recordTraceArgs.Add(resolvedOutput);
141-
142138
string[] profiles = args.Profiles;
143139
if (args.Profiles.Length == 0 && args.Providers.Length == 0 && string.IsNullOrEmpty(args.ClrEvents) && args.PerfEvents.Length == 0)
144140
{
@@ -169,17 +165,18 @@ private byte[] BuildRecordTraceArgs(CollectLinuxArgs args, out string scriptPath
169165
scriptBuilder.Append($"record_dotnet_provider(\"{providerName}\", 0x{keywords:X}, {eventLevel}, {providerNameSanitized}_flags);\n\n");
170166
}
171167

172-
Console.WriteLine($"{("Linux Events"),-80}Enabled By");
168+
List<string> linuxEventLines = new();
173169
foreach (string profile in profiles)
174170
{
175171
Profile traceProfile = ListProfilesCommandHandler.TraceProfiles
176172
.FirstOrDefault(p => p.Name.Equals(profile, StringComparison.OrdinalIgnoreCase));
177173

178-
if (!string.IsNullOrEmpty(traceProfile.VerbExclusivity) &&
174+
if (traceProfile != null &&
175+
!string.IsNullOrEmpty(traceProfile.VerbExclusivity) &&
179176
traceProfile.VerbExclusivity.Equals("collect-linux", StringComparison.OrdinalIgnoreCase))
180177
{
181178
recordTraceArgs.Add(traceProfile.CollectLinuxArgs);
182-
Console.WriteLine($"{traceProfile.Name,-80}--profile");
179+
linuxEventLines.Add($"{traceProfile.Name,-80}--profile");
183180
}
184181
}
185182

@@ -193,14 +190,32 @@ private byte[] BuildRecordTraceArgs(CollectLinuxArgs args, out string scriptPath
193190

194191
string perfProvider = split[0];
195192
string perfEventName = split[1];
196-
Console.WriteLine($"{perfEvent,-80}--perf-events");
193+
linuxEventLines.Add($"{perfEvent,-80}--perf-events");
197194
scriptBuilder.Append($"let {perfEventName} = event_from_tracefs(\"{perfProvider}\", \"{perfEventName}\");\nrecord_event({perfEventName});\n\n");
198195
}
196+
197+
if (linuxEventLines.Count > 0)
198+
{
199+
Console.WriteLine($"{("Linux Perf Events"),-80}Enabled By");
200+
foreach (string line in linuxEventLines)
201+
{
202+
Console.WriteLine(line);
203+
}
204+
}
205+
else
206+
{
207+
Console.WriteLine("No Linux Perf Events enabled.");
208+
}
209+
Console.WriteLine();
210+
211+
FileInfo resolvedOutput = ResolveOutputPath(args.Output);
212+
recordTraceArgs.Add($"--out");
213+
recordTraceArgs.Add(resolvedOutput.FullName);
214+
Console.WriteLine($"Output File : {resolvedOutput.FullName}");
199215
Console.WriteLine();
200216

201217
string scriptText = scriptBuilder.ToString();
202-
string scriptFileName = $"{Path.GetFileNameWithoutExtension(resolvedOutput)}.script";
203-
scriptPath = Path.Combine(Environment.CurrentDirectory, scriptFileName);
218+
scriptPath = Path.ChangeExtension(resolvedOutput.FullName, ".script");
204219
File.WriteAllText(scriptPath, scriptText);
205220

206221
recordTraceArgs.Add("--script-file");
@@ -210,15 +225,15 @@ private byte[] BuildRecordTraceArgs(CollectLinuxArgs args, out string scriptPath
210225
return Encoding.UTF8.GetBytes(options);
211226
}
212227

213-
private static string ResolveOutputPath(FileInfo output)
228+
private static FileInfo ResolveOutputPath(FileInfo output)
214229
{
215230
if (!string.Equals(output.Name, CommonOptions.DefaultTraceName, StringComparison.OrdinalIgnoreCase))
216231
{
217-
return output.Name;
232+
return output;
218233
}
219234

220235
DateTime now = DateTime.Now;
221-
return $"trace_{now:yyyyMMdd}_{now:HHmmss}.nettrace";
236+
return new FileInfo($"trace_{now:yyyyMMdd}_{now:HHmmss}.nettrace");
222237
}
223238

224239
private int OutputHandler(uint type, IntPtr data, UIntPtr dataLen)

src/tests/dotnet-trace/CollectLinuxCommandFunctionalTests.cs

Lines changed: 118 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private static CollectLinuxCommandHandler.CollectLinuxArgs TestArgs(
3434
clrEvents,
3535
perfEvents ?? Array.Empty<string>(),
3636
profile ?? Array.Empty<string>(),
37-
output ?? new FileInfo(CommonOptions.DefaultTraceName),
37+
output ?? new FileInfo("trace.nettrace"),
3838
duration);
3939
}
4040

@@ -47,7 +47,7 @@ public void CollectLinuxCommandProviderConfigurationConsolidation(object testArg
4747
if (OperatingSystem.IsLinux())
4848
{
4949
Assert.Equal((int)ReturnCode.Ok, exitCode);
50-
console.AssertSanitizedLinesEqual(null, expectedLines: expectedLines);
50+
console.AssertSanitizedLinesEqual(CollectLinuxSanitizer, expectedLines: expectedLines);
5151
}
5252
else
5353
{
@@ -64,155 +64,121 @@ public void CollectLinuxCommandProviderConfigurationConsolidation_Throws(object
6464
{
6565
MockConsole console = new(200, 30);
6666
int exitCode = Run(testArgs, console);
67-
if (OperatingSystem.IsLinux())
68-
{
69-
Assert.Equal((int)ReturnCode.TracingError, exitCode);
70-
console.AssertSanitizedLinesEqual(null, true, expectedLines: expectedException);
71-
}
72-
else
73-
{
74-
Assert.Equal((int)ReturnCode.PlatformNotSupportedError, exitCode);
75-
console.AssertSanitizedLinesEqual(null, expectedLines: new string[] {
76-
"The collect-linux command is only supported on Linux.",
77-
});
78-
}
67+
Assert.Equal((int)ReturnCode.TracingError, exitCode);
68+
console.AssertSanitizedLinesEqual(null, true, expectedLines: expectedException);
7969
}
8070

8171
private static int Run(object args, MockConsole console)
8272
{
8373
var handler = new CollectLinuxCommandHandler(console);
84-
handler.RecordTraceInvoker = (cmd, len, cb) => 0;
74+
handler.RecordTraceInvoker = (cmd, len, cb) => {
75+
cb(3, IntPtr.Zero, UIntPtr.Zero);
76+
return 0;
77+
};
8578
return handler.CollectLinux((CollectLinuxCommandHandler.CollectLinuxArgs)args);
8679
}
8780

81+
private static string[] CollectLinuxSanitizer(string[] lines)
82+
{
83+
List<string> result = new();
84+
foreach (string line in lines)
85+
{
86+
if (line.Contains("Recording trace.", StringComparison.OrdinalIgnoreCase))
87+
{
88+
result.Add("[dd:hh:mm:ss]\tRecording trace.");
89+
}
90+
else
91+
{
92+
result.Add(line);
93+
}
94+
}
95+
return result.ToArray();
96+
}
8897

8998
public static IEnumerable<object[]> BasicCases()
9099
{
91100
yield return new object[] {
92101
TestArgs(),
93-
new string[] {
94-
"No providers, profiles, ClrEvents, or PerfEvents were specified, defaulting to trace profiles 'dotnet-common' + 'cpu-sampling'.",
95-
"",
96-
ProviderHeader,
97-
FormatProvider("Microsoft-Windows-DotNETRuntime","000000100003801D","Informational",4,"--profile"),
98-
"",
99-
LinuxHeader,
100-
LinuxProfile("cpu-sampling"),
101-
""
102-
}
102+
ExpectProvidersAndLinuxWithMessages(
103+
new[]{"No providers, profiles, ClrEvents, or PerfEvents were specified, defaulting to trace profiles 'dotnet-common' + 'cpu-sampling'."},
104+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","000000100003801D","Informational",4,"--profile")},
105+
new[]{LinuxProfile("cpu-sampling")})
103106
};
107+
104108
yield return new object[] {
105109
TestArgs(providers: new[]{"Foo:0x1:4"}),
106-
new string[] {
107-
"",
108-
ProviderHeader,
109-
FormatProvider("Foo","0000000000000001","Informational",4,"--providers"),
110-
"",
111-
LinuxHeader,
112-
""
113-
}
110+
ExpectProvidersAndLinux(
111+
new[]{FormatProvider("Foo","0000000000000001","Informational",4,"--providers")},
112+
Array.Empty<string>())
114113
};
114+
115115
yield return new object[] {
116116
TestArgs(providers: new[]{"Foo:0x1:4","Bar:0x2:4"}),
117-
new string[] {
118-
"",
119-
ProviderHeader,
120-
FormatProvider("Foo","0000000000000001","Informational",4,"--providers"),
121-
FormatProvider("Bar","0000000000000002","Informational",4,"--providers"),
122-
"",
123-
LinuxHeader,
124-
""
125-
}
117+
ExpectProvidersAndLinux(
118+
new[]{
119+
FormatProvider("Foo","0000000000000001","Informational",4,"--providers"),
120+
FormatProvider("Bar","0000000000000002","Informational",4,"--providers")
121+
},
122+
Array.Empty<string>())
126123
};
124+
127125
yield return new object[] {
128126
TestArgs(profile: new[]{"cpu-sampling"}),
129-
new string[] {
130-
"No .NET providers were configured.",
131-
"",
132-
LinuxHeader,
133-
LinuxProfile("cpu-sampling"),
134-
""
135-
}
127+
ExpectProvidersAndLinuxWithMessages(
128+
new[]{"No .NET providers were configured."},
129+
Array.Empty<string>(),
130+
new[]{LinuxProfile("cpu-sampling")})
136131
};
132+
137133
yield return new object[] {
138134
TestArgs(providers: new[]{"Foo:0x1:4"}, profile: new[]{"cpu-sampling"}),
139-
new string[] {
140-
"",
141-
ProviderHeader,
142-
FormatProvider("Foo","0000000000000001","Informational",4,"--providers"),
143-
"",
144-
LinuxHeader,
145-
LinuxProfile("cpu-sampling"),
146-
""
147-
}
135+
ExpectProvidersAndLinux(
136+
new[]{FormatProvider("Foo","0000000000000001","Informational",4,"--providers")},
137+
new[]{LinuxProfile("cpu-sampling")})
148138
};
139+
149140
yield return new object[] {
150141
TestArgs(clrEvents: "gc", profile: new[]{"cpu-sampling"}),
151-
new string[] {
152-
"",
153-
ProviderHeader,
154-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--clrevents"),
155-
"",
156-
LinuxHeader,
157-
LinuxProfile("cpu-sampling"),
158-
""
159-
}
142+
ExpectProvidersAndLinux(
143+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--clrevents")},
144+
new[]{LinuxProfile("cpu-sampling")})
160145
};
146+
161147
yield return new object[] {
162148
TestArgs(providers: new[]{"Microsoft-Windows-DotNETRuntime:0x1:4"}, profile: new[]{"cpu-sampling"}),
163-
new string[] {
164-
"",
165-
ProviderHeader,
166-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--providers"),
167-
"",
168-
LinuxHeader,
169-
LinuxProfile("cpu-sampling"),
170-
""
171-
}
149+
ExpectProvidersAndLinux(
150+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--providers")},
151+
new[]{LinuxProfile("cpu-sampling")})
172152
};
153+
173154
yield return new object[] {
174155
TestArgs(providers: new[]{"Microsoft-Windows-DotNETRuntime:0x1:4"}, clrEvents: "gc"),
175-
new string[] {
176-
"Warning: The CLR provider was already specified through --providers or --profile. Ignoring --clrevents.",
177-
"",
178-
ProviderHeader,
179-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--providers"),
180-
"",
181-
LinuxHeader,
182-
""
183-
}
156+
ExpectProvidersAndLinuxWithMessages(
157+
new[]{"Warning: The CLR provider was already specified through --providers or --profile. Ignoring --clrevents."},
158+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--providers")},
159+
Array.Empty<string>())
184160
};
161+
185162
yield return new object[] {
186163
TestArgs(clrEvents: "gc+jit"),
187-
new string[] {
188-
"",
189-
ProviderHeader,
190-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000011","Informational",4,"--clrevents"),
191-
"",
192-
LinuxHeader,
193-
""
194-
}
164+
ExpectProvidersAndLinux(
165+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000011","Informational",4,"--clrevents")},
166+
Array.Empty<string>())
195167
};
168+
196169
yield return new object[] {
197170
TestArgs(clrEvents: "gc+jit", clrEventLevel: "5"),
198-
new string[] {
199-
"",
200-
ProviderHeader,
201-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000011","Verbose",5,"--clrevents"),
202-
"",
203-
LinuxHeader,
204-
""
205-
}
171+
ExpectProvidersAndLinux(
172+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000011","Verbose",5,"--clrevents")},
173+
Array.Empty<string>())
206174
};
175+
207176
yield return new object[] {
208177
TestArgs(perfEvents: new[]{"sched:sched_switch"}),
209-
new string[] {
210-
"No .NET providers were configured.",
211-
"",
212-
LinuxHeader,
213-
LinuxPerfEvent("sched:sched_switch"),
214-
""
215-
}
178+
ExpectProvidersAndLinuxWithMessages(
179+
new[]{"No .NET providers were configured."},
180+
Array.Empty<string>(),
181+
new[]{LinuxPerfEvent("sched:sched_switch")})
216182
};
217183
}
218184

@@ -250,7 +216,7 @@ public static IEnumerable<object[]> InvalidProviders()
250216
}
251217

252218
private const string ProviderHeader = "Provider Name Keywords Level Enabled By";
253-
private static string LinuxHeader => $"{"Linux Events",-80}Enabled By";
219+
private static string LinuxHeader => $"{"Linux Perf Events",-80}Enabled By";
254220
private static string LinuxProfile(string name) => $"{name,-80}--profile";
255221
private static string LinuxPerfEvent(string spec) => $"{spec,-80}--perf-events";
256222
private static string FormatProvider(string name, string keywordsHex, string levelName, int levelValue, string enabledBy)
@@ -261,5 +227,48 @@ private static string FormatProvider(string name, string keywordsHex, string lev
261227
return string.Format("{0, -80}", display) + enabledBy;
262228
}
263229
private static string FormatException(string message, string exceptionType) => $"[ERROR] {exceptionType}: {message}";
230+
private static string DefaultOutputFile => $"Output File : {Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar}trace.nettrace";
231+
private static readonly string[] CommonTail = [
232+
DefaultOutputFile,
233+
"",
234+
"[dd:hh:mm:ss]\tRecording trace.",
235+
"Press <Enter> or <Ctrl-C> to exit...",
236+
];
237+
238+
private static string[] ExpectProvidersAndLinux(string[] dotnetProviders, string[] linuxPerfEvents)
239+
=> ExpectProvidersAndLinuxWithMessages(Array.Empty<string>(), dotnetProviders, linuxPerfEvents);
240+
241+
private static string[] ExpectProvidersAndLinuxWithMessages(string[] messages, string[] dotnetProviders, string[] linuxPerfEvents)
242+
{
243+
List<string> result = new();
244+
245+
if (messages.Length > 0)
246+
{
247+
result.AddRange(messages);
248+
}
249+
result.Add("");
250+
251+
if (dotnetProviders.Length > 0)
252+
{
253+
result.Add(ProviderHeader);
254+
result.AddRange(dotnetProviders);
255+
result.Add("");
256+
}
257+
258+
if (linuxPerfEvents.Length > 0)
259+
{
260+
result.Add(LinuxHeader);
261+
result.AddRange(linuxPerfEvents);
262+
}
263+
else
264+
{
265+
result.Add("No Linux Perf Events enabled.");
266+
}
267+
result.Add("");
268+
269+
result.AddRange(CommonTail);
270+
271+
return result.ToArray();
272+
}
264273
}
265274
}

0 commit comments

Comments
 (0)