Much nicer logging by means of container name-override and long-id log replacements

This commit is contained in:
benbierens 2023-04-30 10:56:19 +02:00
parent 4dd02a96e9
commit db4364d336
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
14 changed files with 107 additions and 29 deletions

View File

@ -5,8 +5,8 @@ namespace DistTestCore.Codex
{ {
public class CodexContainerRecipe : ContainerRecipeFactory public class CodexContainerRecipe : ContainerRecipeFactory
{ {
public const string DockerImage = "thatbenbierens/nim-codex:sha-92ea752"; //public const string DockerImage = "thatbenbierens/nim-codex:sha-9716635";
//public const string DockerImage = "thatbenbierens/codexlocal:latest"; public const string DockerImage = "thatbenbierens/codexlocal:latest";
public const string MetricsPortTag = "metrics_port"; public const string MetricsPortTag = "metrics_port";
protected override string Image => DockerImage; protected override string Image => DockerImage;

View File

@ -5,6 +5,7 @@ namespace DistTestCore.Codex
{ {
public class CodexStartupConfig public class CodexStartupConfig
{ {
public string? NameOverride { get; set; }
public Location Location { get; set; } public Location Location { get; set; }
public CodexLogLevel? LogLevel { get; set; } public CodexLogLevel? LogLevel { get; set; }
public ByteSize? StorageQuota { get; set; } public ByteSize? StorageQuota { get; set; }

View File

@ -75,6 +75,10 @@ namespace DistTestCore
{ {
var debugInfo = access.GetDebugInfo(); var debugInfo = access.GetDebugInfo();
if (debugInfo == null || string.IsNullOrEmpty(debugInfo.id)) throw new InvalidOperationException("Unable to get debug-info from codex node at startup."); if (debugInfo == null || string.IsNullOrEmpty(debugInfo.id)) throw new InvalidOperationException("Unable to get debug-info from codex node at startup.");
var nodePeerId = debugInfo.id;
var nodeName = access.Container.Name;
lifecycle.Log.AddStringReplace(nodePeerId, $"___{nodeName}___");
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -6,6 +6,7 @@ namespace DistTestCore
{ {
public interface ICodexSetup public interface ICodexSetup
{ {
ICodexSetup WithName(string name);
ICodexSetup At(Location location); ICodexSetup At(Location location);
ICodexSetup WithLogLevel(CodexLogLevel level); ICodexSetup WithLogLevel(CodexLogLevel level);
ICodexSetup WithBootstrapNode(IOnlineCodexNode node); ICodexSetup WithBootstrapNode(IOnlineCodexNode node);
@ -24,6 +25,12 @@ namespace DistTestCore
NumberOfNodes = numberOfNodes; NumberOfNodes = numberOfNodes;
} }
public ICodexSetup WithName(string name)
{
NameOverride = name;
return this;
}
public ICodexSetup At(Location location) public ICodexSetup At(Location location)
{ {
Location = location; Location = location;

View File

@ -1,4 +1,5 @@
using DistTestCore.Codex; using DistTestCore.Codex;
using DistTestCore.Marketplace;
using KubernetesWorkflow; using KubernetesWorkflow;
namespace DistTestCore namespace DistTestCore
@ -18,10 +19,7 @@ namespace DistTestCore
LogStart($"Starting {codexSetup.Describe()}..."); LogStart($"Starting {codexSetup.Describe()}...");
var gethStartResult = lifecycle.GethStarter.BringOnlineMarketplaceFor(codexSetup); var gethStartResult = lifecycle.GethStarter.BringOnlineMarketplaceFor(codexSetup);
var startupConfig = new StartupConfig(); var startupConfig = CreateStartupConfig(gethStartResult, codexSetup);
startupConfig.Add(codexSetup);
startupConfig.Add(gethStartResult);
var containers = StartCodexContainers(startupConfig, codexSetup.NumberOfNodes, codexSetup.Location); var containers = StartCodexContainers(startupConfig, codexSetup.NumberOfNodes, codexSetup.Location);
var metricAccessFactory = lifecycle.PrometheusStarter.CollectMetricsFor(codexSetup, containers); var metricAccessFactory = lifecycle.PrometheusStarter.CollectMetricsFor(codexSetup, containers);
@ -56,7 +54,16 @@ namespace DistTestCore
var workflow = CreateWorkflow(); var workflow = CreateWorkflow();
workflow.DownloadContainerLog(container, logHandler); workflow.DownloadContainerLog(container, logHandler);
} }
private StartupConfig CreateStartupConfig(GethStartResult gethStartResult, CodexSetup codexSetup)
{
var startupConfig = new StartupConfig();
startupConfig.NameOverride = codexSetup.NameOverride;
startupConfig.Add(codexSetup);
startupConfig.Add(gethStartResult);
return startupConfig;
}
private RunningContainers StartCodexContainers(StartupConfig startupConfig, int numberOfNodes, Location location) private RunningContainers StartCodexContainers(StartupConfig startupConfig, int numberOfNodes, Location location)
{ {
var workflow = CreateWorkflow(); var workflow = CreateWorkflow();

View File

@ -103,6 +103,20 @@ namespace DistTestCore
return lifecycle.FileManager.GenerateTestFile(size); return lifecycle.FileManager.GenerateTestFile(size);
} }
public IOnlineCodexNode SetupCodexBootstrapNode()
{
return SetupCodexBootstrapNode(s => { });
}
public IOnlineCodexNode SetupCodexBootstrapNode(Action<ICodexSetup> setup)
{
return SetupCodexNode(s =>
{
setup(s);
s.WithName("Bootstrap");
});
}
public IOnlineCodexNode SetupCodexNode() public IOnlineCodexNode SetupCodexNode()
{ {
return SetupCodexNode(s => { }); return SetupCodexNode(s => { });

View File

@ -114,7 +114,7 @@ namespace DistTestCore.Marketplace
private void Log(string msg) private void Log(string msg)
{ {
log.Log($"{codexAccess.Container.GetName()} {msg}"); log.Log($"{codexAccess.Container.Name} {msg}");
} }
} }

View File

@ -29,7 +29,7 @@ namespace DistTestCore.Metrics
var metricSet = GetMetricWithTimeout(metricName); var metricSet = GetMetricWithTimeout(metricName);
var metricValue = metricSet.Values[0].Value; var metricValue = metricSet.Values[0].Value;
log.Log($"{node.GetName()} metric '{metricName}' = {metricValue}"); log.Log($"{node.Name} metric '{metricName}' = {metricValue}");
Assert.That(metricValue, constraint, message); Assert.That(metricValue, constraint, message);
} }

View File

@ -41,7 +41,7 @@ namespace DistTestCore
public string GetName() public string GetName()
{ {
return CodexAccess.Container.GetName(); return CodexAccess.Container.Name;
} }
public CodexDebugResponse GetDebugInfo() public CodexDebugResponse GetDebugInfo()

View File

@ -15,26 +15,35 @@
public string Describe() public string Describe()
{ {
return string.Join(",", Containers.Select(c => c.GetName())); return string.Join(",", Containers.Select(c => c.Name));
} }
} }
public class RunningContainer public class RunningContainer
{ {
public RunningContainer(RunningPod pod, ContainerRecipe recipe, Port[] servicePorts) public RunningContainer(RunningPod pod, ContainerRecipe recipe, Port[] servicePorts, StartupConfig startupConfig)
{ {
Pod = pod; Pod = pod;
Recipe = recipe; Recipe = recipe;
ServicePorts = servicePorts; ServicePorts = servicePorts;
Name = GetContainerName(recipe, startupConfig);
} }
public string GetName() public string Name { get; }
{
return $"<{Recipe.Name}>";
}
public RunningPod Pod { get; } public RunningPod Pod { get; }
public ContainerRecipe Recipe { get; } public ContainerRecipe Recipe { get; }
public Port[] ServicePorts { get; } public Port[] ServicePorts { get; }
private string GetContainerName(ContainerRecipe recipe, StartupConfig startupConfig)
{
if (!string.IsNullOrEmpty(startupConfig.NameOverride))
{
return $"<{startupConfig.NameOverride}{recipe.Number}>";
}
else
{
return $"<{recipe.Name}>";
}
}
} }
} }

View File

@ -4,6 +4,8 @@
{ {
private readonly List<object> configs = new List<object>(); private readonly List<object> configs = new List<object>();
public string? NameOverride { get; set; }
public void Add(object config) public void Add(object config)
{ {
configs.Add(config); configs.Add(config);

View File

@ -26,7 +26,7 @@ namespace KubernetesWorkflow
var runningPod = controller.BringOnline(recipes, location); var runningPod = controller.BringOnline(recipes, location);
return new RunningContainers(startupConfig, runningPod, CreateContainers(runningPod, recipes)); return new RunningContainers(startupConfig, runningPod, CreateContainers(runningPod, recipes, startupConfig));
}); });
} }
@ -62,10 +62,10 @@ namespace KubernetesWorkflow
}); });
} }
private RunningContainer[] CreateContainers(RunningPod runningPod, ContainerRecipe[] recipes) private RunningContainer[] CreateContainers(RunningPod runningPod, ContainerRecipe[] recipes, StartupConfig startupConfig)
{ {
log.Debug(); log.Debug();
return recipes.Select(r => new RunningContainer(runningPod, r, runningPod.GetServicePortsForContainerRecipe(r))).ToArray(); return recipes.Select(r => new RunningContainer(runningPod, r, runningPod.GetServicePortsForContainerRecipe(r), startupConfig)).ToArray();
} }
private ContainerRecipe[] CreateRecipes(int numberOfContainers, ContainerRecipeFactory recipeFactory, StartupConfig startupConfig) private ContainerRecipe[] CreateRecipes(int numberOfContainers, ContainerRecipeFactory recipeFactory, StartupConfig startupConfig)

View File

@ -1,13 +1,13 @@
using System.Diagnostics; using Utils;
using Utils;
namespace Logging namespace Logging
{ {
public abstract class BaseLog public abstract class BaseLog
{ {
private readonly bool debug;
private readonly List<BaseLogStringReplacement> replacements = new List<BaseLogStringReplacement>();
private bool hasFailed; private bool hasFailed;
private LogFile? logFile; private LogFile? logFile;
private readonly bool debug;
protected BaseLog(bool debug) protected BaseLog(bool debug)
{ {
@ -27,7 +27,7 @@ namespace Logging
public void Log(string message) public void Log(string message)
{ {
LogFile.Write(message); LogFile.Write(ApplyReplacements(message));
} }
public void Debug(string message = "", int skipFrames = 0) public void Debug(string message = "", int skipFrames = 0)
@ -35,7 +35,8 @@ namespace Logging
if (debug) if (debug)
{ {
var callerName = DebugStack.GetCallerName(skipFrames); var callerName = DebugStack.GetCallerName(skipFrames);
Log($"(debug)({callerName}) {message}"); // We don't use Log because in the debug output we should not have any replacements.
LogFile.Write($"(debug)({callerName}) {message}");
} }
} }
@ -50,5 +51,38 @@ namespace Logging
hasFailed = true; hasFailed = true;
LogFile.ConcatToFilename("_FAILED"); LogFile.ConcatToFilename("_FAILED");
} }
public void AddStringReplace(string from, string to)
{
replacements.Add(new BaseLogStringReplacement(from, to));
}
private string ApplyReplacements(string str)
{
foreach (var replacement in replacements)
{
str = replacement.Apply(str);
}
return str;
}
}
public class BaseLogStringReplacement
{
private readonly string from;
private readonly string to;
public BaseLogStringReplacement(string from, string to)
{
this.from = from;
this.to = to;
if (string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to) || from == to) throw new ArgumentException();
}
public string Apply(string msg)
{
return msg.Replace(from, to);
}
} }
} }

View File

@ -10,7 +10,7 @@ namespace Tests.BasicTests
[Test] [Test]
public void TwoNodes() public void TwoNodes()
{ {
var primary = SetupCodexNode(); var primary = SetupCodexBootstrapNode();
var secondary = SetupCodexNode(s => s.WithBootstrapNode(primary)); var secondary = SetupCodexNode(s => s.WithBootstrapNode(primary));
primary.ConnectToPeer(secondary); // This is required for the switchPeers to show up. primary.ConnectToPeer(secondary); // This is required for the switchPeers to show up.
@ -29,7 +29,7 @@ namespace Tests.BasicTests
[TestCase(10)] [TestCase(10)]
public void VariableNodes(int number) public void VariableNodes(int number)
{ {
var bootstrap = SetupCodexNode(); var bootstrap = SetupCodexBootstrapNode();
var nodes = SetupCodexNodes(number, s => s.WithBootstrapNode(bootstrap)); var nodes = SetupCodexNodes(number, s => s.WithBootstrapNode(bootstrap));
var file = GenerateTestFile(10.MB()); var file = GenerateTestFile(10.MB());
@ -69,8 +69,8 @@ namespace Tests.BasicTests
//Log.Debug($"Looking for {b.id} in engine-peers [{enginePeers}]"); //Log.Debug($"Looking for {b.id} in engine-peers [{enginePeers}]");
Log.Debug($"{a.id} is looking for {b.id} in switch-peers [{switchPeers}]"); Log.Debug($"{a.id} is looking for {b.id} in switch-peers [{switchPeers}]");
//Assert.That(a.enginePeers.Any(p => p.peerId == b.id), $"Expected peerId '{b.id}' not found in engine-peers [{enginePeers}]"); //Assert.That(a.enginePeers.Any(p => p.peerId == b.id), $"{a.id} was looking for '{b.id}' in engine-peers [{enginePeers}] but it was not found.");
Assert.That(a.switchPeers.Any(p => p.peerId == b.id), $"Expected peerId '{b.id}' not found in switch-peers [{switchPeers}]"); Assert.That(a.switchPeers.Any(p => p.peerId == b.id), $"{a.id} was looking for '{b.id}' in switch-peers [{switchPeers}] but it was not found.");
} }
} }
} }