Skip to content

Commit

Permalink
Merge pull request #213 from SiaFoundation/nate/log-to-stderr
Browse files Browse the repository at this point in the history
Log startup errors to stderr
  • Loading branch information
n8maninger authored Jan 9, 2025
2 parents f0819d5 + fdca6b2 commit 3a76ce2
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 64 deletions.
5 changes: 5 additions & 0 deletions .changeset/log_startup_errors_to_stderr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: minor
---

# Log startup errors to stderr
34 changes: 10 additions & 24 deletions cmd/walletd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"bufio"
"errors"
"fmt"
"net"
"os"
Expand All @@ -18,9 +19,7 @@ import (
func readPasswordInput(context string) string {
fmt.Printf("%s: ", context)
input, err := term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
fatalError(fmt.Errorf("could not read password input: %w", err))
}
checkFatalError("failed to read password input", err)
fmt.Println("")
return string(input)
}
Expand All @@ -29,9 +28,7 @@ func readInput(context string) string {
fmt.Printf("%s: ", context)
r := bufio.NewReader(os.Stdin)
input, err := r.ReadString('\n')
if err != nil {
fatalError(fmt.Errorf("could not read input: %w", err))
}
checkFatalError("failed to read input", err)
return strings.TrimSpace(input)
}

Expand Down Expand Up @@ -115,9 +112,7 @@ func setDataDirectory() {
}

dir, err := filepath.Abs(cfg.Directory)
if err != nil {
fatalError(fmt.Errorf("failed to get absolute path of data directory: %w", err))
}
checkFatalError("failed to get absolute path of data directory", err)

fmt.Println("The data directory is where walletd will store its metadata and consensus data.")
fmt.Println("This directory should be on a fast, reliable storage device, preferably an SSD.")
Expand Down Expand Up @@ -200,7 +195,7 @@ func setAdvancedConfig() {
case strings.EqualFold(mode, "full"):
cfg.Index.Mode = wallet.IndexModeFull
default:
fatalError(fmt.Errorf("invalid index mode: %q", mode))
checkFatalError("invalid index mode", errors.New("must be either 'personal' or 'full'"))
}

fmt.Println("")
Expand Down Expand Up @@ -236,21 +231,12 @@ func buildConfig() {

// write the config file
f, err := os.Create(configPath)
if err != nil {
fatalError(fmt.Errorf("failed to create config file: %w", err))
return
}
checkFatalError("failed to create config file", err)
defer f.Close()

enc := yaml.NewEncoder(f)
if err := enc.Encode(cfg); err != nil {
fatalError(fmt.Errorf("failed to encode config file: %w", err))
return
} else if err := f.Sync(); err != nil {
fatalError(fmt.Errorf("failed to sync config file: %w", err))
return
} else if err := f.Close(); err != nil {
fatalError(fmt.Errorf("failed to close config file: %w", err))
return
}
defer enc.Close()

checkFatalError("failed to encode config file", enc.Encode(cfg))
checkFatalError("failed to sync config file", f.Sync())
}
53 changes: 16 additions & 37 deletions cmd/walletd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
Expand Down Expand Up @@ -85,12 +84,6 @@ var cfg = config.Config{
},
}

func check(context string, err error) {
if err != nil {
log.Fatalf("%v: %v", context, err)
}
}

func mustSetAPIPassword() {
if cfg.HTTP.Password != "" {
return
Expand All @@ -111,8 +104,12 @@ func mustSetAPIPassword() {
}
}

func fatalError(err error) {
os.Stderr.WriteString(err.Error() + "\n")
// checkFatalError prints an error message to stderr and exits with a 1 exit code. If err is nil, this is a no-op.
func checkFatalError(context string, err error) {
if err == nil {
return
}
os.Stderr.WriteString(fmt.Sprintf("%s: %s\n", context, err))
os.Exit(1)
}

Expand All @@ -130,19 +127,13 @@ func tryLoadConfig() {
}

f, err := os.Open(configPath)
if err != nil {
fatalError(fmt.Errorf("failed to open config file: %w", err))
return
}
checkFatalError("failed to open config file", err)
defer f.Close()

dec := yaml.NewDecoder(f)
dec.KnownFields(true)

if err := dec.Decode(&cfg); err != nil {
fmt.Println("failed to decode config file:", err)
os.Exit(1)
}
checkFatalError("failed to decode config file", dec.Decode(&cfg))
}

// jsonEncoder returns a zapcore.Encoder that encodes logs as JSON intended for
Expand Down Expand Up @@ -243,12 +234,14 @@ func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, syscall.SIGKILL)
defer cancel()

if err := os.MkdirAll(cfg.Directory, 0700); err != nil {
fatalError(fmt.Errorf("failed to create data directory: %w", err))
if cfg.Directory != "" {
checkFatalError("failed to create data directory", os.MkdirAll(cfg.Directory, 0700))
}

mustSetAPIPassword()

checkFatalError("failed to parse index mode", cfg.Index.Mode.UnmarshalText([]byte(indexModeStr)))

var logCores []zapcore.Core
if cfg.Log.StdOut.Enabled {
// if no log level is set for stdout, use the global log level
Expand Down Expand Up @@ -290,10 +283,7 @@ func main() {
}

fileWriter, closeFn, err := zap.Open(cfg.Log.File.Path)
if err != nil {
fatalError(fmt.Errorf("failed to open log file: %w", err))
return
}
checkFatalError("failed to open log file", err)
defer closeFn()

// create the file logger
Expand All @@ -312,13 +302,7 @@ func main() {
// redirect stdlib log to zap
zap.RedirectStdLog(log.Named("stdlib"))

if err := cfg.Index.Mode.UnmarshalText([]byte(indexModeStr)); err != nil {
log.Fatal("failed to parse index mode", zap.Error(err))
}

if err := runNode(ctx, cfg, log, enableDebug); err != nil {
log.Fatal("failed to run node", zap.Error(err))
}
checkFatalError("failed to run node", runNode(ctx, cfg, log, enableDebug))
case versionCmd:
if len(cmd.Args()) != 0 {
cmd.Usage()
Expand All @@ -334,9 +318,7 @@ func main() {
}
recoveryPhrase := cwallet.NewSeedPhrase()
var seed [32]byte
if err := cwallet.SeedFromPhrase(&seed, recoveryPhrase); err != nil {
log.Fatal(err)
}
checkFatalError("failed to parse mnemonic phrase", cwallet.SeedFromPhrase(&seed, recoveryPhrase))
addr := types.StandardUnlockHash(cwallet.KeyFromSeed(&seed, 0).PublicKey())

fmt.Println("Recovery Phrase:", recoveryPhrase)
Expand All @@ -355,10 +337,7 @@ func main() {
}

minerAddr, err := types.ParseAddress(minerAddrStr)
if err != nil {
log.Fatal(err)
}

checkFatalError("failed to parse miner address", err)
mustSetAPIPassword()
c := api.NewClient("http://"+cfg.HTTP.Address+"/api", cfg.HTTP.Password)
runCPUMiner(c, minerAddr, minerBlocks)
Expand Down
6 changes: 3 additions & 3 deletions cmd/walletd/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ func runCPUMiner(c *api.Client, minerAddr types.Address, n int) {
}
elapsed := time.Since(start)
cs, err := c.ConsensusTipState()
check("Couldn't get consensus tip state:", err)
checkFatalError("failed to get consensus tip state:", err)
d, _ := new(big.Int).SetString(cs.Difficulty.String(), 10)
d.Mul(d, big.NewInt(int64(1+elapsed)))
fmt.Printf("\rMining block %4v...(%.2f blocks/day), difficulty %v)", cs.Index.Height+1, float64(blocksFound)*float64(24*time.Hour)/float64(elapsed), cs.Difficulty)

txns, v2txns, err := c.TxpoolTransactions()
check("Couldn't get txpool transactions:", err)
checkFatalError("failed to get pool transactions:", err)
b := types.Block{
ParentID: cs.Index.ID,
Nonce: cs.NonceFactor() * frand.Uint64n(100),
Expand All @@ -56,7 +56,7 @@ func runCPUMiner(c *api.Client, minerAddr types.Address, n int) {
blocksFound++
index := types.ChainIndex{Height: cs.Index.Height + 1, ID: b.ID()}
tip, err := c.ConsensusTip()
check("Couldn't get consensus tip:", err)
checkFatalError("failed to get consensus tip:", err)
if tip != cs.Index {
fmt.Printf("\nMined %v but tip changed, starting over\n", index)
} else if err := c.SyncerBroadcastBlock(b); err != nil {
Expand Down

0 comments on commit 3a76ce2

Please sign in to comment.