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
No related branches found
No related tags found
No related merge requests found
......@@ -23,9 +23,8 @@
"DisableStacktrace":false,
"Encoding":"console",
"OutputPaths":[
"stdout"
],
"DisableEvents":false
"shimmer.log"
]
},
"node":{
"disableplugins":"",
......
package statusscreen
import "time"
const (
REPAINT_INTERVAL = 500 * time.Millisecond
)
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
}
}
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
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()))
}
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 {
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.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment