private static async Task <int> ProcessExceptionAsync(Exception ex, CommandProcessorOptions options) { int retVal = (int)ToolExitCode.Unknown; Debug.Assert(ex != null, "exception should not be null!"); if (ex != null) { try { s_processingException = true; var agex = ex as AggregateException; if (agex != null) { foreach (var ax in agex.InnerExceptions) { retVal = await ProcessExceptionAsync(ax, options); } } else if (ex is BootstrapException bootstrapEx) { ToolConsole.WriteToolError(ex); retVal = bootstrapEx.ExitCode; } else if (ex is ProcessRunner.ProcessException rpe) { ToolConsole.WriteError(rpe, null); retVal = rpe.ExitCode; } else if (ex is ToolArgumentException ae) { ToolConsole.WriteToolError(ae); retVal = (int)ae.ExitCode; } else if (ex is ToolRuntimeException rt) { ToolConsole.WriteToolError(rt); retVal = (int)rt.ExitCode; } else if (ex is DcNS.InvalidDataContractException dce) { ToolConsole.WriteError(dce); retVal = (int)ToolExitCode.RuntimeError; } else if (Utils.IsUnexpected(ex)) { ToolConsole.WriteError(SR.ErrUnexpectedError); retVal = (int)ToolExitCode.RuntimeError; } else // (Exception e) { ToolConsole.WriteError(ex); retVal = (int)ToolExitCode.Unknown; } // don't log aggregate exceptions as the internal exceptions are already logged. if (agex == null) { string exMsg = null; if (options?.Logger != null) { exMsg = Utils.GetExceptionMessage(ex, true); await options.Logger.WriteErrorAsync(exMsg, logToUI : false).ConfigureAwait(false); } // Don't log telemetry if we're running from bootstrapper or connected service. // if options = null, it must be that a parsing exception occurred. if (options == null || options.ToolContext <= OperationalContext.Global) { exMsg = exMsg ?? Utils.GetExceptionMessage(ex, true); var telemetryClient = await AppInsightsTelemetryClient.GetInstanceAsync(CancellationToken.None).ConfigureAwait(false); telemetryClient.TrackError("Exception", exMsg); } } } catch { } } return(retVal); }