Skip to content
Snippets Groups Projects
Commit a32056dc authored by Wolfgang Welz's avatar Wolfgang Welz
Browse files

fix: log to console if status screen is not running

parent 43e837e5
Branches
Tags
No related merge requests found
...@@ -23,9 +23,8 @@ ...@@ -23,9 +23,8 @@
"DisableStacktrace":false, "DisableStacktrace":false,
"Encoding":"console", "Encoding":"console",
"OutputPaths":[ "OutputPaths":[
"stdout" "shimmer.log"
], ]
"DisableEvents":false
}, },
"node":{ "node":{
"disableplugins":"", "disableplugins":"",
......
package statusscreen
import "time"
const (
REPAINT_INTERVAL = 500 * time.Millisecond
)
package statusscreen package statusscreen
import ( import (
stdlog "log"
"sync"
"time" "time"
"github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/logger"
) )
func storeStatusMessage(logLevel logger.Level, prefix string, message string) { var (
mutex.Lock() mu sync.Mutex
defer mutex.Unlock() logMessages = make([]*logMessage, 0)
messageLog = append(messageLog, &StatusMessage{ logMessagesByName = make(map[string]*logMessage)
Source: prefix, )
LogLevel: logLevel,
Message: message, type logMessage struct {
Time: time.Now(), 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 { if statusMessage, exists := logMessagesByName[name]; !exists {
statusMessages[prefix] = &StatusMessage{ logMessagesByName[name] = &logMessage{
Source: prefix, time: time.Now(),
LogLevel: logLevel, name: name,
Message: message, level: level,
Time: time.Now(), msg: message,
} }
} else { } else {
statusMessage.LogLevel = logLevel statusMessage.time = time.Now()
statusMessage.Message = message statusMessage.level = level
statusMessage.Time = time.Now() statusMessage.msg = message
} }
} }
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)
}
}
package statusscreen
import (
"time"
"github.com/iotaledger/hive.go/logger"
)
type StatusMessage struct {
Source string
LogLevel logger.Level
Message string
Time time.Time
}
...@@ -2,61 +2,21 @@ package statusscreen ...@@ -2,61 +2,21 @@ package statusscreen
import ( import (
"os" "os"
"sync"
"time"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"github.com/iotaledger/hive.go/daemon" "github.com/iotaledger/hive.go/daemon"
"github.com/iotaledger/hive.go/events"
"github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/logger"
"github.com/iotaledger/hive.go/node"
"github.com/rivo/tview" "github.com/rivo/tview"
"golang.org/x/crypto/ssh/terminal" "golang.org/x/crypto/ssh/terminal"
) )
var statusMessages = make(map[string]*StatusMessage) var (
var messageLog = make([]*StatusMessage, 0) log *logger.Logger
var mutex sync.RWMutex app *tview.Application
frame *tview.Frame
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()
func configureTview() {
headerBar := NewUIHeaderBar() headerBar := NewUIHeaderBar()
content := tview.NewGrid() content := tview.NewGrid()
...@@ -78,30 +38,28 @@ func run(plugin *node.Plugin) { ...@@ -78,30 +38,28 @@ func run(plugin *node.Plugin) {
AddItem(content, 1, 0, 1, 1, 0, 0, false). AddItem(content, 1, 0, 1, 1, 0, 0, false).
AddItem(footer, 2, 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) SetBorders(1, 1, 0, 0, 2, 2)
frame.SetBackgroundColor(tcell.ColorDarkGray) frame.SetBackgroundColor(tcell.ColorDarkGray)
app = tview.NewApplication()
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
// end the daemon on ctrl+c
if event.Key() == tcell.KeyCtrlC || event.Key() == tcell.KeyESC { if event.Key() == tcell.KeyCtrlC || event.Key() == tcell.KeyESC {
daemon.Shutdown() daemon.Shutdown()
return nil return nil
} }
return event return event
}) })
app.SetBeforeDrawFunc(func(screen tcell.Screen) bool { app.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
mutex.RLock()
defer mutex.RUnlock()
headerBar.Update() headerBar.Update()
rows := make([]int, 2) rows := make([]int, 2)
rows[0] = 1 rows[0] = 1
rows[1] = 1 rows[1] = 1
_, _, _, height := content.GetRect() _, _, _, 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) rows = append(rows, 1)
} }
...@@ -112,12 +70,12 @@ func run(plugin *node.Plugin) { ...@@ -112,12 +70,12 @@ func run(plugin *node.Plugin) {
blankLine.SetBackgroundColor(tcell.ColorWhite) blankLine.SetBackgroundColor(tcell.ColorWhite)
content.AddItem(blankLine, 0, 0, 1, 1, 0, 0, false) 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 { if logStart < 0 {
logStart = 0 logStart = 0
} }
for i, message := range messageLog[logStart:] { for i, message := range logMessages[logStart:] {
if i < height-2 { if i < height-2 {
content.AddItem(NewUILogEntry(*message).Primitive, i+1, 0, 1, 1, 0, 0, false) content.AddItem(NewUILogEntry(*message).Primitive, i+1, 0, 1, 1, 0, 0, false)
} }
...@@ -129,23 +87,15 @@ func run(plugin *node.Plugin) { ...@@ -129,23 +87,15 @@ func run(plugin *node.Plugin) {
return false return false
}) })
}
daemon.BackgroundWorker("Statusscreen Refresher", func(shutdownSignal <-chan struct{}) { func newPrimitive(text string) *tview.TextView {
for { textView := tview.NewTextView()
select { textView.SetTextAlign(tview.AlignLeft).SetText(" " + text)
case <-shutdownSignal:
return
case <-time.After(1 * time.Second):
app.QueueUpdateDraw(func() {})
}
}
})
daemon.BackgroundWorker("Statusscreen App", func(shutdownSignal <-chan struct{}) { return textView
if err := app.SetRoot(frame, true).SetFocus(frame).Run(); err != nil {
panic(err)
}
})
} }
var PLUGIN = node.NewPlugin("Status Screen", node.Enabled, configure, run) func isTerminal() bool {
return terminal.IsTerminal(int(os.Stdin.Fd()))
}
package statusscreen
import "github.com/rivo/tview"
type UILog struct {
Primitive *tview.Grid
}
func NewUILog() *UILog {
uiLog := &UILog{
Primitive: tview.NewGrid(),
}
return uiLog
}
...@@ -15,7 +15,7 @@ type UILogEntry struct { ...@@ -15,7 +15,7 @@ type UILogEntry struct {
LogLevelContainer *tview.TextView LogLevelContainer *tview.TextView
} }
func NewUILogEntry(message StatusMessage) *UILogEntry { func NewUILogEntry(message logMessage) *UILogEntry {
logEntry := &UILogEntry{ logEntry := &UILogEntry{
Primitive: tview.NewGrid(), Primitive: tview.NewGrid(),
TimeContainer: tview.NewTextView(), TimeContainer: tview.NewTextView(),
...@@ -36,7 +36,7 @@ func NewUILogEntry(message StatusMessage) *UILogEntry { ...@@ -36,7 +36,7 @@ func NewUILogEntry(message StatusMessage) *UILogEntry {
logEntry.LogLevelContainer.SetDynamicColors(true) logEntry.LogLevelContainer.SetDynamicColors(true)
textColor := "black::d" textColor := "black::d"
switch message.LogLevel { switch message.level {
case logger.LevelInfo: case logger.LevelInfo:
fmt.Fprintf(logEntry.LogLevelContainer, " [black::d][ [blue::d]INFO [black::d]]") fmt.Fprintf(logEntry.LogLevelContainer, " [black::d][ [blue::d]INFO [black::d]]")
case logger.LevelWarn: case logger.LevelWarn:
...@@ -57,11 +57,11 @@ func NewUILogEntry(message StatusMessage) *UILogEntry { ...@@ -57,11 +57,11 @@ func NewUILogEntry(message StatusMessage) *UILogEntry {
textColor = "black::b" textColor = "black::b"
} }
fmt.Fprintf(logEntry.TimeContainer, " [black::b]"+message.Time.Format("15:04:05")) fmt.Fprintf(logEntry.TimeContainer, " [black::b]"+message.time.Format("15:04:05"))
if message.Source == "Node" { if message.name == "Node" {
fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.Message) fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.msg)
} else { } else {
fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.Source+": "+message.Message) fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.name+": "+message.msg)
} }
logEntry.Primitive. logEntry.Primitive.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment