github.com/adityamillind98/nomad@v0.11.8/command/agent_monitor.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"os/signal"
     8  	"strconv"
     9  	"strings"
    10  	"syscall"
    11  	"time"
    12  
    13  	"github.com/hashicorp/nomad/api"
    14  	"github.com/mitchellh/cli"
    15  )
    16  
    17  type MonitorCommand struct {
    18  	Meta
    19  }
    20  
    21  func (c *MonitorCommand) Help() string {
    22  	helpText := `
    23  Usage: nomad monitor [options]
    24  
    25  	Stream log messages of a nomad agent. The monitor command lets you
    26  	listen for log levels that may be filtered out of the Nomad agent. For
    27  	example your agent may only be logging at INFO level, but with the monitor
    28  	command you can set -log-level DEBUG
    29  
    30  General Options:
    31  
    32  	` + generalOptionsUsage() + `
    33  
    34  Monitor Specific Options:
    35  
    36    -log-level <level>
    37      Sets the log level to monitor (default: INFO)
    38  
    39    -node-id <node-id>
    40      Sets the specific node to monitor
    41  
    42    -server-id <server-id>
    43      Sets the specific server to monitor
    44  
    45    -json
    46      Sets log output to JSON format
    47    `
    48  	return strings.TrimSpace(helpText)
    49  }
    50  
    51  func (c *MonitorCommand) Synopsis() string {
    52  	return "Stream logs from a Nomad agent"
    53  }
    54  
    55  func (c *MonitorCommand) Name() string { return "monitor" }
    56  
    57  func (c *MonitorCommand) Run(args []string) int {
    58  	c.Ui = &cli.PrefixedUi{
    59  		OutputPrefix: "    ",
    60  		InfoPrefix:   "    ",
    61  		ErrorPrefix:  "==> ",
    62  		Ui:           c.Ui,
    63  	}
    64  
    65  	var logLevel string
    66  	var nodeID string
    67  	var serverID string
    68  	var logJSON bool
    69  
    70  	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
    71  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    72  	flags.StringVar(&logLevel, "log-level", "", "")
    73  	flags.StringVar(&nodeID, "node-id", "", "")
    74  	flags.StringVar(&serverID, "server-id", "", "")
    75  	flags.BoolVar(&logJSON, "json", false, "")
    76  
    77  	if err := flags.Parse(args); err != nil {
    78  		return 1
    79  	}
    80  
    81  	args = flags.Args()
    82  	if l := len(args); l != 0 {
    83  		c.Ui.Error("This command takes no arguments")
    84  		c.Ui.Error(commandErrorText(c))
    85  		return 1
    86  	}
    87  
    88  	client, err := c.Meta.Client()
    89  	if err != nil {
    90  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
    91  		c.Ui.Error(commandErrorText(c))
    92  		return 1
    93  	}
    94  
    95  	// Query the node info and lookup prefix
    96  	if len(nodeID) == 1 {
    97  		c.Ui.Error(fmt.Sprintf("Node identifier must contain at least two characters."))
    98  		return 1
    99  	}
   100  
   101  	if nodeID != "" {
   102  		nodeID = sanitizeUUIDPrefix(nodeID)
   103  		nodes, _, err := client.Nodes().PrefixList(nodeID)
   104  		if err != nil {
   105  			c.Ui.Error(fmt.Sprintf("Error querying node: %v", err))
   106  			return 1
   107  		}
   108  
   109  		if len(nodes) == 0 {
   110  			c.Ui.Error(fmt.Sprintf("No node(s) with prefix or id %q found", nodeID))
   111  			return 1
   112  		}
   113  
   114  		if len(nodes) > 1 {
   115  			out := formatNodeStubList(nodes, false)
   116  			c.Ui.Output(fmt.Sprintf("Prefix matched multiple nodes\n\n%s", out))
   117  			return 1
   118  		}
   119  		nodeID = nodes[0].ID
   120  	}
   121  
   122  	params := map[string]string{
   123  		"log_level": logLevel,
   124  		"node_id":   nodeID,
   125  		"server_id": serverID,
   126  		"log_json":  strconv.FormatBool(logJSON),
   127  	}
   128  
   129  	query := &api.QueryOptions{
   130  		Params: params,
   131  	}
   132  
   133  	eventDoneCh := make(chan struct{})
   134  	frames, errCh := client.Agent().Monitor(eventDoneCh, query)
   135  	select {
   136  	case err := <-errCh:
   137  		c.Ui.Error(fmt.Sprintf("Error starting monitor: %s", err))
   138  		c.Ui.Error(commandErrorText(c))
   139  		return 1
   140  	default:
   141  	}
   142  
   143  	// Create a reader
   144  	var r io.ReadCloser
   145  	frameReader := api.NewFrameReader(frames, errCh, eventDoneCh)
   146  	frameReader.SetUnblockTime(500 * time.Millisecond)
   147  	r = frameReader
   148  
   149  	defer r.Close()
   150  
   151  	signalCh := make(chan os.Signal, 1)
   152  	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
   153  
   154  	go func() {
   155  		<-signalCh
   156  		// End the streaming
   157  		r.Close()
   158  	}()
   159  
   160  	_, err = io.Copy(os.Stdout, r)
   161  	if err != nil {
   162  		c.Ui.Error(fmt.Sprintf("error monitoring logs: %s", err))
   163  		return 1
   164  	}
   165  
   166  	return 0
   167  }