diff --git a/config.json b/config.json index 1b885d18b12d298365cbf7ea9769a639800f504e..8550f6286b26a43241749146ee261612b75fe8cb 100644 --- a/config.json +++ b/config.json @@ -23,9 +23,8 @@ "DisableStacktrace":false, "Encoding":"console", "OutputPaths":[ - "stdout" - ], - "DisableEvents":false + "shimmer.log" + ] }, "node":{ "disableplugins":"", diff --git a/plugins/statusscreen/constants.go b/plugins/statusscreen/constants.go deleted file mode 100644 index 1fa6c46dac0ec691e0323e9e753952a2a7139b96..0000000000000000000000000000000000000000 --- a/plugins/statusscreen/constants.go +++ /dev/null @@ -1,7 +0,0 @@ -package statusscreen - -import "time" - -const ( - REPAINT_INTERVAL = 500 * time.Millisecond -) diff --git a/plugins/statusscreen/logger.go b/plugins/statusscreen/logger.go index 5d9d780b24f3135a27bca7ec3a24c755b8b125b7..10606990e2659ceb4a58f0267119bb457ed32856 100644 --- a/plugins/statusscreen/logger.go +++ b/plugins/statusscreen/logger.go @@ -1,31 +1,55 @@ package statusscreen import ( + stdlog "log" + "sync" "time" "github.com/iotaledger/hive.go/logger" ) -func storeStatusMessage(logLevel logger.Level, prefix string, message string) { - mutex.Lock() - defer mutex.Unlock() - messageLog = append(messageLog, &StatusMessage{ - Source: prefix, - LogLevel: logLevel, - Message: message, - Time: time.Now(), +var ( + mu sync.Mutex + logMessages = make([]*logMessage, 0) + logMessagesByName = make(map[string]*logMessage) +) + +type logMessage struct { + time time.Time + name string + level logger.Level + msg string +} + +func stdLogMsg(level logger.Level, name string, msg string) { + stdlog.Printf("[ %s ] %s: %s", + level.CapitalString(), + name, + msg, + ) +} + +func storeLogMsg(level logger.Level, name string, message string) { + mu.Lock() + defer mu.Unlock() + + logMessages = append(logMessages, &logMessage{ + time: time.Now(), + name: name, + level: level, + msg: message, }) - if statusMessage, exists := statusMessages[prefix]; !exists { - statusMessages[prefix] = &StatusMessage{ - Source: prefix, - LogLevel: logLevel, - Message: message, - Time: time.Now(), + if statusMessage, exists := logMessagesByName[name]; !exists { + logMessagesByName[name] = &logMessage{ + time: time.Now(), + name: name, + level: level, + msg: message, } } else { - statusMessage.LogLevel = logLevel - statusMessage.Message = message - statusMessage.Time = time.Now() + statusMessage.time = time.Now() + statusMessage.level = level + statusMessage.msg = message } } diff --git a/plugins/statusscreen/plugin.go b/plugins/statusscreen/plugin.go new file mode 100644 index 0000000000000000000000000000000000000000..544e19004106076228876cc8703a3ca01a7a4391 --- /dev/null +++ b/plugins/statusscreen/plugin.go @@ -0,0 +1,81 @@ +package statusscreen + +import ( + "time" + + "github.com/iotaledger/hive.go/daemon" + "github.com/iotaledger/hive.go/events" + "github.com/iotaledger/hive.go/logger" + "github.com/iotaledger/hive.go/node" +) + +const ( + name = "Statusscreen" + repaintInterval = 1 * time.Second +) + +var PLUGIN = node.NewPlugin(name, node.Enabled, configure, run) + +var ( + stdLogMsgClosure = events.NewClosure(stdLogMsg) + storeLogMsgClosure = events.NewClosure(storeLogMsg) +) + +func init() { + // use standard go logger by default + logger.Events.AnyMsg.Attach(stdLogMsgClosure) +} + +func configure(*node.Plugin) { + if !isTerminal() { + return + } + + // store any log message for display + logger.Events.AnyMsg.Attach(storeLogMsgClosure) + + log = logger.NewLogger(name) + configureTview() +} + +func run(*node.Plugin) { + if !isTerminal() { + return + } + + stopped := make(chan struct{}) + err := daemon.BackgroundWorker(name+" Refresher", func(shutdown <-chan struct{}) { + for { + select { + case <-time.After(repaintInterval): + app.QueueUpdateDraw(func() {}) + case <-shutdown: + logger.Events.AnyMsg.Detach(storeLogMsgClosure) + app.Stop() + return + case <-stopped: + return + } + } + }) + if err != nil { + log.Errorf("Failed to start as daemon: %s", err) + return + } + + err = daemon.BackgroundWorker(name+" App", func(<-chan struct{}) { + defer close(stopped) + + // switch logging to status screen + logger.Events.AnyMsg.Detach(stdLogMsgClosure) + defer logger.Events.AnyMsg.Attach(stdLogMsgClosure) + + if err := app.SetRoot(frame, true).SetFocus(frame).Run(); err != nil { + log.Errorf("Error running application: %s", err) + } + }) + if err != nil { + log.Errorf("Failed to start as daemon: %s", err) + close(stopped) + } +} diff --git a/plugins/statusscreen/status_message.go b/plugins/statusscreen/status_message.go deleted file mode 100644 index 2ec23aff1dd3bd3c4c935e986c8c13d370b2cfc7..0000000000000000000000000000000000000000 --- a/plugins/statusscreen/status_message.go +++ /dev/null @@ -1,14 +0,0 @@ -package statusscreen - -import ( - "time" - - "github.com/iotaledger/hive.go/logger" -) - -type StatusMessage struct { - Source string - LogLevel logger.Level - Message string - Time time.Time -} diff --git a/plugins/statusscreen/statusscreen.go b/plugins/statusscreen/statusscreen.go index 0d51af1e13869886815b206082fc0fa841f5db93..40acb01ba3fa40ea593118d47f0e6165210fcf9a 100644 --- a/plugins/statusscreen/statusscreen.go +++ b/plugins/statusscreen/statusscreen.go @@ -2,61 +2,21 @@ package statusscreen import ( "os" - "sync" - "time" "github.com/gdamore/tcell" "github.com/iotaledger/hive.go/daemon" - "github.com/iotaledger/hive.go/events" "github.com/iotaledger/hive.go/logger" - "github.com/iotaledger/hive.go/node" "github.com/rivo/tview" "golang.org/x/crypto/ssh/terminal" ) -var statusMessages = make(map[string]*StatusMessage) -var messageLog = make([]*StatusMessage, 0) -var mutex sync.RWMutex - -var app *tview.Application - -func configure(plugin *node.Plugin) { - if !terminal.IsTerminal(int(os.Stdin.Fd())) { - return - } - - // store any log message for display - anyLogMsgClosure := events.NewClosure(func(logLevel logger.Level, prefix string, msg string) { - storeStatusMessage(logLevel, prefix, msg) - }) - logger.Events.AnyMsg.Attach(anyLogMsgClosure) - - daemon.BackgroundWorker("UI-Detach", func(shutdownSignal <-chan struct{}) { - <-shutdownSignal - logger.Events.AnyMsg.Detach(anyLogMsgClosure) - if app != nil { - app.Stop() - } - }, 1) -} - -func run(plugin *node.Plugin) { - if !terminal.IsTerminal(int(os.Stdin.Fd())) { - return - } - - newPrimitive := func(text string) *tview.TextView { - textView := tview.NewTextView() - - textView. - SetTextAlign(tview.AlignLeft). - SetText(" " + text) - - return textView - } - - app = tview.NewApplication() +var ( + log *logger.Logger + app *tview.Application + frame *tview.Frame +) +func configureTview() { headerBar := NewUIHeaderBar() content := tview.NewGrid() @@ -78,30 +38,28 @@ func run(plugin *node.Plugin) { AddItem(content, 1, 0, 1, 1, 0, 0, false). AddItem(footer, 2, 0, 1, 1, 0, 0, false) - frame := tview.NewFrame(grid). + frame = tview.NewFrame(grid). SetBorders(1, 1, 0, 0, 2, 2) frame.SetBackgroundColor(tcell.ColorDarkGray) + app = tview.NewApplication() app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { + // end the daemon on ctrl+c if event.Key() == tcell.KeyCtrlC || event.Key() == tcell.KeyESC { daemon.Shutdown() - return nil } - return event }) app.SetBeforeDrawFunc(func(screen tcell.Screen) bool { - mutex.RLock() - defer mutex.RUnlock() headerBar.Update() rows := make([]int, 2) rows[0] = 1 rows[1] = 1 _, _, _, height := content.GetRect() - for i := 0; i < len(messageLog) && i < height-2; i++ { + for i := 0; i < len(logMessages) && i < height-2; i++ { rows = append(rows, 1) } @@ -112,12 +70,12 @@ func run(plugin *node.Plugin) { blankLine.SetBackgroundColor(tcell.ColorWhite) content.AddItem(blankLine, 0, 0, 1, 1, 0, 0, false) - logStart := len(messageLog) - (len(rows) - 2) + logStart := len(logMessages) - (len(rows) - 2) if logStart < 0 { logStart = 0 } - for i, message := range messageLog[logStart:] { + for i, message := range logMessages[logStart:] { if i < height-2 { content.AddItem(NewUILogEntry(*message).Primitive, i+1, 0, 1, 1, 0, 0, false) } @@ -129,23 +87,15 @@ func run(plugin *node.Plugin) { return false }) +} - daemon.BackgroundWorker("Statusscreen Refresher", func(shutdownSignal <-chan struct{}) { - for { - select { - case <-shutdownSignal: - return - case <-time.After(1 * time.Second): - app.QueueUpdateDraw(func() {}) - } - } - }) +func newPrimitive(text string) *tview.TextView { + textView := tview.NewTextView() + textView.SetTextAlign(tview.AlignLeft).SetText(" " + text) - daemon.BackgroundWorker("Statusscreen App", func(shutdownSignal <-chan struct{}) { - if err := app.SetRoot(frame, true).SetFocus(frame).Run(); err != nil { - panic(err) - } - }) + return textView } -var PLUGIN = node.NewPlugin("Status Screen", node.Enabled, configure, run) +func isTerminal() bool { + return terminal.IsTerminal(int(os.Stdin.Fd())) +} diff --git a/plugins/statusscreen/ui_log.go b/plugins/statusscreen/ui_log.go deleted file mode 100644 index 6dae65662bd2b2b100d954409c7435e558443587..0000000000000000000000000000000000000000 --- a/plugins/statusscreen/ui_log.go +++ /dev/null @@ -1,15 +0,0 @@ -package statusscreen - -import "github.com/rivo/tview" - -type UILog struct { - Primitive *tview.Grid -} - -func NewUILog() *UILog { - uiLog := &UILog{ - Primitive: tview.NewGrid(), - } - - return uiLog -} diff --git a/plugins/statusscreen/ui_log_entry.go b/plugins/statusscreen/ui_log_entry.go index 4134636d1d48a71efe2a1d1d3060aec4866e2560..57cbc6e7ebefa986056c8df36a3f1cb5003793f6 100644 --- a/plugins/statusscreen/ui_log_entry.go +++ b/plugins/statusscreen/ui_log_entry.go @@ -15,7 +15,7 @@ type UILogEntry struct { LogLevelContainer *tview.TextView } -func NewUILogEntry(message StatusMessage) *UILogEntry { +func NewUILogEntry(message logMessage) *UILogEntry { logEntry := &UILogEntry{ Primitive: tview.NewGrid(), TimeContainer: tview.NewTextView(), @@ -36,7 +36,7 @@ func NewUILogEntry(message StatusMessage) *UILogEntry { logEntry.LogLevelContainer.SetDynamicColors(true) textColor := "black::d" - switch message.LogLevel { + switch message.level { case logger.LevelInfo: fmt.Fprintf(logEntry.LogLevelContainer, " [black::d][ [blue::d]INFO [black::d]]") case logger.LevelWarn: @@ -57,11 +57,11 @@ func NewUILogEntry(message StatusMessage) *UILogEntry { textColor = "black::b" } - fmt.Fprintf(logEntry.TimeContainer, " [black::b]"+message.Time.Format("15:04:05")) - if message.Source == "Node" { - fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.Message) + fmt.Fprintf(logEntry.TimeContainer, " [black::b]"+message.time.Format("15:04:05")) + if message.name == "Node" { + fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.msg) } else { - fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.Source+": "+message.Message) + fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.name+": "+message.msg) } logEntry.Primitive.