Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error logging #1341

Merged
merged 1 commit into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/CommandLine/Commands/GenerateDocCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ DocumentationWriter CreateDocumentationWriter(DocumentationContext context)
}
catch (IOException ex)
{
WriteError(ex);
WriteCriticalError(ex);
return CommandResults.Fail;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/CommandLine/Commands/HelpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public CommandStatus Execute()
}
catch (ArgumentException ex)
{
WriteError(ex);
WriteCriticalError(ex);
return CommandStatus.Fail;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/CommandLine/Commands/MSBuildWorkspaceCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public async Task<CommandStatus> ExecuteAsync(IEnumerable<PathInfo> paths, strin
catch (ProjectOrSolutionLoadException ex)
{
WriteLine(ex.Message, Colors.Message_Warning, Verbosity.Minimal);
WriteError(ex.InnerException, ConsoleColor.Yellow, Verbosity.Minimal);
WriteError(ex.InnerException);
status = CommandStatus.Fail;
continue;
}
Expand Down
6 changes: 3 additions & 3 deletions src/CommandLine/Commands/MigrateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ private CommandStatus ExecuteRuleSet(string path)
catch (XmlException ex)
{
WriteLine($"Cannot load '{path}'", Colors.Message_Warning, Verbosity.Minimal);
WriteError(ex, verbosity: Verbosity.Minimal);
WriteError(ex);
return CommandStatus.NotSuccess;
}

Expand Down Expand Up @@ -287,7 +287,7 @@ private CommandStatus ExecuteEditorConfig(string path)
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
{
WriteLine($"Cannot load '{path}'", Verbosity.Minimal);
WriteError(ex, verbosity: Verbosity.Minimal);
WriteError(ex);
return CommandStatus.NotSuccess;
}

Expand Down Expand Up @@ -355,7 +355,7 @@ private CommandStatus ExecuteEditorConfig(string path)
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
{
WriteLine($"Cannot save '{path}'", Colors.Message_Warning, Verbosity.Minimal);
WriteError(ex, verbosity: Verbosity.Minimal);
WriteError(ex);
return CommandStatus.NotSuccess;
}
}
Expand Down
96 changes: 1 addition & 95 deletions src/CommandLine/DelegateFactory.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using static Roslynator.Logger;
Expand Down Expand Up @@ -63,99 +62,6 @@ public static bool TryCreateFromSourceText<TDelegate>(
return result is not null;
}

public static bool TryCreateFromCodeFile<TDelegate>(
string filePath,
Type returnType,
Type parameterType,
out TDelegate result) where TDelegate : Delegate
{
if (!ParseHelpers.TryReadAllText(filePath, out string content, f => Logger.WriteError(f)))
{
result = null;
return false;
}

Assembly assembly = AssemblyFactory.FromSourceText(content);

if (assembly is null)
{
result = null;
return false;
}

result = CreateDelegateAndCatchIfThrows<TDelegate>(assembly, returnType, new Type[] { parameterType });
return result is not null;
}

public static bool TryCreateFromAssembly<TDelegate>(
string path,
Type returnType,
Type parameterType,
out TDelegate result) where TDelegate : Delegate
{
return TryCreateFromAssembly(path, returnType, new Type[] { parameterType }, out result);
}

private static bool TryCreateFromAssembly<TDelegate>(
string path,
Type returnType,
Type[] parameters,
out TDelegate result) where TDelegate : Delegate
{
result = default;

if (path is null)
return false;

int index = path.LastIndexOf(',');

if (index <= 0
|| index >= path.Length - 1)
{
WriteError($"Invalid value: {path}. "
+ "The expected format is \"MyLib.dll,MyNamespace.MyClass.MyMethod\".");

return false;
}

string assemblyName = path.Substring(0, index);

string methodFullName = path.Substring(index + 1);

index = methodFullName.LastIndexOf('.');

if (index < 0
|| index >= path.Length - 1)
{
WriteError($"Invalid method full name: {methodFullName}. "
+ "The expected format is \"MyNamespace.MyClass.MyMethod\".");

return false;
}

Assembly assembly;

try
{
assembly = Assembly.LoadFrom(assemblyName);
}
catch (Exception ex) when (ex is ArgumentException
|| ex is IOException
|| ex is BadImageFormatException)
{
Logger.WriteError(ex);
return false;
}

string typeName = methodFullName.Substring(0, index);

string methodName = methodFullName.Substring(index + 1);

result = CreateDelegateAndCatchIfThrows<TDelegate>(assembly, returnType, parameters, typeName, methodName);

return result is not null;
}

private static TDelegate CreateDelegateAndCatchIfThrows<TDelegate>(
Assembly assembly,
Type returnType,
Expand All @@ -174,7 +80,7 @@ private static TDelegate CreateDelegateAndCatchIfThrows<TDelegate>(
|| ex is MissingMemberException
|| ex is TypeLoadException)
{
Logger.WriteError(ex);
WriteCriticalError(ex);
return null;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/CommandLine/ParseHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static bool TryParseCodeExpression<T>(
return false;
}

if (!TryReadAllText(filePath, out filePath, ex => WriteError(ex)))
if (!TryReadAllText(filePath, out filePath, ex => WriteCriticalError(ex)))
return false;

return DelegateFactory.TryCreateFromSourceText(filePath, returnType, parameterType, out func);
Expand Down
2 changes: 1 addition & 1 deletion src/CommandLine/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ private static int Main(string[] args)
|| ex is FileNotFoundException
|| ex is InvalidOperationException)
{
WriteError(ex);
WriteCriticalError(ex);
}
finally
{
Expand Down
7 changes: 5 additions & 2 deletions src/Workspaces.Core/Logging/ConsoleWriter.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.IO;

namespace Roslynator;

internal sealed class ConsoleWriter : TextWriterWithVerbosity
{
public static ConsoleWriter Instance { get; } = new();
public static ConsoleWriter Out { get; } = new(Console.Out, Console.Out.FormatProvider);

private ConsoleWriter() : base(Console.Out, Console.Out.FormatProvider)
public static ConsoleWriter Error { get; } = new(Console.Error, Console.Error.FormatProvider);

private ConsoleWriter(TextWriter writer, IFormatProvider formatProvider) : base(writer, formatProvider)
{
}

Expand Down
53 changes: 22 additions & 31 deletions src/Workspaces.Core/Logging/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ namespace Roslynator;

internal static class Logger
{
public static ConsoleWriter ConsoleOut { get; } = ConsoleWriter.Instance;
public static ConsoleWriter ConsoleOut { get; } = ConsoleWriter.Out;

public static ConsoleWriter ConsoleError { get; } = ConsoleWriter.Error;

public static TextWriterWithVerbosity? Out { get; set; }

Expand Down Expand Up @@ -268,42 +270,31 @@ public static void WriteLine(object value)
Out?.WriteLine(value);
}

public static void WriteCriticalError(Exception exception)
{
WriteError(exception, isCritical: true, ConsoleColor.Red, Verbosity.Minimal);
}

public static void WriteError(
Exception exception,
ConsoleColor color = ConsoleColor.Red,
Verbosity verbosity = Verbosity.Quiet)
ConsoleColor color = ConsoleColor.Yellow,
Verbosity verbosity = Verbosity.Minimal)
{
var colors = new ConsoleColors(color);
WriteError(exception, isCritical: false, color, verbosity);
}

string message = exception.Message;
#if DEBUG
if (ShouldWrite(Verbosity.Diagnostic))
message = exception.ToString();
#endif
WriteLine(message, colors, verbosity);
private static void WriteError(Exception exception, bool isCritical, ConsoleColor color, Verbosity verbosity)
{
var colors = new ConsoleColors(color);

if (exception is AggregateException aggregateException)
WriteInnerExceptions(aggregateException, "");
ConsoleError.WriteLine(
(isCritical || ConsoleError.ShouldWrite(Verbosity.Diagnostic)) ? exception.ToString() : exception.Message,
colors,
verbosity: verbosity);

void WriteInnerExceptions(AggregateException aggregateException, string indent)
{
indent += " ";

foreach (Exception innerException in aggregateException.InnerExceptions)
{
string message = innerException.Message;
#if DEBUG
if (ShouldWrite(Verbosity.Diagnostic))
message = innerException.ToString();
#endif
WriteLine(indent + "Inner exception: " + message, colors, verbosity);

if (innerException is AggregateException aggregateException2)
WriteInnerExceptions(aggregateException2, indent);
}

indent = indent.Substring(2);
}
Out?.WriteLine(
(isCritical || Out.ShouldWrite(Verbosity.Diagnostic)) ? exception.ToString() : exception.Message,
verbosity: verbosity);
}

public static bool ShouldWrite(Verbosity verbosity)
Expand Down