Skip to content

Commit b52ebeb

Browse files
committed
New chart + refactoring
1 parent 7be66e5 commit b52ebeb

File tree

2 files changed

+146
-52
lines changed

2 files changed

+146
-52
lines changed

chia-log-analyzer.go

Lines changed: 146 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"os"
1515
"os/user"
1616
"regexp"
17+
"sort"
1718
"strconv"
1819
"strings"
1920
"time"
@@ -30,12 +31,13 @@ var widgetFoundProofs *widgets.Paragraph
3031
var widgetLastFarmingTime *widgets.Paragraph
3132
var widgetTotalFarmingPlotsNumber *widgets.Paragraph
3233
var widgetLog *widgets.Paragraph
33-
var widgetMinFarmingTime *widgets.Paragraph
34-
var widgetMaxFarmingTime *widgets.Paragraph
3534
var widgetBarChart *widgets.BarChart
3635
var widgetBarChartParagraph *widgets.Paragraph
3736
var widgetBarChart2 *widgets.Plot
3837
var widgetBarChart2Paragraph *widgets.Paragraph
38+
var widgetSparklines *widgets.Sparkline
39+
var widgetSparklinesGroup *widgets.SparklineGroup
40+
var widgetOverallHealthPercent *widgets.Paragraph
3941
var lastRow string = ""
4042
var lastParsedLines []string
4143

@@ -50,8 +52,10 @@ var farmingTime = "0"
5052
var totalPlots = "0"
5153
var minFarmingTime = 999999.0
5254
var maxFarmingTime = 0.0
55+
var allFarmingTimes []float64
5356

5457
var lastLogFileSize = int64(0)
58+
var healthData = make(map[string]float64)
5559

5660
type stackStruct struct {
5761
lines []string
@@ -81,7 +85,7 @@ func (stack *stackStructFloats) push(value float64) {
8185

8286
var lastParsedLinesStack = stackStruct{count: 5}
8387
var lastFarmStack = stackStructFloats{count: 29}
84-
var lastFarmingTimesStack = stackStructFloats{count: 110}
88+
var lastFarmingTimesStack = stackStructFloats{count: 113}
8589

8690
func main() {
8791
detectLogFileLocation()
@@ -91,70 +95,75 @@ func main() {
9195
}
9296
defer ui.Close()
9397

94-
var smallWidgetWidth = 20
9598
var smallWidgetHeight = 3
9699

97100
widgetLastPlots = widgets.NewParagraph()
98-
widgetLastPlots.SetRect(smallWidgetWidth*0, 0, smallWidgetWidth-1, smallWidgetHeight)
99-
widgetLastPlots.Title = "Last plots count"
101+
widgetLastPlots.SetRect(0, 0, 9, smallWidgetHeight)
102+
widgetLastPlots.Title = "Plots"
100103
ui.Render(widgetLastPlots)
101104

102105
widgetFoundProofs = widgets.NewParagraph()
103-
widgetFoundProofs.SetRect(smallWidgetWidth*1, 0, (smallWidgetWidth*2)-1, smallWidgetHeight)
104-
widgetFoundProofs.Title = "Found proofs"
106+
widgetFoundProofs.SetRect(9, 0, 18, smallWidgetHeight)
107+
widgetFoundProofs.Title = "Proofs"
105108
ui.Render(widgetFoundProofs)
106109

107-
widgetLastFarmingTime = widgets.NewParagraph()
108-
widgetLastFarmingTime.SetRect(smallWidgetWidth*2, 0, (smallWidgetWidth*3)-1, smallWidgetHeight)
109-
widgetLastFarmingTime.Title = "Last farming time"
110-
ui.Render(widgetLastFarmingTime)
111-
112110
widgetTotalFarmingPlotsNumber = widgets.NewParagraph()
113-
widgetTotalFarmingPlotsNumber.SetRect(smallWidgetWidth*3, 0, (smallWidgetWidth*4)-1, smallWidgetHeight)
111+
widgetTotalFarmingPlotsNumber.SetRect(18, 0, 37, smallWidgetHeight)
114112
widgetTotalFarmingPlotsNumber.Title = "Farming attempts"
115113
ui.Render(widgetTotalFarmingPlotsNumber)
116114

117-
widgetMinFarmingTime = widgets.NewParagraph()
118-
widgetMinFarmingTime.SetRect(smallWidgetWidth*4, 0, (smallWidgetWidth*5)-1, smallWidgetHeight)
119-
widgetMinFarmingTime.Title = "Min farming time"
120-
ui.Render(widgetMinFarmingTime)
115+
widgetLastFarmingTime = widgets.NewParagraph()
116+
widgetLastFarmingTime.SetRect(37, 0, 77, smallWidgetHeight)
117+
widgetLastFarmingTime.Title = "Farming times (last/min/avg/max)"
118+
ui.Render(widgetLastFarmingTime)
121119

122-
widgetMaxFarmingTime = widgets.NewParagraph()
123-
widgetMaxFarmingTime.SetRect(smallWidgetWidth*5, 0, (smallWidgetWidth*6)-1, smallWidgetHeight)
124-
widgetMaxFarmingTime.Title = "Max farming time"
125-
ui.Render(widgetMaxFarmingTime)
120+
widgetOverallHealthPercent = widgets.NewParagraph()
121+
widgetOverallHealthPercent.Title = "Overall farming health indicator"
122+
widgetOverallHealthPercent.SetRect(77, 0, 119, smallWidgetHeight)
123+
widgetOverallHealthPercent.TextStyle.Fg = ui.ColorCyan
124+
widgetOverallHealthPercent.Text = "?? %"
126125

127126
widgetLog = widgets.NewParagraph()
128-
widgetLog.SetRect(0, 10, 179, smallWidgetHeight)
127+
widgetLog.SetRect(0, 15, 119, smallWidgetHeight)
129128
widgetLog.Title = "Last farming"
130129
ui.Render(widgetLog)
131130

132131
widgetBarChart = widgets.NewBarChart()
133-
widgetBarChart.Data = []float64{3, 2, 5, 3, 9, 3}
134-
widgetBarChart.Title = "Plots eligible for farming - last 29 values"
135-
widgetBarChart.SetRect(0, 10, 119, 25)
132+
widgetBarChart.Title = "Plots eligible for farming - last 59 values"
133+
widgetBarChart.SetRect(0, 15, 119, 25)
134+
widgetBarChart.BarWidth = 3
135+
widgetBarChart.BarGap = 1
136136
widgetBarChart.BarColors = []ui.Color{ui.ColorGreen}
137137
widgetBarChart.LabelStyles = []ui.Style{ui.NewStyle(ui.ColorBlue)}
138138
widgetBarChart.NumStyles = []ui.Style{ui.NewStyle(ui.ColorWhite)}
139139

140140
//widget for "not enough data"
141141
widgetBarChartParagraph = widgets.NewParagraph()
142-
widgetBarChartParagraph.SetRect(0, 10, 119, 25) //same as above
142+
widgetBarChartParagraph.SetRect(0, 15, 119, 25) //same as above
143143
widgetBarChartParagraph.Title = "Not engough data or zero values"
144144

145145
widgetBarChart2 = widgets.NewPlot()
146-
widgetBarChart2.Title = "Farming times (axis Y in seconds) - last 110 values"
146+
widgetBarChart2.Title = "Farming times (axis Y in seconds) - last 113 values"
147147
widgetBarChart2.Data = make([][]float64, 1)
148-
widgetBarChart2.SetRect(0, 25, 119, 40)
148+
widgetBarChart2.SetRect(0, 25, 119, 35)
149149
widgetBarChart2.AxesColor = ui.ColorWhite
150150
widgetBarChart2.LineColors[0] = ui.ColorRed
151151
widgetBarChart2.Marker = widgets.MarkerBraille
152152

153153
//widget for "not enough data"
154154
widgetBarChart2Paragraph = widgets.NewParagraph()
155-
widgetBarChart2Paragraph.SetRect(0, 25, 119, 40) //same as above
155+
widgetBarChart2Paragraph.SetRect(0, 25, 119, 35) //same as above
156156
widgetBarChart2Paragraph.Title = "Not engough data or zero values"
157157

158+
widgetSparklines = widgets.NewSparkline()
159+
widgetSparklines.Title = "1 col = 10 minutes block. It could be about 64 reqs/ 10minutes. Chart could be almost flat (+/-1 height block)"
160+
widgetSparklines.LineColor = ui.ColorBlue
161+
widgetSparklines.TitleStyle.Fg = ui.ColorWhite
162+
163+
widgetSparklinesGroup = widgets.NewSparklineGroup(widgetSparklines)
164+
widgetSparklinesGroup.Title = "Health indicator - number of incoming farming requests from the Chia network"
165+
widgetSparklinesGroup.SetRect(0, 35, 119, 45)
166+
158167
go loopReadFile()
159168

160169
uiEvents := ui.PollEvents()
@@ -173,15 +182,15 @@ func detectLogFileLocation() {
173182
flag.Parse()
174183
missingLogFile := false
175184

176-
//1 - try open debug.log in actual directory or get file from paremeter "log"
185+
//1 - try open debug.log in the actual directory or get file from the paremeter "log"
177186
fmt.Printf("trying: %s\n", *debuglogFile)
178187
if _, err := os.Stat(*debuglogFile); os.IsNotExist(err) {
179188
missingLogFile = true
180189
} else {
181190
return
182191
}
183192

184-
//2 - try open debug log from default home location
193+
//2 - try open debug log from the default home location
185194
usr, _ := user.Current()
186195
dir := usr.HomeDir
187196
defaultLogLocation := fmt.Sprintf("%s/.chia/mainnet/log/debug.log", dir)
@@ -202,11 +211,13 @@ func detectLogFileLocation() {
202211
func loopReadFile() {
203212
renderLog(fmt.Sprintf("Reading log %s, please wait", *debuglogFile))
204213
readFullFile(*debuglogFile)
214+
setLastLogFileSize(*debuglogFile)
215+
205216
c := time.Tick(5 * time.Second)
206217
var actualLogFileSize int64
207218
for range c {
208219
actualLogFileSize, _ = getFileSize(*debuglogFile)
209-
if actualLogFileSize == 0 {
220+
if actualLogFileSize == 0 || actualLogFileSize == lastLogFileSize {
210221
continue
211222
}
212223
if actualLogFileSize < lastLogFileSize { // new file ?
@@ -237,8 +248,6 @@ func readFullFile(fname string) {
237248
return
238249
}
239250

240-
//setLastLogFileSize(fname)
241-
242251
// os.Open() opens specific file in
243252
// read-only mode and this return
244253
// a pointer of type os.
@@ -280,8 +289,6 @@ func readFile(fname string) {
280289
return
281290
}
282291

283-
//setLastLogFileSize(fname)
284-
285292
file, err := os.Open(fname)
286293
if err != nil {
287294
panic(err)
@@ -336,6 +343,16 @@ func parseLines(lines []string) {
336343
if regexPlotsFarming.MatchString(s) {
337344
lastParsedLinesStack.push(s)
338345

346+
//extract number of requests in 10minutes blocks
347+
runes := []rune(s)
348+
dateTime := string(runes[0:15]) //1 or 10-minutes (15=10min, 16=1min)
349+
_, exists := healthData[dateTime]
350+
if !exists {
351+
healthData[dateTime] = 0
352+
}
353+
healthData[dateTime] = healthData[dateTime] + 1
354+
355+
//plots + proofs
339356
match := regexPlotsFarming.FindStringSubmatch(s)
340357
farmingPlotsNumber, _ := strconv.Atoi(match[1])
341358
foundProofsActual, _ := strconv.Atoi(match[2])
@@ -351,45 +368,52 @@ func parseLines(lines []string) {
351368
totalFarmingAttempt++
352369
lastFarmStack.push(float64(farmingPlotsNumber)) //data for barchart
353370

354-
parsedTime, _ := strconv.ParseFloat(farmingTime, 8)
371+
parsedTime, _ := strconv.ParseFloat(farmingTime, 8) //last time
372+
373+
allFarmingTimes = append(allFarmingTimes, parsedTime) //for AVG computing
374+
355375
if parsedTime < float64(minFarmingTime) {
356376
minFarmingTime = parsedTime
357377
}
358378
if parsedTime > float64(maxFarmingTime) {
359379
maxFarmingTime = parsedTime
360380
}
361381
lastFarmingTimesStack.push(parsedTime)
362-
363-
renderWidgets()
364382
}
365383
}
384+
366385
renderWidgets()
367386
renderLastFarmBarChart()
368387
renderLastFarmBarChart2()
388+
renderSparkLines()
369389

370390
var tmpTxt strings.Builder
371391
for i := range lastParsedLinesStack.lines {
372-
tmpTxt.WriteString(lastParsedLinesStack.lines[i])
392+
//tmpTxt.WriteString(lastParsedLinesStack.lines[i])
393+
twoCols := strings.Split(lastParsedLinesStack.lines[i], " ")
394+
tmpTxt.WriteString(twoCols[0])
395+
tmpTxt.WriteString("\n")
396+
tmpTxt.WriteString("-->")
397+
tmpTxt.WriteString(twoCols[1])
373398
tmpTxt.WriteString("\n")
374399
}
375400
renderLog(tmpTxt.String())
376401
}
377402

378403
func renderWidgets() {
404+
renderOverallHealth()
379405
renderTotalFarmingPlotsNumber()
380406
renderLastPlots()
381407
renderFoundProofs()
382408
renderLastFarmingTime()
383-
renderMinFarmingTime()
384-
renderMaxFarmingTime()
385409
}
386410

387411
func renderTotalFarmingPlotsNumber() {
388412
percent := 0.0
389413
if totalFarmingAttempt > 0 {
390414
percent = float64(float64(positiveFarmingAttempt)/float64(totalFarmingAttempt)) * 100
391415
}
392-
widgetTotalFarmingPlotsNumber.Text = fmt.Sprintf("%d/%d(%.2f%%)", positiveFarmingAttempt, totalFarmingAttempt, percent)
416+
widgetTotalFarmingPlotsNumber.Text = fmt.Sprintf("%d/%d(%.1f%%)", positiveFarmingAttempt, totalFarmingAttempt, percent)
393417
ui.Render(widgetTotalFarmingPlotsNumber)
394418
}
395419

@@ -404,7 +428,13 @@ func renderFoundProofs() {
404428
}
405429

406430
func renderLastFarmingTime() {
407-
widgetLastFarmingTime.Text = fmt.Sprintf("%ss", farmingTime)
431+
total := 0.0
432+
for _, number := range allFarmingTimes {
433+
total = total + number
434+
}
435+
average := total / float64(len(allFarmingTimes))
436+
437+
widgetLastFarmingTime.Text = fmt.Sprintf("%ss / %.3fs / %.3fs / %.3fs", farmingTime, minFarmingTime, average, maxFarmingTime)
408438
ui.Render(widgetLastFarmingTime)
409439
}
410440

@@ -413,14 +443,30 @@ func renderLog(text string) {
413443
ui.Render(widgetLog)
414444
}
415445

416-
func renderMinFarmingTime() {
417-
widgetMinFarmingTime.Text = fmt.Sprintf("%fs", minFarmingTime)
418-
ui.Render(widgetMinFarmingTime)
419-
}
446+
func renderOverallHealth() {
447+
values := sortMap(healthData)
448+
values = values[1 : len(values)-1] //remove the first and the last (may be incomplete)
449+
sum := sumFloats(values)
450+
avg := sum / float64(len(values))
451+
452+
//in chia network we can see 6.4 req/minute (64 req/10minutes) for farming
453+
percent := avg / 64 * 100
420454

421-
func renderMaxFarmingTime() {
422-
widgetMaxFarmingTime.Text = fmt.Sprintf("%fs", maxFarmingTime)
423-
ui.Render(widgetMaxFarmingTime)
455+
/*
456+
if percent > 100 { //result may be > 100%, but it is due some meassure inaccuracy
457+
percent = 100 //overwrite down to 100% is OK
458+
}*/
459+
460+
//percent := avg
461+
widgetOverallHealthPercent.TextStyle.Fg = ui.ColorRed
462+
if percent > 80 {
463+
widgetOverallHealthPercent.TextStyle.Fg = ui.ColorCyan
464+
}
465+
if percent > 95 {
466+
widgetOverallHealthPercent.TextStyle.Fg = ui.ColorGreen
467+
}
468+
widgetOverallHealthPercent.Text = fmt.Sprintf("%.2f%% - normal value is about 100%%", percent)
469+
ui.Render(widgetOverallHealthPercent)
424470
}
425471

426472
func renderLastFarmBarChart() {
@@ -446,3 +492,51 @@ func renderLastFarmBarChart2() {
446492

447493
ui.Render(widgetBarChart2Paragraph)
448494
}
495+
496+
func renderSparkLines() {
497+
498+
if len(healthData) == 0 {
499+
return
500+
}
501+
502+
v := sortMap(healthData)
503+
504+
sliceNumberOfValues := 117
505+
if len(v) < sliceNumberOfValues {
506+
sliceNumberOfValues = len(v)
507+
v = v[len(v)-sliceNumberOfValues:]
508+
}
509+
510+
widgetSparklines.Data = v
511+
ui.Render(widgetSparklinesGroup)
512+
}
513+
514+
func sortMap(m map[string]float64) []float64 {
515+
if len(m) == 0 {
516+
return make([]float64, 0)
517+
}
518+
519+
v := make([]float64, 0, len(m))
520+
521+
//sort map by keys
522+
keys := make([]string, 0, len(m))
523+
for k := range m {
524+
keys = append(keys, k)
525+
}
526+
sort.Strings(keys)
527+
for _, k := range keys {
528+
v = append(v, m[k])
529+
}
530+
531+
return v
532+
}
533+
534+
func sumFloats(input []float64) float64 {
535+
sum := 0.0
536+
537+
for i := range input {
538+
sum += input[i]
539+
}
540+
541+
return sum
542+
}

docs/screenshot-1.png

20.5 KB
Loading

0 commit comments

Comments
 (0)