11// Copyright (c) .NET Foundation and contributors. All rights reserved.
22// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33
4+ using System . Runtime . CompilerServices ;
45using System . Threading ;
56using System . Threading . Tasks ;
67
@@ -10,8 +11,16 @@ internal static class InvocationPipeline
1011 {
1112 internal static async Task < int > InvokeAsync ( ParseResult parseResult , CancellationToken cancellationToken )
1213 {
14+ using var invokeActivity = Activities . ActivitySource . StartActivity ( DiagnosticsStrings . InvokeMethod ) ;
15+ if ( invokeActivity is not null )
16+ {
17+ invokeActivity . DisplayName = parseResult . CommandResult . FullCommandName ( ) ;
18+ invokeActivity . AddTag ( DiagnosticsStrings . Command , parseResult . CommandResult . Command . Name ) ;
19+ }
20+
1321 if ( parseResult . Action is null )
1422 {
23+ invokeActivity ? . SetStatus ( Diagnostics . ActivityStatusCode . Error ) ;
1524 return ReturnCodeForMissingAction ( parseResult ) ;
1625 }
1726
@@ -41,7 +50,9 @@ internal static async Task<int> InvokeAsync(ParseResult parseResult, Cancellatio
4150 switch ( parseResult . Action )
4251 {
4352 case SynchronousCommandLineAction syncAction :
44- return syncAction . Invoke ( parseResult ) ;
53+ var syncResult = syncAction . Invoke ( parseResult ) ;
54+ invokeActivity ? . SetExitCode ( syncResult ) ;
55+ return syncResult ;
4556
4657 case AsynchronousCommandLineAction asyncAction :
4758 var startedInvocation = asyncAction . InvokeAsync ( parseResult , cts . Token ) ;
@@ -52,23 +63,30 @@ internal static async Task<int> InvokeAsync(ParseResult parseResult, Cancellatio
5263
5364 if ( terminationHandler is null )
5465 {
55- return await startedInvocation ;
66+ var asyncResult = await startedInvocation ;
67+ invokeActivity ? . SetExitCode ( asyncResult ) ;
68+ return asyncResult ;
5669 }
5770 else
5871 {
5972 // Handlers may not implement cancellation.
6073 // In such cases, when CancelOnProcessTermination is configured and user presses Ctrl+C,
6174 // ProcessTerminationCompletionSource completes first, with the result equal to native exit code for given signal.
6275 Task < int > firstCompletedTask = await Task . WhenAny ( startedInvocation , terminationHandler . ProcessTerminationCompletionSource . Task ) ;
63- return await firstCompletedTask ; // return the result or propagate the exception
76+ var asyncResult = await firstCompletedTask ; // return the result or propagate the exception
77+ invokeActivity ? . SetExitCode ( asyncResult ) ;
78+ return asyncResult ;
6479 }
6580
6681 default :
67- throw new ArgumentOutOfRangeException ( nameof ( parseResult . Action ) ) ;
82+ var error = new ArgumentOutOfRangeException ( nameof ( parseResult . Action ) ) ;
83+ invokeActivity ? . Error ( error ) ;
84+ throw error ;
6885 }
6986 }
7087 catch ( Exception ex ) when ( parseResult . Configuration . EnableDefaultExceptionHandler )
7188 {
89+ invokeActivity ? . Error ( ex ) ;
7290 return DefaultExceptionHandler ( ex , parseResult . Configuration ) ;
7391 }
7492 finally
@@ -79,9 +97,17 @@ internal static async Task<int> InvokeAsync(ParseResult parseResult, Cancellatio
7997
8098 internal static int Invoke ( ParseResult parseResult )
8199 {
100+ using var invokeActivity = Activities . ActivitySource . StartActivity ( DiagnosticsStrings . InvokeMethod ) ;
101+ if ( invokeActivity is not null )
102+ {
103+ invokeActivity . DisplayName = parseResult . CommandResult . FullCommandName ( ) ;
104+ invokeActivity . AddTag ( DiagnosticsStrings . Command , parseResult . CommandResult . Command . Name ) ;
105+ }
106+
82107 switch ( parseResult . Action )
83108 {
84109 case null :
110+ invokeActivity ? . Error ( ) ;
85111 return ReturnCodeForMissingAction ( parseResult ) ;
86112
87113 case SynchronousCommandLineAction syncAction :
@@ -112,15 +138,20 @@ internal static int Invoke(ParseResult parseResult)
112138 }
113139 }
114140
115- return syncAction . Invoke ( parseResult ) ;
141+ var result = syncAction . Invoke ( parseResult ) ;
142+ invokeActivity ? . SetExitCode ( result ) ;
143+ return result ;
116144 }
117145 catch ( Exception ex ) when ( parseResult . Configuration . EnableDefaultExceptionHandler )
118146 {
147+ invokeActivity ? . Error ( ex ) ;
119148 return DefaultExceptionHandler ( ex , parseResult . Configuration ) ;
120149 }
121150
122151 default :
123- throw new InvalidOperationException ( $ "{ nameof ( AsynchronousCommandLineAction ) } called within non-async invocation.") ;
152+ var error = new InvalidOperationException ( $ "{ nameof ( AsynchronousCommandLineAction ) } called within non-async invocation.") ;
153+ invokeActivity ? . Error ( error ) ;
154+ throw error ;
124155 }
125156 }
126157
@@ -150,5 +181,38 @@ private static int ReturnCodeForMissingAction(ParseResult parseResult)
150181 return 0 ;
151182 }
152183 }
184+
185+ private static void Succeed ( this Diagnostics . Activity activity )
186+ {
187+ activity . SetStatus ( Diagnostics . ActivityStatusCode . Ok ) ;
188+ activity . AddTag ( DiagnosticsStrings . ExitCode , 0 ) ;
189+ }
190+ private static void Error ( this Diagnostics . Activity activity , int statusCode )
191+ {
192+ activity . SetStatus ( Diagnostics . ActivityStatusCode . Error ) ;
193+ activity . AddTag ( DiagnosticsStrings . ExitCode , statusCode ) ;
194+ }
195+
196+ private static void Error ( this Diagnostics . Activity activity , Exception ? exception = null )
197+ {
198+ activity . SetStatus ( Diagnostics . ActivityStatusCode . Error ) ;
199+ activity . AddTag ( DiagnosticsStrings . ExitCode , 1 ) ;
200+ if ( exception is not null )
201+ {
202+ activity . AddBaggage ( DiagnosticsStrings . Exception , exception . ToString ( ) ) ;
203+ }
204+ }
205+
206+ private static void SetExitCode ( this Diagnostics . Activity activity , int exitCode )
207+ {
208+ if ( exitCode == 0 )
209+ {
210+ activity . Succeed ( ) ;
211+ }
212+ else
213+ {
214+ activity . Error ( exitCode ) ;
215+ }
216+ }
153217 }
154218}
0 commit comments