You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2019/12/02 17:26:12 UTC

[mynewt-newtmgr] branch master updated: log show: Specify `-a` to get entire log

This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newtmgr.git


The following commit(s) were added to refs/heads/master by this push:
     new 54fb24b  log show: Specify `-a` to get entire log
54fb24b is described below

commit 54fb24b9c274bbc2bce23c18753209945b186efb
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Nov 27 16:08:17 2019 -0800

    log show: Specify `-a` to get entire log
    
    Normally, the `newtmgr log show` command only receives one packet's
    worth of log entries.
    
    This commit adds a `-a` option to this command.  When this option is
    specified, newtmgr continues requesting more data until it reaches the
    end of the log.
    
    This is slightly better than using a script to read an entire log
    because newtmgr will reuse the established BLE connection for its
    subsequent requests, making the process faster.
---
 newtmgr/cli/log.go | 162 +++++++++++++++++++++++++++++++++++++++--------------
 nmxact/xact/log.go |  86 +++++++++++++++++++++++++++-
 2 files changed, 205 insertions(+), 43 deletions(-)

diff --git a/newtmgr/cli/log.go b/newtmgr/cli/log.go
index 350ccff..0774103 100644
--- a/newtmgr/cli/log.go
+++ b/newtmgr/cli/log.go
@@ -32,9 +32,12 @@ import (
 	"mynewt.apache.org/newtmgr/newtmgr/nmutil"
 	"mynewt.apache.org/newtmgr/nmxact/nmp"
 	"mynewt.apache.org/newtmgr/nmxact/nmxutil"
+	"mynewt.apache.org/newtmgr/nmxact/sesn"
 	"mynewt.apache.org/newtmgr/nmxact/xact"
 )
 
+var optLogShowFull bool
+
 // Converts the provided CBOR map to a JSON string.
 func logCborMsgText(cborMap []byte) (string, error) {
 	cm, err := nmxutil.DecodeCborMap(cborMap)
@@ -50,72 +53,75 @@ func logCborMsgText(cborMap []byte) (string, error) {
 	return string(msg), nil
 }
 
-func logShowCmd(cmd *cobra.Command, args []string) {
-	c := xact.NewLogShowCmd()
-	c.SetTxOptions(nmutil.TxOptions())
+type logShowCfg struct {
+	Name      string
+	Last      bool
+	Index     uint32
+	Timestamp int64
+}
 
-	if len(args) >= 1 {
-		c.Name = args[0]
-	}
-	if len(args) >= 2 {
-		if args[1] == "last" {
-			c.Index = 0
-			c.Timestamp = -1
-		} else {
-			u64, err := strconv.ParseUint(args[1], 0, 64)
-			if err != nil {
-				nmUsage(cmd, err)
-			}
-			if u64 > 0xffffffff {
-				nmUsage(cmd, util.NewNewtError("index out of range"))
-			}
-			c.Index = uint32(u64)
-		}
+func logShowParseArgs(args []string) (*logShowCfg, error) {
+	cfg := &logShowCfg{}
+
+	if len(args) < 1 {
+		return cfg, nil
 	}
-	if len(args) >= 3 && args[1] != "last" {
-		var err error
-		c.Timestamp, err = strconv.ParseInt(args[2], 0, 64)
+	cfg.Name = args[0]
+
+	if len(args) < 2 {
+		return cfg, nil
+	}
+
+	if args[1] == "last" {
+		cfg.Index = 0
+		cfg.Timestamp = -1
+	} else {
+		u64, err := strconv.ParseUint(args[1], 0, 64)
 		if err != nil {
-			nmUsage(cmd, err)
+			return nil, util.ChildNewtError(err)
+		}
+		if u64 > 0xffffffff {
+			return nil, util.NewNewtError("index out of range")
 		}
+		cfg.Index = uint32(u64)
 	}
 
-	s, err := GetSesn()
-	if err != nil {
-		nmUsage(nil, err)
+	if len(args) < 3 || args[1] == "last" {
+		return cfg, nil
 	}
 
-	res, err := c.Run(s)
+	ts, err := strconv.ParseInt(args[2], 0, 64)
 	if err != nil {
-		nmUsage(nil, util.ChildNewtError(err))
+		return nil, util.ChildNewtError(err)
 	}
+	cfg.Timestamp = ts
 
-	sres := res.(*xact.LogShowResult)
-	fmt.Printf("Status: %d\n", sres.Status())
-	fmt.Printf("Next index: %d\n", sres.Rsp.NextIndex)
-	if len(sres.Rsp.Logs) == 0 {
+	return cfg, nil
+}
+
+func printLogShowRsp(rsp *nmp.LogShowRsp, printHdr bool) {
+	if len(rsp.Logs) == 0 {
 		fmt.Printf("(no logs retrieved)\n")
 		return
 	}
 
-	for _, log := range sres.Rsp.Logs {
-		fmt.Printf("Name: %s\n", log.Name)
-		fmt.Printf("Type: %s\n", nmp.LogTypeToString(log.Type))
+	for _, log := range rsp.Logs {
+		if printHdr {
+			fmt.Printf("Name: %s\n", log.Name)
+			fmt.Printf("Type: %s\n", nmp.LogTypeToString(log.Type))
 
-		if len(log.Entries) == 0 {
-			fmt.Printf("(no log entries retrieved)\n")
-			return
+			fmt.Printf("%10s %22s | %16s %16s %6s %8s %s\n",
+				"[index]", "[timestamp]", "[module]", "[level]", "[type]",
+				"[img]", "[message]")
 		}
 
-		fmt.Printf("%10s %22s | %16s %16s %6s %8s %s\n",
-			"[index]", "[timestamp]", "[module]", "[level]", "[type]",
-			"[img]", "[message]")
 		for _, entry := range log.Entries {
 			modText := fmt.Sprintf("%s (%d)",
 				nmp.LogModuleToString(int(entry.Module)), entry.Module)
 			levText := fmt.Sprintf("%s (%d)",
 				nmp.LogLevelToString(int(entry.Level)), entry.Level)
 
+			var err error
 			msgText := ""
 			switch entry.Type {
 			case nmp.LOG_ENTRY_TYPE_STRING:
@@ -151,6 +157,77 @@ func logShowCmd(cmd *cobra.Command, args []string) {
 	}
 }
 
+func logShowFullCmd(s sesn.Sesn, cfg *logShowCfg) error {
+	if cfg.Name == "" {
+		return util.FmtNewtError("must specify a single log to read when `-a` is used")
+	}
+
+	c := xact.NewLogShowFullCmd()
+	c.SetTxOptions(nmutil.TxOptions())
+
+	c.Name = cfg.Name
+	c.Index = cfg.Index
+
+	first := true
+	c.ProgressCb = func(_ *xact.LogShowFullCmd, rsp *nmp.LogShowRsp) {
+		printLogShowRsp(rsp, first)
+		first = false
+	}
+
+	_, err := c.Run(s)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func logShowPartialCmd(s sesn.Sesn, cfg *logShowCfg) error {
+	c := xact.NewLogShowCmd()
+	c.SetTxOptions(nmutil.TxOptions())
+
+	c.Name = cfg.Name
+	c.Index = cfg.Index
+	c.Timestamp = cfg.Timestamp
+
+	res, err := c.Run(s)
+	if err != nil {
+		return err
+	}
+
+	sres := res.(*xact.LogShowResult)
+	fmt.Printf("Status: %d\n", sres.Status())
+	fmt.Printf("Next index: %d\n", sres.Rsp.NextIndex)
+	if len(sres.Rsp.Logs) == 0 {
+		fmt.Printf("(no logs retrieved)\n")
+	} else {
+		printLogShowRsp(sres.Rsp, true)
+	}
+
+	return nil
+}
+
+func logShowCmd(cmd *cobra.Command, args []string) {
+	cfg, err := logShowParseArgs(args)
+	if err != nil {
+		nmUsage(cmd, err)
+	}
+
+	s, err := GetSesn()
+	if err != nil {
+		nmUsage(nil, err)
+	}
+
+	if optLogShowFull {
+		err = logShowFullCmd(s, cfg)
+	} else {
+		err = logShowPartialCmd(s, cfg)
+	}
+	if err != nil {
+		nmUsage(nil, err)
+	}
+}
+
 func logListCmd(cmd *cobra.Command, args []string) {
 	s, err := GetSesn()
 	if err != nil {
@@ -296,6 +373,7 @@ func logCmd() *cobra.Command {
 		Short:   "Show the logs on a device",
 		Run:     logShowCmd,
 	}
+	showCmd.PersistentFlags().BoolVarP(&optLogShowFull, "all", "a", false, "read until end of log")
 	logCmd.AddCommand(showCmd)
 
 	clearCmd := &cobra.Command{
diff --git a/nmxact/xact/log.go b/nmxact/xact/log.go
index ca5dff3..b99a4b6 100644
--- a/nmxact/xact/log.go
+++ b/nmxact/xact/log.go
@@ -25,7 +25,7 @@ import (
 )
 
 //////////////////////////////////////////////////////////////////////////////
-// $read                                                                    //
+// $show                                                                    //
 //////////////////////////////////////////////////////////////////////////////
 
 type LogShowCmd struct {
@@ -71,6 +71,90 @@ func (c *LogShowCmd) Run(s sesn.Sesn) (Result, error) {
 }
 
 //////////////////////////////////////////////////////////////////////////////
+// $showfull                                                                //
+//////////////////////////////////////////////////////////////////////////////
+
+type LogShowFullProgressFn func(c *LogShowFullCmd, r *nmp.LogShowRsp)
+type LogShowFullCmd struct {
+	CmdBase
+	Name       string
+	Index      uint32
+	ProgressCb LogShowFullProgressFn
+}
+
+func NewLogShowFullCmd() *LogShowFullCmd {
+	return &LogShowFullCmd{
+		CmdBase: NewCmdBase(),
+	}
+}
+
+type LogShowFullResult struct {
+	Rsps []*nmp.LogShowRsp
+}
+
+func newLogShowFullResult() *LogShowFullResult {
+	return &LogShowFullResult{}
+}
+
+func (r *LogShowFullResult) Status() int {
+	if len(r.Rsps) > 0 {
+		return r.Rsps[len(r.Rsps)-1].Rc
+	} else {
+		return nmp.NMP_ERR_EUNKNOWN
+	}
+}
+
+func (c *LogShowFullCmd) buildReq(idx uint32) *nmp.LogShowReq {
+	r := nmp.NewLogShowReq()
+	r.Name = c.Name
+	r.Index = idx
+
+	return r
+}
+
+func (c *LogShowFullCmd) Run(s sesn.Sesn) (Result, error) {
+	res := newLogShowFullResult()
+
+	idx := c.Index
+	for {
+		r := c.buildReq(idx)
+
+		rsp, err := txReq(s, r.Msg(), &c.CmdBase)
+		if err != nil {
+			return nil, err
+		}
+		srsp := rsp.(*nmp.LogShowRsp)
+
+		if c.ProgressCb != nil {
+			c.ProgressCb(c, srsp)
+		}
+
+		res.Rsps = append(res.Rsps, srsp)
+
+		// A status code of 1 means there logs to read.  For historical
+		// reasons, 1 doesn't map to an appropriate error code, so just
+		// hardcode it here.
+		if srsp.Rc != 1 {
+			break
+		}
+
+		if len(srsp.Logs) == 0 {
+			break
+		}
+		lastLog := srsp.Logs[len(srsp.Logs)-1]
+
+		if len(lastLog.Entries) == 0 {
+			break
+		}
+		lastEntry := lastLog.Entries[len(lastLog.Entries)-1]
+
+		idx = lastEntry.Index + 1
+	}
+
+	return res, nil
+}
+
+//////////////////////////////////////////////////////////////////////////////
 // $list                                                                    //
 //////////////////////////////////////////////////////////////////////////////