Select Git revision
plugin.go 4.79 KiB
// Package remotelog is a plugin that enables log messages being sent via UDP to a central ELK stack for debugging.
// It is disabled by default and when enabled, additionally, logger.disableEvents=false in config.json needs to be set.
// The destination can be set via logger.remotelog.serverAddress.
// All events according to logger.level in config.json are sent.
package remotelog
import (
"os"
"path/filepath"
"runtime"
"sync"
"time"
"github.com/iotaledger/goshimmer/packages/shutdown"
"github.com/iotaledger/goshimmer/plugins/autopeering/local"
"github.com/iotaledger/goshimmer/plugins/banner"
"github.com/iotaledger/goshimmer/plugins/config"
"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/iotaledger/hive.go/workerpool"
flag "github.com/spf13/pflag"
"gopkg.in/src-d/go-git.v4"
)
const (
// CfgLoggerRemotelogServerAddress defines the config flag of the server address.
CfgLoggerRemotelogServerAddress = "logger.remotelog.serverAddress"
// CfgDisableEvents defines the config flag for disabling logger events.
CfgDisableEvents = "logger.disableEvents"
// PluginName is the name of the remote log plugin.
PluginName = "RemoteLog"
remoteLogType = "log"
)
var (
// plugin is the plugin instance of the remote plugin instance.
plugin *node.Plugin
pluginOnce sync.Once
log *logger.Logger
myID string
myGitHead string
myGitBranch string
workerPool *workerpool.WorkerPool
remoteLogger *RemoteLoggerConn
remoteLoggerOnce sync.Once
)
// Plugin gets the plugin instance.
func Plugin() *node.Plugin {
pluginOnce.Do(func() {
plugin = node.NewPlugin(PluginName, node.Disabled, configure, run)
})
return plugin
}
func init() {
flag.String(CfgLoggerRemotelogServerAddress, "remotelog.goshimmer.iota.cafe:5213", "RemoteLog server address")
}
func configure(plugin *node.Plugin) {
log = logger.NewLogger(PluginName)
if config.Node().GetBool(CfgDisableEvents) {
log.Fatalf("%s in config.json needs to be false so that events can be captured!", CfgDisableEvents)
return
}
// initialize remote logger connection
RemoteLogger()
if local.GetInstance() != nil {
myID = local.GetInstance().ID().String()
}
getGitInfo()
workerPool = workerpool.New(func(task workerpool.Task) {
sendLogMsg(task.Param(0).(logger.Level), task.Param(1).(string), task.Param(2).(string))
task.Return(nil)
}, workerpool.WorkerCount(runtime.GOMAXPROCS(0)), workerpool.QueueSize(1000))
}
func run(plugin *node.Plugin) {
logEvent := events.NewClosure(func(level logger.Level, name string, msg string) {
workerPool.TrySubmit(level, name, msg)
})
if err := daemon.BackgroundWorker(PluginName, func(shutdownSignal <-chan struct{}) {
logger.Events.AnyMsg.Attach(logEvent)
workerPool.Start()
<-shutdownSignal
log.Infof("Stopping %s ...", PluginName)
logger.Events.AnyMsg.Detach(logEvent)
workerPool.Stop()
log.Infof("Stopping %s ... done", PluginName)
}, shutdown.PriorityRemoteLog); err != nil {
log.Panicf("Failed to start as daemon: %s", err)
}
}
func sendLogMsg(level logger.Level, name string, msg string) {
m := logMessage{
banner.AppVersion,
myGitHead,
myGitBranch,
myID,
level.CapitalString(),
name,
msg,
time.Now(),
remoteLogType,
}
_ = RemoteLogger().Send(m)
}
func getGitInfo() {
r, err := git.PlainOpen(getGitDir())
if err != nil {
log.Debug("Could not open Git repo.")
return
}
// extract git branch and head
if h, err := r.Head(); err == nil {
myGitBranch = h.Name().String()
myGitHead = h.Hash().String()
}
}
func getGitDir() string {
var gitDir string
// this is valid when running an executable, when using "go run" this is a temp path
if ex, err := os.Executable(); err == nil {
temp := filepath.Join(filepath.Dir(ex), ".git")
if _, err := os.Stat(temp); err == nil {
gitDir = temp
}
}
// when running "go run" from the same directory
if gitDir == "" {
if wd, err := os.Getwd(); err == nil {
temp := filepath.Join(wd, ".git")
if _, err := os.Stat(temp); err == nil {
gitDir = temp
}
}
}
return gitDir
}
// RemoteLogger represents a connection to our remote log server.
func RemoteLogger() *RemoteLoggerConn {
remoteLoggerOnce.Do(func() {
r, err := newRemoteLoggerConn(config.Node().GetString(CfgLoggerRemotelogServerAddress))
if err != nil {
log.Fatal(err)
return
}
remoteLogger = r
})
return remoteLogger
}
type logMessage struct {
Version string `json:"version"`
GitHead string `json:"gitHead,omitempty"`
GitBranch string `json:"gitBranch,omitempty"`
NodeID string `json:"nodeId"`
Level string `json:"level"`
Name string `json:"name"`
Msg string `json:"msg"`
Timestamp time.Time `json:"timestamp"`
Type string `json:"type"`
}