Skip to content
This repository was archived by the owner on Aug 2, 2023. It is now read-only.

Commit f8fec48

Browse files
authored
Dashboard update (#16)
* Update timout work * Add simple error comparsion between calls * Update docker to run terminal dashboard in browser * Small corrections and fixes
1 parent 7644df9 commit f8fec48

File tree

165 files changed

+31928
-46
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

165 files changed

+31928
-46
lines changed

Dockerfile

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
1-
FROM golang:1.10-alpine
1+
FROM golang:1.12-stretch
22

3-
LABEL description="Image to compile project from container"
3+
LABEL description="Image to execute BitAccretion in web"
4+
ENV GO111MODULE=off
45

5-
# Create working paths
6+
# Install deps
7+
RUN apt-get -y update && apt-get install -y \
8+
ca-certificates \
9+
make \
10+
libasound2 \
11+
libasound2-dev \
12+
curl \
13+
tar
14+
15+
# Install gotty for web terminal
16+
# TODO Remove hardocded gotty version
17+
RUN curl -sLk https://github.com/yudai/gotty/releases/download/v2.0.0-alpha.3/gotty_2.0.0-alpha.3_linux_amd64.tar.gz | tar xzC /opt && \
18+
chmod +x /opt/gotty && \
19+
chmod 744 /opt/gotty && \
20+
mv /opt/gotty /usr/local/bin/
21+
22+
RUN apt-get purge --auto-remove -y && apt-get clean && rm -rf /var/lib/apt/lists*
23+
24+
# Setup application paths
625
RUN mkdir -p /go/src/github.com/LinMAD/BitAccretion
26+
COPY ./. /go/src/github.com/LinMAD/BitAccretion
727
WORKDIR /go/src/github.com/LinMAD/BitAccretion
828

9-
# Install dependecies
10-
RUN apk update && apk add --update \
11-
build-base make \
12-
git \
13-
nodejs nodejs-npm \
14-
alsa-lib-dev
29+
# Compile it
30+
# TODO Remove hardcoded provider plugin
31+
RUN go build -o ./build/BitAccretion main.go && make plugin_relic && make plugin_sound
32+
COPY config.json build/config.json
33+
WORKDIR build
34+
35+
# Execute
36+
EXPOSE 8080
37+
CMD gotty --reconnect ./BitAccretion

core/kernel.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,13 @@ func (k *Kernel) initDashboard(t terminalapi.Terminal) error {
6464

6565
log.Println("Creating terminal dashboard UI...")
6666
var dErr error
67-
k.d, dErr = dashboard.NewMonitoringDashboard("BitAccretion", k.c, k.s, t, g)
67+
k.d, dErr = dashboard.NewMonitoringDashboard(
68+
fmt.Sprintf("BitAccretion:%s - [%s]", k.p.GetDescription().Name, k.p.GetDescription().MetricsDescription),
69+
k.c,
70+
k.s,
71+
t,
72+
g,
73+
)
6874
if dErr != nil {
6975
return dErr
7076
}
@@ -89,7 +95,7 @@ func (k *Kernel) dashboardUpdate(ctx context.Context, delay time.Duration) {
8995
}
9096

9197
isNeedToFetch = false
92-
k.l.Normal("Requesting provider to get new data update...")
98+
k.l.Normal(fmt.Sprintf("Requesting provider (%s) to get new data update...", k.p.GetDescription().Name))
9399

94100
providerGraph, providerGraphErr := k.p.FetchNewData(k.l)
95101
if providerGraphErr != nil {
@@ -133,6 +139,7 @@ func (k *Kernel) Run(t terminalapi.Terminal) error {
133139

134140
fmt.Print("\033[H\033[2J") // Clean terminal screen from any artifacts
135141

142+
k.l.Normal("Dashboard ready and preparing to collect data...")
136143
termErr := termdash.Run(
137144
ctx,
138145
t,

dashboard/dashboard.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type widgets struct {
2626
reqAggregated *SparkLineWidgetHandler
2727
eventLog *AnnouncerHandler
2828
clock *ClockWidgetHandler
29+
regression *GaugeRegressHandler
2930
}
3031

3132
// HandleNotifyEvent send update to monitoring dashboard
@@ -61,7 +62,8 @@ func (m *MonitoringDashboard) initWidgets(s extension.ISound, c *model.Config, n
6162
if err != nil {
6263
return err
6364
}
64-
m.widgetCollection.clock, err = NewClockWidget()
65+
66+
m.widgetCollection.regression, err = NewRegressionWidget("Regression level of errors", c)
6567
if err != nil {
6668
return err
6769
}
@@ -73,7 +75,7 @@ func (m *MonitoringDashboard) initWidgets(s extension.ISound, c *model.Config, n
7375
func (m *MonitoringDashboard) createLayout(dashboardName string, t *terminalapi.Terminal) (err error) {
7476
m.TerminalContainer, err = container.New(
7577
*t,
76-
container.Border(linestyle.Double),
78+
container.Border(linestyle.Light),
7779
container.BorderTitle(dashboardName),
7880
container.SplitHorizontal(
7981
container.Top(
@@ -82,10 +84,10 @@ func (m *MonitoringDashboard) createLayout(dashboardName string, t *terminalapi.
8284
container.SplitHorizontal(
8385
container.Top(
8486
container.Border(linestyle.Round),
85-
container.PlaceWidget(m.widgetCollection.clock.sdClock),
87+
container.PlaceWidget(m.widgetCollection.regression.gauge),
8688
),
8789
container.Bottom(
88-
container.Border(linestyle.Double),
90+
container.Border(linestyle.Round),
8991
container.BorderTitle("Event log"),
9092
container.PlaceWidget(m.widgetCollection.eventLog.t),
9193
),
@@ -143,6 +145,7 @@ func NewMonitoringDashboard(dashboardName string, c *model.Config, s extension.I
143145
termDash.observer.RegisterNewSubscriber(termDash.widgetCollection.reqIncorrect)
144146
termDash.observer.RegisterNewSubscriber(termDash.widgetCollection.reqAggregated)
145147
termDash.observer.RegisterNewSubscriber(termDash.widgetCollection.eventLog)
148+
termDash.observer.RegisterNewSubscriber(termDash.widgetCollection.regression)
146149

147150
return termDash, nil
148151
}

dashboard/log.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,21 @@ func (l *loggerHandler) SetMode(level logger.LevelOfLog) {
2323

2424
// Debug messages
2525
func (l *loggerHandler) Debug(msg string) {
26-
if l.lvl == logger.DebugLog {
26+
if l.lvl <= logger.DebugLog {
2727
l.widget.WriteToEventLog("Debug: "+msg, cell.ColorWhite)
2828
}
2929
}
3030

3131
// Normal events messages
3232
func (l *loggerHandler) Normal(msg string) {
33-
l.widget.WriteToEventLog(msg, cell.ColorWhite)
33+
if l.lvl < logger.ErrorLog {
34+
l.widget.WriteToEventLog(msg, cell.ColorWhite)
35+
}
3436
}
3537

3638
// Error events messages
3739
func (l *loggerHandler) Error(msg string) {
38-
if l.lvl == logger.ErrorLog {
40+
if l.lvl <= logger.ErrorLog {
3941
l.widget.WriteToEventLog(msg, cell.ColorRed)
4042
}
4143
}

dashboard/regression.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package dashboard
2+
3+
import (
4+
"github.com/LinMAD/BitAccretion/event"
5+
"github.com/LinMAD/BitAccretion/model"
6+
"github.com/mum4k/termdash/cell"
7+
"github.com/mum4k/termdash/linestyle"
8+
"github.com/mum4k/termdash/widgets/gauge"
9+
)
10+
11+
// GaugeRegressHandler for dashboard
12+
type GaugeRegressHandler struct {
13+
name string
14+
gauge *gauge.Gauge
15+
config *model.Config
16+
// currentRatio showing regression of errors
17+
currentRatio int
18+
prevErrCount int
19+
}
20+
21+
// HandleNotifyEvent update of gauge regression process
22+
func (g *GaugeRegressHandler) HandleNotifyEvent(e event.UpdateEvent) error {
23+
if err := g.gauge.Percent(g.currentRatio); err != nil {
24+
panic(err)
25+
}
26+
27+
var newErrCount int
28+
vertices := e.MonitoringGraph.GetAllVertices()
29+
l := len(vertices)
30+
31+
for i := 0; i < l; i++ {
32+
newErrCount += int(vertices[i].Metric.ErrorCount)
33+
}
34+
35+
// TODO Think about longer compactions maybe between hours or weeks
36+
if newErrCount == 0 {
37+
g.currentRatio = 0
38+
g.prevErrCount = 0
39+
} else {
40+
g.currentRatio = +(newErrCount - g.prevErrCount)
41+
if g.currentRatio > 100 {
42+
g.currentRatio = 100
43+
} else if g.currentRatio < 0 {
44+
g.currentRatio = 0
45+
}
46+
}
47+
48+
g.prevErrCount = newErrCount
49+
50+
return nil
51+
}
52+
53+
// GetName of widget handler
54+
func (g *GaugeRegressHandler) GetName() string {
55+
return g.name
56+
}
57+
58+
// NewRegressionWidget create and return prepared widget, shows % of ok/err requests as regression
59+
func NewRegressionWidget(name string, c *model.Config) (*GaugeRegressHandler, error) {
60+
g, err := gauge.New(
61+
gauge.Height(2),
62+
gauge.Color(cell.ColorRed),
63+
gauge.Border(linestyle.Light, cell.FgColor(cell.ColorYellow)),
64+
gauge.BorderTitle(name),
65+
)
66+
if err != nil {
67+
return nil, err
68+
}
69+
70+
widget := &GaugeRegressHandler{
71+
name: name,
72+
gauge: g,
73+
config: c,
74+
}
75+
76+
return widget, nil
77+
}

docker.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env sh
2+
3+
build() {
4+
docker build -t web_bit_accretion .
5+
}
6+
7+
# ARG - 1 port
8+
execute() {
9+
docker run -it --rm -p "80:8080" --device /dev/snd:/dev/snd --network host --name web_bit_accretion web_bit_accretion
10+
}
11+
12+
### MAIN
13+
build
14+
execute "$1"

extension/fake/provider.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
// FakeProvider randomly generates dummy data
1212
type FakeProvider struct {
1313
pluginHealth model.HealthState
14+
pluginInfo model.ProviderDescription
1415
}
1516

1617
// LoadConfig stub
@@ -40,9 +41,20 @@ func (f *FakeProvider) ProvideHealth() model.HealthState {
4041
return f.pluginHealth
4142
}
4243

44+
// GetDescription of provider
45+
func (f *FakeProvider) GetDescription() model.ProviderDescription {
46+
return f.pluginInfo
47+
}
48+
4349
// NewProvider implementation
4450
func NewProvider() extension.IProvider {
45-
return &FakeProvider{pluginHealth: model.HealthNormal}
51+
return &FakeProvider{
52+
pluginHealth: model.HealthNormal,
53+
pluginInfo: model.ProviderDescription{
54+
Name: "Fake provider",
55+
MetricsDescription: "Random generated data",
56+
},
57+
}
4658
}
4759

4860
// GetStubNodes generated dummy nodes with data

extension/newrelic/provider.go

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
import (
4-
"context"
54
"encoding/json"
65
"fmt"
76
"os"
@@ -50,6 +49,8 @@ type ProviderNewRelic struct {
5049
worker *worker.RelicWorker
5150
// pluginHealth current state of extension
5251
pluginHealth model.HealthState
52+
// pluginIfo short info of new relic provider
53+
pluginInfo model.ProviderDescription
5354
}
5455

5556
// LoadConfig of new relic extension
@@ -93,31 +94,23 @@ func (nr *ProviderNewRelic) DispatchGraph() (model.Graph, error) {
9394
// FetchNewData returns latest assembled graph
9495
func (nr *ProviderNewRelic) FetchNewData(log logger.ILogger) (model.Graph, error) {
9596
g := nr.prepareGraph()
97+
timeout := time.After(time.Duration(nr.Config.SurveyIntervalSec*2+1) * time.Second)
98+
isProcessed := make(chan bool, 1)
9699

97-
log.Debug(fmt.Sprintf("Harvesting data from NewRelic API..."))
98-
99-
ctx, cancel := context.WithCancel(context.Background())
100-
101-
// Get info from API with timeout
102-
ticker := time.NewTicker(time.Duration(nr.Config.SurveyIntervalSec*2+1) * time.Second)
103-
defer ticker.Stop()
104-
isExecuted := false // all only one coroutine
100+
go func(g *model.Graph) {
101+
log.Debug(fmt.Sprintf("Harvesting data from NewRelic API..."))
102+
nr.fetchMetricsWithGraph(g, log)
103+
isProcessed <- true
104+
}(g)
105105

106106
for {
107107
select {
108-
default:
109-
if isExecuted {
110-
continue
111-
}
112-
113-
isExecuted = true
114-
go func(g *model.Graph) {
115-
defer cancel()
116-
nr.fetchMetricsWithGraph(g, log)
117-
}(g)
118-
case <-ticker.C:
119-
cancel()
120-
case <-ctx.Done():
108+
case <-isProcessed:
109+
nr.pluginHealth = model.HealthNormal
110+
return *g, nil
111+
case <-timeout:
112+
log.Error("Timeout got from NewRelic provider...")
113+
nr.pluginHealth = model.HealthWarning
121114
return *g, nil
122115
}
123116
}
@@ -128,6 +121,11 @@ func (nr *ProviderNewRelic) ProvideHealth() model.HealthState {
128121
return nr.pluginHealth
129122
}
130123

124+
// GetDescription of provider
125+
func (nr *ProviderNewRelic) GetDescription() model.ProviderDescription {
126+
return nr.pluginInfo
127+
}
128+
131129
// fetchMetricsWithGraph from API and put in to graph
132130
func (nr *ProviderNewRelic) fetchMetricsWithGraph(g *model.Graph, log logger.ILogger) {
133131
appList := g.GetAllVertices()
@@ -191,5 +189,11 @@ func (nr *ProviderNewRelic) prepareGraph() (g *model.Graph) {
191189

192190
// NewProvider returns instance with implemented interface
193191
func NewProvider() extension.IProvider {
194-
return &ProviderNewRelic{pluginHealth: model.HealthNormal}
192+
return &ProviderNewRelic{
193+
pluginHealth: model.HealthNormal,
194+
pluginInfo: model.ProviderDescription{
195+
Name: "New Relic API",
196+
MetricsDescription: "Requests per minute",
197+
},
198+
}
195199
}

extension/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ type IProvider interface {
1919
// ProvideHealth must provide if extension still can work
2020
// example API not reachable or extension has errors and it must be restarted
2121
ProvideHealth() model.HealthState
22+
// GetDescription of implemented provider
23+
GetDescription() model.ProviderDescription
2224
}

main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package main
22

33
import (
4+
"runtime"
5+
46
"github.com/LinMAD/BitAccretion/core"
57
"github.com/LinMAD/BitAccretion/extension"
68
"github.com/LinMAD/BitAccretion/model"
79
"github.com/mum4k/termdash/terminal/termbox"
810
)
911

1012
func main() {
13+
runtime.GOMAXPROCS(runtime.NumCPU())
14+
1115
t, err := termbox.New()
1216
if err != nil {
1317
panic(err)

0 commit comments

Comments
 (0)