github.com/hernad/nomad@v1.6.112/command/operator_raft_logs.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package command
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"os"
    10  	"strings"
    11  
    12  	"github.com/hernad/nomad/helper/raftutil"
    13  	"github.com/posener/complete"
    14  )
    15  
    16  type OperatorRaftLogsCommand struct {
    17  	Meta
    18  }
    19  
    20  func (c *OperatorRaftLogsCommand) Help() string {
    21  	helpText := `
    22  Usage: nomad operator raft logs <path to nomad data dir>
    23  
    24    Display the log entries persisted in the Nomad data directory in JSON
    25    format.
    26  
    27    This command requires file system permissions to access the data directory on
    28    disk. The Nomad server locks access to the data directory, so this command
    29    cannot be run on a data directory that is being used by a running Nomad server.
    30  
    31    This is a low-level debugging tool and not subject to Nomad's usual backward
    32    compatibility guarantees.
    33  
    34  Raft Logs Options:
    35  
    36    -pretty
    37      By default this command outputs newline delimited JSON. If the -pretty flag
    38      is passed, each entry will be pretty-printed.
    39  `
    40  	return strings.TrimSpace(helpText)
    41  }
    42  
    43  func (c *OperatorRaftLogsCommand) AutocompleteFlags() complete.Flags {
    44  	return complete.Flags{}
    45  }
    46  
    47  func (c *OperatorRaftLogsCommand) AutocompleteArgs() complete.Predictor {
    48  	return complete.PredictNothing
    49  }
    50  
    51  func (c *OperatorRaftLogsCommand) Synopsis() string {
    52  	return "Display raft log content"
    53  }
    54  
    55  func (c *OperatorRaftLogsCommand) Name() string { return "operator raft logs" }
    56  
    57  func (c *OperatorRaftLogsCommand) Run(args []string) int {
    58  
    59  	var pretty bool
    60  	flagSet := c.Meta.FlagSet(c.Name(), FlagSetClient)
    61  	flagSet.Usage = func() { c.Ui.Output(c.Help()) }
    62  	flagSet.BoolVar(&pretty, "pretty", false, "")
    63  
    64  	if err := flagSet.Parse(args); err != nil {
    65  		return 1
    66  	}
    67  
    68  	args = flagSet.Args()
    69  	if l := len(args); l != 1 {
    70  		c.Ui.Error("This command takes one argument: <path>")
    71  		c.Ui.Error(commandErrorText(c))
    72  		return 1
    73  	}
    74  
    75  	raftPath, err := raftutil.FindRaftFile(args[0])
    76  	if err != nil {
    77  		c.Ui.Error(err.Error())
    78  		return 1
    79  	}
    80  
    81  	enc := json.NewEncoder(os.Stdout)
    82  	if pretty {
    83  		enc.SetIndent("", "  ")
    84  	}
    85  
    86  	logChan, warningsChan, err := raftutil.LogEntries(raftPath)
    87  	if err != nil {
    88  		c.Ui.Error(err.Error())
    89  		return 1
    90  	}
    91  
    92  	// so that the warnings don't end up mixed into the JSON stream,
    93  	// collect them and print them once we're done
    94  	warnings := []error{}
    95  
    96  DONE:
    97  	for {
    98  		select {
    99  		case log := <-logChan:
   100  			if log == nil {
   101  				break DONE // no more logs, but break to print warnings
   102  			}
   103  			if err := enc.Encode(log); err != nil {
   104  				c.Ui.Error(fmt.Sprintf("failed to encode output: %v", err))
   105  				return 1
   106  			}
   107  		case warning := <-warningsChan:
   108  			warnings = append(warnings, warning)
   109  		}
   110  	}
   111  
   112  	for _, warning := range warnings {
   113  		c.Ui.Error(warning.Error())
   114  	}
   115  
   116  	return 0
   117  }