Browse Source

Ansi2Html converter for logs

pull/1566/head
razvan.goga@gmail.com 4 years ago
parent
commit
017c4ae486
  1. 55
      src/Microsoft.Tye.Hosting/Ansi2Html/Constants.cs
  2. 49
      src/Microsoft.Tye.Hosting/Ansi2Html/Converter.cs
  3. 9
      src/Microsoft.Tye.Hosting/Dashboard/Pages/Logs.razor
  4. 5
      src/Microsoft.Tye.Hosting/ProcessRunner.cs
  5. 2
      src/Microsoft.Tye.Hosting/TyeHost.cs
  6. 21
      test/UnitTests/Ansi2HtmlConverterTests.cs

55
src/Microsoft.Tye.Hosting/Ansi2Html/Constants.cs

@ -0,0 +1,55 @@
using System.Collections.Generic;
namespace Microsoft.Tye.Hosting.Ansi2Html
{
public static class Constants
{
public const string Red = "#800000";
public const string Black = "#000000";
public const string Green = "#008000";
public const string Yellow = "#808000";
public const string Blue = "#000080";
public const string Purple = "#800080";
public const string Cyan = "#008080";
public const string LightGray = "#c0c0c0";
public const string DarkGray = "#808080";
public const string BrightRed = "#ff0000";
public const string BrightGreen = "#00ff00";
public const string BrightYellow = "#ffff00";
public const string BrightBlue = "#0000ff";
public const string BrightPurple = "#ff00ff";
public const string BrightCyan = "#00ffff";
public const string White = "#ffffff";
public static Dictionary<string, string> ColorMap = new Dictionary<string, string>()
{
{ "0", Black }, // Black
{ "1", Red }, // Red
{ "2", Green }, // Green
{ "3", Yellow }, // Yellow
{ "4", Blue }, // Blue
{ "5", Purple }, // Purple
{ "6", Cyan }, // Cyan
{ "7", LightGray }, // Light Gray
{ "8", DarkGray }, // Dark Gray
{ "9", BrightRed }, // Bright Red
{ "10", BrightGreen }, // Bright Green
{ "11", BrightYellow }, // Bright Yellow
{ "12", BrightBlue }, // Bright Blue
{ "13", BrightPurple }, // Bright Purple
{ "14", BrightCyan }, // Bright Cyan
{ "15", White } // White
};
public static class SelectGraphicRenditionParameters
{
public const int Reset = 0;
public static HashSet<int> SetForeground = new HashSet<int>()
{
30, 31, 32, 33, 34, 35, 36, 37,38
};
}
}
}

49
src/Microsoft.Tye.Hosting/Ansi2Html/Converter.cs

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Microsoft.Tye.Hosting.Ansi2Html
{
public class Converter
{
private readonly Regex _rule = new Regex("\u001b\\[(?<code>\\d+)(?<args>;\\d+)*m", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase);
public string Parse(string input)
{
var htmlText = _rule.Replace(input, match =>
{
var code = Convert.ToInt32(match.Groups["code"].Value);
var args = match.Groups["args"].Value;
List<string> attributes = args.Split(';').ToList();
var tagBuilder = new StringBuilder();
if (code == Constants.SelectGraphicRenditionParameters.Reset)
{
tagBuilder.Append("</span>");
}
else
{
var color = Constants.White;
if (attributes.Count > 0)
{
string colorCode = attributes.Last();
if (Constants.ColorMap.ContainsKey(colorCode))
{
color = Constants.ColorMap[colorCode];
}
}
tagBuilder.Append("<span style=\"color:");
tagBuilder.Append(color);
tagBuilder.Append(";\">");
}
return tagBuilder.ToString();
});
return htmlText;
}
}
}

9
src/Microsoft.Tye.Hosting/Dashboard/Pages/Logs.razor

@ -1,6 +1,8 @@
@page "/logs/{ServiceName}"
@using Microsoft.Tye.Hosting.Ansi2Html;
@inject IJSRuntime JS
@inject Application application
@inject Converter ansi2HtmlParser
@implements IDisposable
<style>
@ -42,7 +44,7 @@ else
[Parameter]
public string ServiceName { get; set; } = default!;
public List<(string Text, int Id)>? ApplicationLogs { get; set; }
public List<(MarkupString Text, int Id)>? ApplicationLogs { get; set; }
private IDisposable? _subscription;
@ -53,7 +55,7 @@ else
// TODO: handle this returning false
if (application.Services.TryGetValue(ServiceName, out var service))
{
ApplicationLogs = service.CachedLogs.Select((item, index) => (item, index)).ToList();
ApplicationLogs = service.CachedLogs.Select((item, index) => ((MarkupString)item, index)).ToList();
var count = ApplicationLogs.Count;
StateHasChanged();
@ -62,7 +64,8 @@ else
count++;
InvokeAsync(() =>
{
ApplicationLogs.Add((log, count));
string htmlLog = ansi2HtmlParser.Parse(log);
ApplicationLogs.Add(((MarkupString)htmlLog, count));
StateHasChanged();
});
});

5
src/Microsoft.Tye.Hosting/ProcessRunner.cs

@ -200,10 +200,7 @@ namespace Microsoft.Tye.Hosting
{
// Default to development environment
["DOTNET_ENVIRONMENT"] = "Development",
["ASPNETCORE_ENVIRONMENT"] = "Development",
// Remove the color codes from the console output
["DOTNET_LOGGING__CONSOLE__DISABLECOLORS"] = "true",
["ASPNETCORE_LOGGING__CONSOLE__DISABLECOLORS"] = "true"
["ASPNETCORE_ENVIRONMENT"] = "Development"
};
// Set up environment variables to use the version of dotnet we're using to run

2
src/Microsoft.Tye.Hosting/TyeHost.cs

@ -20,6 +20,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Tye.Hosting.Ansi2Html;
using Microsoft.Tye.Hosting.Diagnostics;
using Microsoft.Tye.Hosting.Model;
using Serilog;
@ -204,6 +205,7 @@ namespace Microsoft.Tye.Hosting
});
});
services.AddSingleton(application);
services.AddTransient<Converter>();
})
.Build();
}

21
test/UnitTests/Ansi2HtmlConverterTests.cs

@ -0,0 +1,21 @@
using Microsoft.Tye.Hosting.Ansi2Html;
using Xunit;
namespace Microsoft.Tye.UnitTests;
public class Ansi2HtmlConverterTests
{
[Theory]
[InlineData("\u001b[31;1mThis text is red\u001b[0m", $"<span style=\"color:{Constants.Red};\">This text is red</span>")]
[InlineData(
"\u001b[31;1m\u001b[0m\u001b[36;1m\u001b[36;1m 3 | \u001b[0m \u001b[36;1muvicorn\u001b[0m app.main:app --port $Env:PORT --reload --log-level debug\u001b[0m",
$"<span style=\"color:{Constants.Red};\"></span><span style=\"color:{Constants.Red};\"><span style=\"color:{Constants.Red};\"> 3 | </span> <span style=\"color:{Constants.Red};\">uvicorn</span> app.main:app --port $Env:PORT --reload --log-level debug</span>")]
public void ShouldParse(string input, string expected)
{
Converter converter = new Converter();
string actual = converter.Parse(input);
Assert.Equal(expected, actual);
}
}
Loading…
Cancel
Save