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

[FancyLogger] -> LiveLogger #8356

Merged
merged 24 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
85f80d7
Rename FancyLogger to LiveLogger
edvilme Jan 26, 2023
b7dc89e
Updated command line switches and environment variables
edvilme Jan 26, 2023
7025d05
Merge branch 'main' into edvilme-flg-llg
edvilme Jan 29, 2023
9dd1294
Fix code formatting
edvilme Jan 30, 2023
f334686
Fix code formatting for XMake.cs
edvilme Jan 30, 2023
c83b667
Drop prefix from LiveLogger class names
rainersigwald Jan 30, 2023
9dc4eb2
fixup! Merge branch 'main' into edvilme-flg-llg
rainersigwald Jan 30, 2023
bc587fe
Revert to main
rainersigwald Jan 30, 2023
6b6efd4
Rename FancyLogger folder to LiveLogger
rainersigwald Jan 30, 2023
2644224
Rename FancyLogger namespace to LiveLogger
rainersigwald Jan 30, 2023
3fbb266
VS UI rename FancyLoggerBuffer to TerminalBuffer
rainersigwald Jan 30, 2023
c54b12c
VS UI rename FancyLoggerMessageNode to MessageNode
rainersigwald Jan 30, 2023
76292c4
VS UI rename FancyLoggerProjectNode to ProjectNode
rainersigwald Jan 30, 2023
5307a93
VS UI rename FancyLoggerTargetNode to TargetNode
rainersigwald Jan 30, 2023
6466ca5
VS UI rename FancyLoggerTaskNode to TaskNode
rainersigwald Jan 30, 2023
ffad7c2
Updated command line switches and environment variables
edvilme Jan 26, 2023
53bd140
Revert accidental future-looking main change
rainersigwald Jan 30, 2023
d87b50f
Delete old clone of LiveLogger source
rainersigwald Jan 30, 2023
67e3320
Revert accidental future-looking main change
rainersigwald Jan 30, 2023
cea2059
VS UI rename FancyLogger to LiveLogger
rainersigwald Jan 30, 2023
33a36ea
Renamed documentation
edvilme Jan 30, 2023
49e9c62
Updated remaining reference on documentation and removed .DS_Store files
edvilme Jan 30, 2023
85a1654
Renamed FancyLoggerBufferLine to TerminalBufferLine
edvilme Jan 31, 2023
fa10283
Fix some comments
Forgind Jan 31, 2023
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
469 changes: 469 additions & 0 deletions src/Build/Logging/LiveLogger/ANSIBuilder.cs

Large diffs are not rendered by default.

282 changes: 282 additions & 0 deletions src/Build/Logging/LiveLogger/LiveLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Build.Framework;

namespace Microsoft.Build.Logging.LiveLogger
{
public class LiveLogger : ILogger
{
private Dictionary<int, LiveLoggerProjectNode> projects = new Dictionary<int, LiveLoggerProjectNode>();

private bool Succeeded;

private float existingTasks = 1;
private float completedTasks = 0;

public string Parameters { get; set; }

public LoggerVerbosity Verbosity { get; set; }

public LiveLogger()
{
Parameters = "";
}

public void Initialize(IEventSource eventSource)
{
// Register for different events
// Started
eventSource.BuildStarted += new BuildStartedEventHandler(eventSource_BuildStarted);
eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted);
eventSource.TargetStarted += new TargetStartedEventHandler(eventSource_TargetStarted);
eventSource.TaskStarted += new TaskStartedEventHandler(eventSource_TaskStarted);
// Finished
eventSource.BuildFinished += new BuildFinishedEventHandler(eventSource_BuildFinished);
eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished);
eventSource.TargetFinished += new TargetFinishedEventHandler(eventSource_TargetFinished);
// eventSource.TaskFinished += new TaskFinishedEventHandler(eventSource_TaskFinished);
// Raised
eventSource.MessageRaised += new BuildMessageEventHandler(eventSource_MessageRaised);
eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised);
// Cancelled
Console.CancelKeyPress += new ConsoleCancelEventHandler(console_CancelKeyPressed);

Task.Run(() =>
{
Render();
});
}

private void Render()
{
// Initialize
LiveLoggerBuffer.Initialize();
// TODO: Fix. First line does not appear at top. Leaving empty line for now
LiveLoggerBuffer.WriteNewLine(string.Empty);
// First render
LiveLoggerBuffer.Render();
int i = 0;
// Rerender periodically
while (!LiveLoggerBuffer.IsTerminated)
{
i++;
// Delay by 1/60 seconds
// Use task delay to avoid blocking the task, so that keyboard input is listened continously
Task.Delay((i / 60) * 1_000).ContinueWith((t) =>
{
// Rerender projects only when needed
foreach (var project in projects)
{
project.Value.Log();
}
// Rerender buffer
LiveLoggerBuffer.Render();
});
// Handle keyboard input
if (Console.KeyAvailable)
{
ConsoleKey key = Console.ReadKey().Key;
switch (key)
{
case ConsoleKey.UpArrow:
if (LiveLoggerBuffer.TopLineIndex > 0)
{
LiveLoggerBuffer.TopLineIndex--;
}

LiveLoggerBuffer.ShouldRerender = true;
break;
case ConsoleKey.DownArrow:
LiveLoggerBuffer.TopLineIndex++;
LiveLoggerBuffer.ShouldRerender = true;
break;
default:
break;
}
}
}
}

// Build
private void eventSource_BuildStarted(object sender, BuildStartedEventArgs e)
{
}

private void eventSource_BuildFinished(object sender, BuildFinishedEventArgs e)
{
Succeeded = e.Succeeded;
}

// Project
private void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
{
// Get project id
int id = e.BuildEventContext!.ProjectInstanceId;
// If id already exists...
if (projects.ContainsKey(id))
{
return;
}
// Add project
LiveLoggerProjectNode node = new LiveLoggerProjectNode(e);
projects[id] = node;
// Log
node.ShouldRerender = true;
}

private void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
{
// Get project id
int id = e.BuildEventContext!.ProjectInstanceId;
if (!projects.TryGetValue(id, out LiveLoggerProjectNode? node))
{
return;
}
// Update line
node.Finished = true;
// Log
node.ShouldRerender = true;
}

// Target
private void eventSource_TargetStarted(object sender, TargetStartedEventArgs e)
{
// Get project id
int id = e.BuildEventContext!.ProjectInstanceId;
if (!projects.TryGetValue(id, out LiveLoggerProjectNode? node))
{
return;
}
// Update
node.AddTarget(e);
// Log
node.ShouldRerender = true;
}

private void eventSource_TargetFinished(object sender, TargetFinishedEventArgs e)
{
// Get project id
int id = e.BuildEventContext!.ProjectInstanceId;
if (!projects.TryGetValue(id, out LiveLoggerProjectNode? node))
{
return;
}
// Update
node.FinishedTargets++;
// Log
node.ShouldRerender = true;
}

// Task
private void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
{
// Get project id
int id = e.BuildEventContext!.ProjectInstanceId;
if (!projects.TryGetValue(id, out LiveLoggerProjectNode? node))
{
return;
}
// Update
node.AddTask(e);
existingTasks++;
// Log
node.ShouldRerender = true;
}

private void eventSource_TaskFinished(object sender, TaskFinishedEventArgs e)
{
completedTasks++;
}

// Raised messages, warnings and errors
private void eventSource_MessageRaised(object sender, BuildMessageEventArgs e)
{
if (e is TaskCommandLineEventArgs)
{
return;
}
// Get project id
int id = e.BuildEventContext!.ProjectInstanceId;
if (!projects.TryGetValue(id, out LiveLoggerProjectNode? node))
{
return;
}
// Update
node.AddMessage(e);
// Log
node.ShouldRerender = true;
}

private void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
{
// Get project id
int id = e.BuildEventContext!.ProjectInstanceId;
if (!projects.TryGetValue(id, out LiveLoggerProjectNode? node))
{
return;
}
// Update
node.AddWarning(e);
// Log
node.ShouldRerender = true;
}

private void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
{
// Get project id
int id = e.BuildEventContext!.ProjectInstanceId;
if (!projects.TryGetValue(id, out LiveLoggerProjectNode? node))
{
return;
}
// Update
node.AddError(e);
// Log
node.ShouldRerender = true;
}

private void console_CancelKeyPressed(object? sender, ConsoleCancelEventArgs eventArgs)
{
// Shutdown logger
Shutdown();
}

public void Shutdown()
{
LiveLoggerBuffer.Terminate();
// TODO: Remove. There is a bug that causes switching to main buffer without deleting the contents of the alternate buffer
Console.Clear();
int errorCount = 0;
int warningCount = 0;
foreach (var project in projects)
{
errorCount += project.Value.ErrorCount;
warningCount += project.Value.WarningCount;
foreach (var message in project.Value.AdditionalDetails)
{
Console.WriteLine(message.ToANSIString());
}
}

// Emmpty line
Console.WriteLine();
if (Succeeded)
{
Console.WriteLine(ANSIBuilder.Formatting.Color("Build succeeded.", ANSIBuilder.Formatting.ForegroundColor.Green));
Console.WriteLine($"\t{warningCount} Warning(s)");
Console.WriteLine($"\t{errorCount} Error(s)");
}
else
{
Console.WriteLine(ANSIBuilder.Formatting.Color("Build failed.", ANSIBuilder.Formatting.ForegroundColor.Red));
Console.WriteLine($"\t{warningCount} Warnings(s)");
Console.WriteLine($"\t{errorCount} Errors(s)");
}
}
}
}
Loading