@@ -14,6 +14,7 @@ import (
14
14
"os"
15
15
"os/user"
16
16
"regexp"
17
+ "sort"
17
18
"strconv"
18
19
"strings"
19
20
"time"
@@ -30,12 +31,13 @@ var widgetFoundProofs *widgets.Paragraph
30
31
var widgetLastFarmingTime * widgets.Paragraph
31
32
var widgetTotalFarmingPlotsNumber * widgets.Paragraph
32
33
var widgetLog * widgets.Paragraph
33
- var widgetMinFarmingTime * widgets.Paragraph
34
- var widgetMaxFarmingTime * widgets.Paragraph
35
34
var widgetBarChart * widgets.BarChart
36
35
var widgetBarChartParagraph * widgets.Paragraph
37
36
var widgetBarChart2 * widgets.Plot
38
37
var widgetBarChart2Paragraph * widgets.Paragraph
38
+ var widgetSparklines * widgets.Sparkline
39
+ var widgetSparklinesGroup * widgets.SparklineGroup
40
+ var widgetOverallHealthPercent * widgets.Paragraph
39
41
var lastRow string = ""
40
42
var lastParsedLines []string
41
43
@@ -50,8 +52,10 @@ var farmingTime = "0"
50
52
var totalPlots = "0"
51
53
var minFarmingTime = 999999.0
52
54
var maxFarmingTime = 0.0
55
+ var allFarmingTimes []float64
53
56
54
57
var lastLogFileSize = int64 (0 )
58
+ var healthData = make (map [string ]float64 )
55
59
56
60
type stackStruct struct {
57
61
lines []string
@@ -81,7 +85,7 @@ func (stack *stackStructFloats) push(value float64) {
81
85
82
86
var lastParsedLinesStack = stackStruct {count : 5 }
83
87
var lastFarmStack = stackStructFloats {count : 29 }
84
- var lastFarmingTimesStack = stackStructFloats {count : 110 }
88
+ var lastFarmingTimesStack = stackStructFloats {count : 113 }
85
89
86
90
func main () {
87
91
detectLogFileLocation ()
@@ -91,70 +95,75 @@ func main() {
91
95
}
92
96
defer ui .Close ()
93
97
94
- var smallWidgetWidth = 20
95
98
var smallWidgetHeight = 3
96
99
97
100
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 "
100
103
ui .Render (widgetLastPlots )
101
104
102
105
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 "
105
108
ui .Render (widgetFoundProofs )
106
109
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
-
112
110
widgetTotalFarmingPlotsNumber = widgets .NewParagraph ()
113
- widgetTotalFarmingPlotsNumber .SetRect (smallWidgetWidth * 3 , 0 , ( smallWidgetWidth * 4 ) - 1 , smallWidgetHeight )
111
+ widgetTotalFarmingPlotsNumber .SetRect (18 , 0 , 37 , smallWidgetHeight )
114
112
widgetTotalFarmingPlotsNumber .Title = "Farming attempts"
115
113
ui .Render (widgetTotalFarmingPlotsNumber )
116
114
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 )
121
119
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 = "?? %"
126
125
127
126
widgetLog = widgets .NewParagraph ()
128
- widgetLog .SetRect (0 , 10 , 179 , smallWidgetHeight )
127
+ widgetLog .SetRect (0 , 15 , 119 , smallWidgetHeight )
129
128
widgetLog .Title = "Last farming"
130
129
ui .Render (widgetLog )
131
130
132
131
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
136
136
widgetBarChart .BarColors = []ui.Color {ui .ColorGreen }
137
137
widgetBarChart .LabelStyles = []ui.Style {ui .NewStyle (ui .ColorBlue )}
138
138
widgetBarChart .NumStyles = []ui.Style {ui .NewStyle (ui .ColorWhite )}
139
139
140
140
//widget for "not enough data"
141
141
widgetBarChartParagraph = widgets .NewParagraph ()
142
- widgetBarChartParagraph .SetRect (0 , 10 , 119 , 25 ) //same as above
142
+ widgetBarChartParagraph .SetRect (0 , 15 , 119 , 25 ) //same as above
143
143
widgetBarChartParagraph .Title = "Not engough data or zero values"
144
144
145
145
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"
147
147
widgetBarChart2 .Data = make ([][]float64 , 1 )
148
- widgetBarChart2 .SetRect (0 , 25 , 119 , 40 )
148
+ widgetBarChart2 .SetRect (0 , 25 , 119 , 35 )
149
149
widgetBarChart2 .AxesColor = ui .ColorWhite
150
150
widgetBarChart2 .LineColors [0 ] = ui .ColorRed
151
151
widgetBarChart2 .Marker = widgets .MarkerBraille
152
152
153
153
//widget for "not enough data"
154
154
widgetBarChart2Paragraph = widgets .NewParagraph ()
155
- widgetBarChart2Paragraph .SetRect (0 , 25 , 119 , 40 ) //same as above
155
+ widgetBarChart2Paragraph .SetRect (0 , 25 , 119 , 35 ) //same as above
156
156
widgetBarChart2Paragraph .Title = "Not engough data or zero values"
157
157
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
+
158
167
go loopReadFile ()
159
168
160
169
uiEvents := ui .PollEvents ()
@@ -173,15 +182,15 @@ func detectLogFileLocation() {
173
182
flag .Parse ()
174
183
missingLogFile := false
175
184
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"
177
186
fmt .Printf ("trying: %s\n " , * debuglogFile )
178
187
if _ , err := os .Stat (* debuglogFile ); os .IsNotExist (err ) {
179
188
missingLogFile = true
180
189
} else {
181
190
return
182
191
}
183
192
184
- //2 - try open debug log from default home location
193
+ //2 - try open debug log from the default home location
185
194
usr , _ := user .Current ()
186
195
dir := usr .HomeDir
187
196
defaultLogLocation := fmt .Sprintf ("%s/.chia/mainnet/log/debug.log" , dir )
@@ -202,11 +211,13 @@ func detectLogFileLocation() {
202
211
func loopReadFile () {
203
212
renderLog (fmt .Sprintf ("Reading log %s, please wait" , * debuglogFile ))
204
213
readFullFile (* debuglogFile )
214
+ setLastLogFileSize (* debuglogFile )
215
+
205
216
c := time .Tick (5 * time .Second )
206
217
var actualLogFileSize int64
207
218
for range c {
208
219
actualLogFileSize , _ = getFileSize (* debuglogFile )
209
- if actualLogFileSize == 0 {
220
+ if actualLogFileSize == 0 || actualLogFileSize == lastLogFileSize {
210
221
continue
211
222
}
212
223
if actualLogFileSize < lastLogFileSize { // new file ?
@@ -237,8 +248,6 @@ func readFullFile(fname string) {
237
248
return
238
249
}
239
250
240
- //setLastLogFileSize(fname)
241
-
242
251
// os.Open() opens specific file in
243
252
// read-only mode and this return
244
253
// a pointer of type os.
@@ -280,8 +289,6 @@ func readFile(fname string) {
280
289
return
281
290
}
282
291
283
- //setLastLogFileSize(fname)
284
-
285
292
file , err := os .Open (fname )
286
293
if err != nil {
287
294
panic (err )
@@ -336,6 +343,16 @@ func parseLines(lines []string) {
336
343
if regexPlotsFarming .MatchString (s ) {
337
344
lastParsedLinesStack .push (s )
338
345
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
339
356
match := regexPlotsFarming .FindStringSubmatch (s )
340
357
farmingPlotsNumber , _ := strconv .Atoi (match [1 ])
341
358
foundProofsActual , _ := strconv .Atoi (match [2 ])
@@ -351,45 +368,52 @@ func parseLines(lines []string) {
351
368
totalFarmingAttempt ++
352
369
lastFarmStack .push (float64 (farmingPlotsNumber )) //data for barchart
353
370
354
- parsedTime , _ := strconv .ParseFloat (farmingTime , 8 )
371
+ parsedTime , _ := strconv .ParseFloat (farmingTime , 8 ) //last time
372
+
373
+ allFarmingTimes = append (allFarmingTimes , parsedTime ) //for AVG computing
374
+
355
375
if parsedTime < float64 (minFarmingTime ) {
356
376
minFarmingTime = parsedTime
357
377
}
358
378
if parsedTime > float64 (maxFarmingTime ) {
359
379
maxFarmingTime = parsedTime
360
380
}
361
381
lastFarmingTimesStack .push (parsedTime )
362
-
363
- renderWidgets ()
364
382
}
365
383
}
384
+
366
385
renderWidgets ()
367
386
renderLastFarmBarChart ()
368
387
renderLastFarmBarChart2 ()
388
+ renderSparkLines ()
369
389
370
390
var tmpTxt strings.Builder
371
391
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 ])
373
398
tmpTxt .WriteString ("\n " )
374
399
}
375
400
renderLog (tmpTxt .String ())
376
401
}
377
402
378
403
func renderWidgets () {
404
+ renderOverallHealth ()
379
405
renderTotalFarmingPlotsNumber ()
380
406
renderLastPlots ()
381
407
renderFoundProofs ()
382
408
renderLastFarmingTime ()
383
- renderMinFarmingTime ()
384
- renderMaxFarmingTime ()
385
409
}
386
410
387
411
func renderTotalFarmingPlotsNumber () {
388
412
percent := 0.0
389
413
if totalFarmingAttempt > 0 {
390
414
percent = float64 (float64 (positiveFarmingAttempt )/ float64 (totalFarmingAttempt )) * 100
391
415
}
392
- widgetTotalFarmingPlotsNumber .Text = fmt .Sprintf ("%d/%d(%.2f %%)" , positiveFarmingAttempt , totalFarmingAttempt , percent )
416
+ widgetTotalFarmingPlotsNumber .Text = fmt .Sprintf ("%d/%d(%.1f %%)" , positiveFarmingAttempt , totalFarmingAttempt , percent )
393
417
ui .Render (widgetTotalFarmingPlotsNumber )
394
418
}
395
419
@@ -404,7 +428,13 @@ func renderFoundProofs() {
404
428
}
405
429
406
430
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 )
408
438
ui .Render (widgetLastFarmingTime )
409
439
}
410
440
@@ -413,14 +443,30 @@ func renderLog(text string) {
413
443
ui .Render (widgetLog )
414
444
}
415
445
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
420
454
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 )
424
470
}
425
471
426
472
func renderLastFarmBarChart () {
@@ -446,3 +492,51 @@ func renderLastFarmBarChart2() {
446
492
447
493
ui .Render (widgetBarChart2Paragraph )
448
494
}
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
+ }
0 commit comments