1313using System . Threading . Tasks ;
1414using Microsoft . Diagnostics . Monitoring . EventPipe ;
1515using Microsoft . Diagnostics . NETCore . Client ;
16+ using Microsoft . Diagnostics . Tools . Common ;
1617using Microsoft . Internal . Common ;
1718using Microsoft . Internal . Common . Utils ;
1819
1920namespace Microsoft . Diagnostics . Tools . Trace
2021{
21- internal static class CollectCommandHandler
22+ internal class CollectCommandHandler
2223 {
23- internal static bool IsQuiet { get ; set ; }
24+ internal bool IsQuiet { get ; set ; }
2425
25- private static void ConsoleWriteLine ( string str )
26+ public CollectCommandHandler ( )
27+ {
28+ Console = new DefaultConsole ( false ) ;
29+ StartTraceSessionAsync = async ( client , config , ct ) => new CollectSession ( await client . StartEventPipeSessionAsync ( config , ct ) . ConfigureAwait ( false ) ) ;
30+ ResumeRuntimeAsync = ( client , ct ) => client . ResumeRuntimeAsync ( ct ) ;
31+ CollectSessionEventStream = name => new FileStream ( name , FileMode . Create , FileAccess . Write ) ;
32+ IsOutputRedirected = Console . IsOutputRedirected ;
33+ }
34+
35+ private void ConsoleWriteLine ( string str )
2636 {
2737 if ( ! IsQuiet )
2838 {
@@ -54,7 +64,7 @@ private static void ConsoleWriteLine(string str)
5464 /// <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>
5565 /// <param name="rundown">Collect rundown events.</param>
5666 /// <returns></returns>
57- internal 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 )
67+ internal 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 )
5868 {
5969 bool collectionStopped = false ;
6070 bool cancelOnEnter = true ;
@@ -79,7 +89,7 @@ internal static async Task<int> Collect(CancellationToken ct, CommandLineConfigu
7989 {
8090 cancelOnCtrlC = true ;
8191 cancelOnEnter = ! Console . IsInputRedirected ;
82- printStatusOverTime = ! IsOutputRedirected ( ) ;
92+ printStatusOverTime = ! IsOutputRedirected ;
8393 }
8494
8595 if ( ! cancelOnCtrlC )
@@ -357,10 +367,10 @@ internal static async Task<int> Collect(CancellationToken ct, CommandLineConfigu
357367
358368 LineRewriter rewriter = null ;
359369
360- using ( FileStream fs = new ( output . FullName , FileMode . Create , FileAccess . Write ) )
370+ using ( Stream eventStream = CollectSessionEventStream ( output . FullName ) )
361371 {
362372 ConsoleWriteLine ( $ "Process : { processMainModuleFileName } ") ;
363- ConsoleWriteLine ( $ "Output File : { fs . Name } ") ;
373+ ConsoleWriteLine ( $ "Output File : { output . FullName } ") ;
364374 if ( shouldStopAfterDuration )
365375 {
366376 ConsoleWriteLine ( $ "Trace Duration : { duration : dd\\:hh\\:mm\\:ss} ") ;
@@ -383,14 +393,14 @@ internal static async Task<int> Collect(CancellationToken ct, CommandLineConfigu
383393 onPayloadFilterMismatch : ( traceEvent ) => {
384394 ConsoleWriteLine ( $ "One or more field names specified in the payload filter for event '{ traceEvent . ProviderName } /{ traceEvent . EventName } ' do not match any of the known field names: '{ string . Join ( ' ' , traceEvent . PayloadNames ) } '. As a result the requested stopping event is unreachable; will continue to collect the trace for the remaining specified duration.") ;
385395 } ,
386- eventStream : new PassthroughStream ( session . EventStream , fs , ( int ) buffersize , leaveDestinationStreamOpen : true ) ,
396+ eventStream : new PassthroughStream ( session . EventStream , eventStream , ( int ) buffersize , leaveDestinationStreamOpen : true ) ,
387397 callOnEventOnlyOnce : true ) ;
388398
389399 copyTask = eventMonitor . ProcessAsync ( CancellationToken . None ) ;
390400 }
391401 else
392402 {
393- copyTask = session . EventStream . CopyToAsync ( fs ) ;
403+ copyTask = session . EventStream . CopyToAsync ( eventStream ) ;
394404 }
395405 Task shouldExitTask = copyTask . ContinueWith (
396406 ( task ) => shouldExit . Set ( ) ,
@@ -400,7 +410,7 @@ internal static async Task<int> Collect(CancellationToken ct, CommandLineConfigu
400410
401411 if ( printStatusOverTime )
402412 {
403- if ( AreCursorOperationsSupported ( ) )
413+ if ( CursorOperationsSupported )
404414 {
405415 rewriter = new LineRewriter { LineToClear = Console . CursorTop - 1 } ;
406416 Console . CursorVisible = false ;
@@ -506,7 +516,7 @@ internal static async Task<int> Collect(CancellationToken ct, CommandLineConfigu
506516 }
507517 finally
508518 {
509- if ( printStatusOverTime && AreCursorOperationsSupported ( ) )
519+ if ( printStatusOverTime && CursorOperationsSupported )
510520 {
511521 if ( ! Console . IsOutputRedirected )
512522 {
@@ -527,7 +537,7 @@ internal static async Task<int> Collect(CancellationToken ct, CommandLineConfigu
527537 return ret ;
528538 }
529539
530- private static void PrintProviders ( IReadOnlyList < EventPipeProvider > providers , Dictionary < string , string > enabledBy )
540+ private void PrintProviders ( IReadOnlyList < EventPipeProvider > providers , Dictionary < string , string > enabledBy )
531541 {
532542 ConsoleWriteLine ( "" ) ;
533543 ConsoleWriteLine ( string . Format ( "{0, -40}" , "Provider Name" ) + string . Format ( "{0, -20}" , "Keywords" ) +
@@ -588,27 +598,30 @@ public static Command CollectCommand()
588598 collectCommand . TreatUnmatchedTokensAsErrors = false ; // see the logic in Program.Main that handles UnmatchedTokens
589599 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." ;
590600
591- collectCommand . SetAction ( ( parseResult , ct ) => Collect (
592- ct ,
593- cliConfig : parseResult . Configuration ,
594- processId : parseResult . GetValue ( CommonOptions . ProcessIdOption ) ,
595- output : parseResult . GetValue ( OutputPathOption ) ,
596- buffersize : parseResult . GetValue ( CircularBufferOption ) ,
597- providers : parseResult . GetValue ( ProvidersOption ) ?? string . Empty ,
598- profile : parseResult . GetValue ( ProfileOption ) ?? string . Empty ,
599- format : parseResult . GetValue ( CommonOptions . FormatOption ) ,
600- duration : parseResult . GetValue ( DurationOption ) ,
601- clrevents : parseResult . GetValue ( CLREventsOption ) ?? string . Empty ,
602- clreventlevel : parseResult . GetValue ( CLREventLevelOption ) ?? string . Empty ,
603- name : parseResult . GetValue ( CommonOptions . NameOption ) ,
604- diagnosticPort : parseResult . GetValue ( DiagnosticPortOption ) ?? string . Empty ,
605- showchildio : parseResult . GetValue ( ShowChildIOOption ) ,
606- resumeRuntime : parseResult . GetValue ( ResumeRuntimeOption ) ,
607- stoppingEventProviderName : parseResult . GetValue ( StoppingEventProviderNameOption ) ,
608- stoppingEventEventName : parseResult . GetValue ( StoppingEventEventNameOption ) ,
609- stoppingEventPayloadFilter : parseResult . GetValue ( StoppingEventPayloadFilterOption ) ,
610- rundown : parseResult . GetValue ( RundownOption ) ,
611- dsrouter : parseResult . GetValue ( DSRouterOption ) ) ) ;
601+ collectCommand . SetAction ( ( parseResult , ct ) =>
602+ {
603+ CollectCommandHandler handler = new ( ) ;
604+ return handler . Collect ( ct ,
605+ cliConfig : parseResult . Configuration ,
606+ processId : parseResult . GetValue ( CommonOptions . ProcessIdOption ) ,
607+ output : parseResult . GetValue ( OutputPathOption ) ,
608+ buffersize : parseResult . GetValue ( CircularBufferOption ) ,
609+ providers : parseResult . GetValue ( ProvidersOption ) ?? string . Empty ,
610+ profile : parseResult . GetValue ( ProfileOption ) ?? string . Empty ,
611+ format : parseResult . GetValue ( CommonOptions . FormatOption ) ,
612+ duration : parseResult . GetValue ( DurationOption ) ,
613+ clrevents : parseResult . GetValue ( CLREventsOption ) ?? string . Empty ,
614+ clreventlevel : parseResult . GetValue ( CLREventLevelOption ) ?? string . Empty ,
615+ name : parseResult . GetValue ( CommonOptions . NameOption ) ,
616+ diagnosticPort : parseResult . GetValue ( DiagnosticPortOption ) ?? string . Empty ,
617+ showchildio : parseResult . GetValue ( ShowChildIOOption ) ,
618+ resumeRuntime : parseResult . GetValue ( ResumeRuntimeOption ) ,
619+ stoppingEventProviderName : parseResult . GetValue ( StoppingEventProviderNameOption ) ,
620+ stoppingEventEventName : parseResult . GetValue ( StoppingEventEventNameOption ) ,
621+ stoppingEventPayloadFilter : parseResult . GetValue ( StoppingEventPayloadFilterOption ) ,
622+ rundown : parseResult . GetValue ( RundownOption ) ,
623+ dsrouter : parseResult . GetValue ( DSRouterOption ) ) ;
624+ } ) ;
612625
613626 return collectCommand ;
614627 }
@@ -735,14 +748,12 @@ private sealed class CollectSession : ICollectSession
735748 public void Dispose ( ) => _session . Dispose ( ) ;
736749 }
737750
738- internal static Func < DiagnosticsClient , EventPipeSessionConfiguration , CancellationToken , Task < ICollectSession > > StartTraceSessionAsync { get ; set ; }
739- = async ( client , config , ct ) => new CollectSession ( await client . StartEventPipeSessionAsync ( config , ct ) . ConfigureAwait ( false ) ) ;
740-
741- internal static Func < DiagnosticsClient , CancellationToken , Task > ResumeRuntimeAsync { get ; set ; }
742- = ( client , ct ) => client . ResumeRuntimeAsync ( ct ) ;
743-
744- internal static Func < bool > IsOutputRedirected { get ; set ; } = ( ) => Console . IsOutputRedirected ;
745- internal static Func < bool > AreCursorOperationsSupported { get ; set ; } = ( ) => true ;
751+ internal Func < DiagnosticsClient , EventPipeSessionConfiguration , CancellationToken , Task < ICollectSession > > StartTraceSessionAsync { get ; set ; }
752+ internal Func < DiagnosticsClient , CancellationToken , Task > ResumeRuntimeAsync { get ; set ; }
753+ internal bool CursorOperationsSupported { get ; set ; } = true ;
754+ internal Func < string , Stream > CollectSessionEventStream { get ; set ; }
755+ internal IConsole Console { get ; set ; }
756+ internal bool IsOutputRedirected { get ; set ; }
746757#endregion
747758 }
748759}
0 commit comments