public HarvestSummeryReadable(HarvestSummary summery) { this.LogFolder = summery.LogFolder; this.AvgEligiblePlots = Formatter.formatDouble(summery.AvgEligiblePlots, 5, null); this.FoundProofs = summery.FoundProofs; this.BestLookupTime = Formatter.formatDouble(summery.BestLookupTime, 5, "s"); this.WorstLookupTime = Formatter.formatDouble(summery.WorstLookupTime, 5, "s"); this.AvgLookupTime = Formatter.formatDouble(summery.AvgLookupTime, 5, "s"); this.FilterRatio = Formatter.formatDouble(summery.FilterRatio, 5, null); this.TotalPlots = summery.TotalPlots; this.ChallengesPerMinute = Formatter.formatDouble(summery.ChallengesPerMinute, 5, null); this.AvgHeat = Formatter.formatDouble(summery.AvgHeat, 5, null); this.MaxHeat = Formatter.formatDouble(summery.MaxHeat, 5, null); this.MinHeat = Formatter.formatDouble(summery.MinHeat, 5, null); this.RuntimeMinutes = Formatter.formatDouble(summery.RuntimeMinutes, 2, null); }
public Tuple <string, HarvestSummary, List <Harvest> >?ParseLogs(string path, double maxAllowedLookupTime, int nrOfRecentEntries) { string[] debugLogFiles = { }; if (Directory.Exists(path)) { debugLogFiles = Directory.GetFiles(path, "debug.log*"); } var regex = new Regex("([0-9:.\\-T]*) harvester .*.harvester.harvester: INFO\\s*([0-9]*) " + "plots were eligible for farming ([a-z0-9.]*) Found ([0-9]*) proofs. " + "Time: ([0-9.]*) s. Total ([0-9]*) plots", RegexOptions.Compiled | RegexOptions.IgnoreCase); ConcurrentBag <Harvest> harvestsBag = new(); Parallel.ForEach(debugLogFiles, (file) => { try { // for now close after each read as I am not sure how wallets / harvesters // react if they run or get restarted while we keep a shared lock on those files new TailLineEmitter(file, true, (line) => { if (regex.IsMatch(line)) { var matches = regex.Matches(line)[0]; var harvest = new Harvest { LogFolder = path, DateTime = DateTime.Parse(matches.Groups[1].Value), ElgiblePlots = int.Parse(matches.Groups[2].Value, CultureInfo.InvariantCulture), FoundProofs = int.Parse(matches.Groups[4].Value, CultureInfo.InvariantCulture), LookupTime = double.Parse(matches.Groups[5].Value, CultureInfo.InvariantCulture), TotalPlots = int.Parse(matches.Groups[6].Value, CultureInfo.InvariantCulture), FilterRatio = double.Parse(matches.Groups[2].Value) / int.Parse(matches.Groups[6].Value, CultureInfo.InvariantCulture), Heat = double.Parse(matches.Groups[5].Value, CultureInfo.InvariantCulture) == 0 ? 0 : (double.Parse(matches.Groups[5].Value, CultureInfo.InvariantCulture) / maxAllowedLookupTime), }; harvestsBag.Add(harvest); } }).ReadMore(); } catch (Exception e) { Debug.WriteLine("ERROR: parsing harvester log " + path + " failed. skipping it"); } }); List <Harvest> harvests = harvestsBag.ToList(); if (harvests.Count == 0) { Debug.WriteLine("No harvests found! Set log level at least to info!"); return(null); } else if (harvests.Count == 1) { Debug.WriteLine("Only found a single harvest! Need at least two!"); return(null); } harvests.Sort((a, b) => a.DateTime.CompareTo(b.DateTime)); harvests = new(harvests.Skip(Math.Max(0, harvests.Count() - nrOfRecentEntries))); var first = harvests[0]; var last = harvests[harvests.Count - 1]; var runtimeMinutes = (last.DateTime - first.DateTime).TotalMinutes; var summary = new HarvestSummary { LogFolder = path, WorstLookupTime = harvests.Aggregate((a, b) => a.LookupTime > b.LookupTime ? a : b).LookupTime, BestLookupTime = harvests.Aggregate((a, b) => a.LookupTime < b.LookupTime ? a : b).LookupTime, AvgLookupTime = harvests.Average(a => a.LookupTime), AvgEligiblePlots = harvests.Average(a => a.ElgiblePlots), TotalPlots = last.TotalPlots, FoundProofs = (int)harvests.Sum(a => a.FoundProofs), FilterRatio = harvests.Average(a => a.FilterRatio), ChallengesPerMinute = harvests.Count / runtimeMinutes, AvgHeat = harvests.Average(a => a.Heat), MaxHeat = harvests.Aggregate((a, b) => a.LookupTime > b.LookupTime ? a : b).LookupTime, MinHeat = harvests.Aggregate((a, b) => a.LookupTime < b.LookupTime ? a : b).LookupTime, RuntimeMinutes = runtimeMinutes, }; return(new(path, summary, harvests)); }