Skip to content

Commit

Permalink
trace2: add trace2 error tracing statements
Browse files Browse the repository at this point in the history
Add TRACE2 error tracing statements throughout GCM codebase. Note that
this is a best effort - there are certain places (most notably static and
unsafe methods) where statements were purposefully not added because it is
either not safe or was deemed to much lift/churn to do so.
  • Loading branch information
ldennington committed Mar 17, 2023
1 parent dce1d3e commit 2bb8414
Show file tree
Hide file tree
Showing 34 changed files with 505 additions and 178 deletions.
11 changes: 8 additions & 3 deletions src/shared/Atlassian.Bitbucket.UI/Commands/CredentialsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ private async Task<int> ExecuteAsync(Uri url, string userName, bool showOAuth, b

if (!viewModel.WindowResult || viewModel.SelectedMode == AuthenticationModes.None)
{
throw new Exception("User cancelled dialog.");
var message = "User cancelled dialog.";
Context.Trace2.WriteError(message);
throw new Exception(message);
}

switch (viewModel.SelectedMode)
Expand All @@ -70,8 +72,11 @@ private async Task<int> ExecuteAsync(Uri url, string userName, bool showOAuth, b
break;

default:
throw new ArgumentOutOfRangeException(nameof(AuthenticationModes),
"Unknown authentication mode", viewModel.SelectedMode.ToString());
var actualValue = "Unknown authentication mode";
var message = viewModel.SelectedMode.ToString();

Context.Trace2.WriteError($"{actualValue}: {message}");
throw new ArgumentOutOfRangeException(nameof(AuthenticationModes), actualValue, message);
}

return 0;
Expand Down
22 changes: 18 additions & 4 deletions src/shared/Atlassian.Bitbucket/BitbucketAuthentication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ public async Task<CredentialsPromptResult> GetCredentialsAsync(Uri targetUri, st
// We need at least one mode!
if (modes == AuthenticationModes.None)
{
var format = @"Must specify at least one {0}";
var message = string.Format(format, nameof(AuthenticationModes));

Context.Trace2.WriteError(message, format);
throw new ArgumentException(@$"Must specify at least one {nameof(AuthenticationModes)}", nameof(modes));
}

Expand Down Expand Up @@ -128,12 +132,16 @@ public async Task<CredentialsPromptResult> GetCredentialsAsync(Uri targetUri, st
{
if (!output.TryGetValue("username", out userName))
{
throw new Exception("Missing username in response");
var message = "Missing username in response";
Context.Trace2.WriteError(message);
throw new Exception(message);
}

if (!output.TryGetValue("password", out password))
{
throw new Exception("Missing password in response");
var message = "Missing password in response";
Context.Trace2.WriteError(message);
throw new Exception(message);
}

return new CredentialsPromptResult(
Expand Down Expand Up @@ -172,7 +180,11 @@ public async Task<CredentialsPromptResult> GetCredentialsAsync(Uri targetUri, st
return new CredentialsPromptResult(AuthenticationModes.OAuth);

case AuthenticationModes.None:
throw new ArgumentOutOfRangeException(nameof(modes), @$"At least one {nameof(AuthenticationModes)} must be supplied");
var format = "At least one {0} must be supplied";
var message = string.Format(format, nameof(AuthenticationModes));

Context.Trace2.WriteError(message, format);
throw new ArgumentOutOfRangeException(nameof(modes), message);

default:
var menuTitle = $"Select an authentication method for '{targetUri}'";
Expand All @@ -190,7 +202,9 @@ public async Task<CredentialsPromptResult> GetCredentialsAsync(Uri targetUri, st
if (choice == oauthItem) goto case AuthenticationModes.OAuth;
if (choice == basicItem) goto case AuthenticationModes.Basic;

throw new Exception();
Exception e = new Exception();
Context.Trace2.WriteError(e.Message);
throw e;
}
}
}
Expand Down
50 changes: 38 additions & 12 deletions src/shared/Atlassian.Bitbucket/BitbucketHostProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Atlassian.Bitbucket.Cloud;
using GitCredentialManager;
Expand Down Expand Up @@ -79,7 +80,10 @@ public async Task<ICredential> GetCredentialAsync(InputArguments input)
if (StringComparer.OrdinalIgnoreCase.Equals(input.Protocol, "http")
&& BitbucketHelper.IsBitbucketOrg(input))
{
throw new Exception("Unencrypted HTTP is not supported for Bitbucket.org. Ensure the repository remote URL is using HTTPS.");
var message =
"Unencrypted HTTP is not supported for Bitbucket.org. Ensure the repository remote URL is using HTTPS.";
_context.Trace2.WriteError(message);
throw new Exception(message);
}

var authModes = await GetSupportedAuthenticationModesAsync(input);
Expand Down Expand Up @@ -145,8 +149,10 @@ private async Task<ICredential> GetRefreshedCredentials(InputArguments input, Au
var result = await _bitbucketAuth.GetCredentialsAsync(remoteUri, input.UserName, authModes);
if (result is null || result.AuthenticationMode == AuthenticationModes.None)
{
_context.Trace.WriteLine("User cancelled credential prompt");
throw new Exception("User cancelled credential prompt.");
var message = "User cancelled credential prompt";
_context.Trace.WriteLine(message);
_context.Trace2.WriteError(message);
throw new Exception(message);
}

switch (result.AuthenticationMode)
Expand All @@ -160,8 +166,10 @@ private async Task<ICredential> GetRefreshedCredentials(InputArguments input, Au
break;

default:
throw new ArgumentOutOfRangeException(
$"Unexpected {nameof(AuthenticationModes)} returned from prompt");
var format = "Unexpected {0} returned from prompt";
var message = string.Format(format, nameof(AuthenticationModes));
_context.Trace2.WriteError(message, format);
throw new ArgumentOutOfRangeException(message);
}

// Fall through to the start of the interactive OAuth authentication flow
Expand All @@ -176,8 +184,10 @@ private async Task<ICredential> GetRefreshedCredentials(InputArguments input, Au
}
catch (OAuth2Exception ex)
{
_context.Trace.WriteLine("Failed to refresh existing OAuth credential using refresh token");
var message = "Failed to refresh existing OAuth credential using refresh token";
_context.Trace.WriteLine(message);
_context.Trace.WriteException(ex);
_context.Trace2.WriteError(message);

// We failed to refresh the AT using the RT; log the refresh failure and fall through to restart
// the OAuth authentication flow
Expand Down Expand Up @@ -279,7 +289,7 @@ public async Task<AuthenticationModes> GetSupportedAuthenticationModesAsync(Inpu
try
{
var authenticationMethods = await _restApiRegistry.Get(input).GetAuthenticationMethodsAsync();

var modes = AuthenticationModes.None;

if (authenticationMethods.Contains(AuthenticationMethod.BasicAuth))
Expand All @@ -298,8 +308,12 @@ public async Task<AuthenticationModes> GetSupportedAuthenticationModesAsync(Inpu
}
catch (Exception ex)
{
_context.Trace.WriteLine($"Failed to query '{input.GetRemoteUri()}' for supported authentication schemes.");
var format = "Failed to query '{0}' for supported authentication schemes.";
var message = string.Format(format, input.GetRemoteUri());

_context.Trace.WriteLine(message);
_context.Trace.WriteException(ex);
_context.Trace2.WriteError(message, format);

_context.Terminal.WriteLine($"warning: failed to query '{input.GetRemoteUri()}' for supported authentication schemes.");

Expand Down Expand Up @@ -356,7 +370,11 @@ private async Task<string> ResolveOAuthUserNameAsync(InputArguments input, strin
return result.Response.UserName;
}

throw new Exception($"Failed to resolve username. HTTP: {result.StatusCode}");
var format = "Failed to resolve username. HTTP: {0}";
var message = string.Format(format, result.StatusCode);
_context.Trace2.WriteError(message, format);

throw new Exception(message);
}

private async Task<string> ResolveBasicAuthUserNameAsync(InputArguments input, string username, string password)
Expand All @@ -367,7 +385,11 @@ private async Task<string> ResolveBasicAuthUserNameAsync(InputArguments input, s
return result.Response.UserName;
}

throw new Exception($"Failed to resolve username. HTTP: {result.StatusCode}");
var format = "Failed to resolve username. HTTP: {0}";
var message = string.Format(format, result.StatusCode);
_context.Trace2.WriteError(message, format);

throw new Exception(message);
}

private async Task<bool> ValidateCredentialsWork(InputArguments input, ICredential credentials, AuthenticationModes authModes)
Expand Down Expand Up @@ -404,8 +426,10 @@ private async Task<bool> ValidateCredentialsWork(InputArguments input, ICredenti
}
catch (Exception ex)
{
_context.Trace.WriteLine($"Failed to validate existing credentials using OAuth");
var message = "Failed to validate existing credentials using OAuth";
_context.Trace.WriteLine(message);
_context.Trace.WriteException(ex);
_context.Trace2.WriteError(message);
}
}

Expand All @@ -419,8 +443,10 @@ private async Task<bool> ValidateCredentialsWork(InputArguments input, ICredenti
}
catch (Exception ex)
{
_context.Trace.WriteLine($"Failed to validate existing credentials using Basic Auth");
var message = "Failed to validate existing credentials using Basic Auth";
_context.Trace.WriteLine(message);
_context.Trace.WriteException(ex);
_context.Trace2.WriteError(message);
return false;
}
}
Expand Down
12 changes: 7 additions & 5 deletions src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public BitbucketRestApi(ICommandContext context)
EnsureArgument.NotNull(context, nameof(context));

_context = context;

}

public async Task<RestApiResult<IUserInfo>> GetUserInformationAsync(string userName, string password, bool isBearerToken)
Expand All @@ -35,7 +35,7 @@ public async Task<RestApiResult<IUserInfo>> GetUserInformationAsync(string userN
}

// Bitbucket Server/DC doesn't actually provide a REST API we can use to trade an access_token for the owning username,
// therefore this is always going to return a placeholder username, however this call does provide a way to validate the
// therefore this is always going to return a placeholder username, however this call does provide a way to validate the
// credentials we do have
var requestUri = new Uri(ApiUri, "api/1.0/users");
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri))
Expand Down Expand Up @@ -131,14 +131,16 @@ public void Dispose()

private HttpClient HttpClient => _httpClient ??= _context.HttpClientFactory.CreateClient();

private Uri ApiUri
private Uri ApiUri
{
get
get
{
var remoteUri = _context.Settings?.RemoteUri;
if (remoteUri == null)
{
throw new ArgumentException("RemoteUri must be defined to generate Bitbucket DC OAuth2 endpoint Urls");
var message = "RemoteUri must be defined to generate Bitbucket DC OAuth2 endpoint Urls";
_context.Trace2.WriteError(message);
throw new ArgumentException(message);
}

return new Uri(BitbucketHelper.GetBaseUri(remoteUri) + "/rest/");
Expand Down
4 changes: 3 additions & 1 deletion src/shared/Core.UI/Commands/CredentialsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ private async Task<int> ExecuteAsync(CommandOptions options)

if (!viewModel.WindowResult)
{
throw new Exception("User cancelled dialog.");
var message = "User cancelled dialog.";
Context.Trace2.WriteError(message);
throw new Exception(message);
}

WriteResult(
Expand Down
4 changes: 3 additions & 1 deletion src/shared/Core.UI/Commands/DeviceCodeCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ private async Task<int> ExecuteAsync(string code, string url, bool noLogo)

if (!viewModel.WindowResult)
{
throw new Exception("User cancelled dialog.");
var message = "User cancelled dialog.";
Context.Trace2.WriteError(message);
throw new Exception(message);
}

return 0;
Expand Down
8 changes: 6 additions & 2 deletions src/shared/Core.UI/Commands/OAuthCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ private async Task<int> ExecuteAsync(CommandOptions options)

if (!viewModel.WindowResult)
{
throw new Exception("User cancelled dialog.");
var message = "User cancelled dialog.";
Context.Trace2.WriteError(message);
throw new Exception(message);
}

var result = new Dictionary<string, string>();
Expand All @@ -81,7 +83,9 @@ private async Task<int> ExecuteAsync(CommandOptions options)
break;

default:
throw new ArgumentOutOfRangeException();
var e = new ArgumentOutOfRangeException();
Context.Trace2.WriteError(e.Message);
throw e;
}

WriteResult(result);
Expand Down
1 change: 1 addition & 0 deletions src/shared/Core.UI/HelperApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ private bool WriteException(Exception ex)
{
["error"] = ex.Message
});
Context.Trace2.WriteError(ex.Message);

return true;
}
Expand Down
20 changes: 17 additions & 3 deletions src/shared/Core/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,18 +134,32 @@ private void OnException(Exception ex, InvocationContext invocationContext)

private bool WriteException(Exception ex)
{
string format;
string message;

// Try and use a nicer format for some well-known exception types
switch (ex)
{
case GitException gitEx:
Context.Streams.Error.WriteLine("fatal: {0} [{1}]", gitEx.Message, gitEx.ExitCode);
format = "fatal: {0} [{1}]";
message = string.Format(format, gitEx.Message, gitEx.ExitCode);

Context.Streams.Error.WriteLine(message);
Context.Streams.Error.WriteLine(gitEx.GitErrorMessage);

format += "{2}{3}";
message = string.Format(format, gitEx.Message, Environment.NewLine, gitEx.GitErrorMessage);
Context.Trace2.WriteError(message);
break;
case InteropException interopEx:
Context.Streams.Error.WriteLine("fatal: {0} [0x{1:x}]", interopEx.Message, interopEx.ErrorCode);
format = "fatal: {0} [0x{1:x}]";
message = string.Format(format, interopEx.Message, interopEx.ErrorCode);
Context.Streams.Error.WriteLine(message);
break;
default:
Context.Streams.Error.WriteLine("fatal: {0}", ex.Message);
format = "fatal: {0}";
message = string.Format(format, ex.Message);
Context.Streams.Error.WriteLine(message);
break;
}

Expand Down
27 changes: 22 additions & 5 deletions src/shared/Core/Authentication/AuthenticationBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ protected AuthenticationBase(ICommandContext context)
var process = ChildProcess.Start(Context.Trace2, procStartInfo, Trace2ProcessClass.UIHelper);
if (process is null)
{
throw new Exception($"Failed to start helper process: {path} {args}");
var format = "Failed to start helper process: {0} {1}";
var message = string.Format(format, path, args);

Context.Trace2.WriteError(message, format);
throw new Exception(message);
}

// Kill the process upon a cancellation request
Expand All @@ -69,7 +73,11 @@ protected AuthenticationBase(ICommandContext context)
errorMessage = "Unknown";
}

throw new Exception($"helper error ({exitCode}): {errorMessage}");
var format = "helper error ({0}): {1}";
var message = string.Format(format, exitCode, errorMessage);

Context.Trace2.WriteError(message, format);
throw new Exception(message);
}

return resultDict;
Expand All @@ -86,7 +94,10 @@ protected void ThrowIfUserInteractionDisabled()

Context.Trace.WriteLine($"{envName} / {cfgName} is false/never; user interactivity has been disabled.");

throw new InvalidOperationException("Cannot prompt because user interactivity has been disabled.");
var message = "Cannot prompt because user interactivity has been disabled.";
Context.Trace2.WriteError(message);

throw new InvalidOperationException(message);
}
}

Expand All @@ -96,7 +107,10 @@ protected void ThrowIfGuiPromptsDisabled()
{
Context.Trace.WriteLine($"{Constants.EnvironmentVariables.GitTerminalPrompts} is 0; GUI prompts have been disabled.");

throw new InvalidOperationException("Cannot show prompt because GUI prompts have been disabled.");
var message = "Cannot show prompt because GUI prompts have been disabled.";
Context.Trace2.WriteError(message);

throw new InvalidOperationException(message);
}
}

Expand All @@ -106,7 +120,10 @@ protected void ThrowIfTerminalPromptsDisabled()
{
Context.Trace.WriteLine($"{Constants.EnvironmentVariables.GitTerminalPrompts} is 0; terminal prompts have been disabled.");

throw new InvalidOperationException("Cannot prompt because terminal prompts have been disabled.");
var message = "Cannot prompt because terminal prompts have been disabled.";
Context.Trace2.WriteError(message);

throw new InvalidOperationException(message);
}
}

Expand Down
Loading

0 comments on commit 2bb8414

Please sign in to comment.