diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go index 7ef908814..0ed3deab3 100644 --- a/p2p/simulations/adapters/exec.go +++ b/p2p/simulations/adapters/exec.go @@ -184,7 +184,19 @@ func (n *ExecNode) Start(snapshots map[string][]byte) (err error) { if err != nil { return fmt.Errorf("error generating node config: %s", err) } - + // expose the admin namespace via websocket if it's not enabled + exposed := confCopy.Stack.WSExposeAll + if !exposed { + for _, api := range confCopy.Stack.WSModules { + if api == "admin" { + exposed = true + break + } + } + } + if !exposed { + confCopy.Stack.WSModules = append(confCopy.Stack.WSModules, "admin") + } // start the one-shot server that waits for startup information ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -362,13 +374,44 @@ type execNodeConfig struct { PeerAddrs map[string]string `json:"peer_addrs,omitempty"` } +func initLogging() { + // Initialize the logging by default first. + glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.LogfmtFormat())) + glogger.Verbosity(log.LvlInfo) + log.Root().SetHandler(glogger) + + confEnv := os.Getenv(envNodeConfig) + if confEnv == "" { + return + } + var conf execNodeConfig + if err := json.Unmarshal([]byte(confEnv), &conf); err != nil { + return + } + var writer = os.Stderr + if conf.Node.LogFile != "" { + logWriter, err := os.Create(conf.Node.LogFile) + if err != nil { + return + } + writer = logWriter + } + var verbosity = log.LvlInfo + if conf.Node.LogVerbosity <= log.LvlTrace && conf.Node.LogVerbosity >= log.LvlCrit { + verbosity = conf.Node.LogVerbosity + } + // Reinitialize the logger + glogger = log.NewGlogHandler(log.StreamHandler(writer, log.TerminalFormat(true))) + glogger.Verbosity(verbosity) + log.Root().SetHandler(glogger) +} + // execP2PNode starts a simulation node when the current binary is executed with // argv[0] being "p2p-node", reading the service / ID from argv[1] / argv[2] // and the node config from an environment variable. func execP2PNode() { - glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.LogfmtFormat())) - glogger.Verbosity(log.LvlInfo) - log.Root().SetHandler(glogger) + initLogging() + statusURL := os.Getenv(envStatusURL) if statusURL == "" { log.Crit("missing " + envStatusURL) @@ -380,7 +423,7 @@ func execP2PNode() { if stackErr != nil { status.Err = stackErr.Error() } else { - status.WSEndpoint = "ws://" + stack.WSEndpoint() + status.WSEndpoint = stack.WSEndpoint() status.NodeInfo = stack.Server().NodeInfo() } @@ -454,7 +497,6 @@ func startExecNodeStack() (*node.Node, error) { return nil, err } services[name] = service - stack.RegisterLifecycle(service) } // Add the snapshot API. diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go index b6af37008..1da464a10 100644 --- a/p2p/simulations/adapters/types.go +++ b/p2p/simulations/adapters/types.go @@ -120,6 +120,17 @@ type NodeConfig struct { Reachable func(id enode.ID) bool Port uint16 + + // LogFile is the log file name of the p2p node at runtime. + // + // The default value is empty so that the default log writer + // is the system standard output. + LogFile string + + // LogVerbosity is the log verbosity of the p2p node at runtime. + // + // The default verbosity is INFO. + LogVerbosity log.Lvl } // nodeConfigJSON is used to encode and decode NodeConfig as JSON by encoding @@ -128,10 +139,12 @@ type nodeConfigJSON struct { ID string `json:"id"` PrivateKey string `json:"private_key"` Name string `json:"name"` - Services []string `json:"services"` + Lifecycles []string `json:"lifecycles"` Properties []string `json:"properties"` EnableMsgEvents bool `json:"enable_msg_events"` Port uint16 `json:"port"` + LogFile string `json:"logfile"` + LogVerbosity int `json:"log_verbosity"` } // MarshalJSON implements the json.Marshaler interface by encoding the config @@ -140,10 +153,12 @@ func (n *NodeConfig) MarshalJSON() ([]byte, error) { confJSON := nodeConfigJSON{ ID: n.ID.String(), Name: n.Name, - Services: n.Lifecycles, + Lifecycles: n.Lifecycles, Properties: n.Properties, Port: n.Port, EnableMsgEvents: n.EnableMsgEvents, + LogFile: n.LogFile, + LogVerbosity: int(n.LogVerbosity), } if n.PrivateKey != nil { confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey)) @@ -178,10 +193,12 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) error { } n.Name = confJSON.Name - n.Lifecycles = confJSON.Services + n.Lifecycles = confJSON.Lifecycles n.Properties = confJSON.Properties n.Port = confJSON.Port n.EnableMsgEvents = confJSON.EnableMsgEvents + n.LogFile = confJSON.LogFile + n.LogVerbosity = log.Lvl(confJSON.LogVerbosity) return nil } @@ -211,6 +228,7 @@ func RandomNodeConfig() *NodeConfig { Name: fmt.Sprintf("node_%s", enodId.String()), Port: port, EnableMsgEvents: true, + LogVerbosity: log.LvlInfo, } }