github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/stat.go (about)

     1  package commands
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"time"
     9  
    10  	humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize"
    11  
    12  	cmds "github.com/ipfs/go-ipfs/commands"
    13  	metrics "github.com/ipfs/go-ipfs/metrics"
    14  	peer "github.com/ipfs/go-ipfs/p2p/peer"
    15  	protocol "github.com/ipfs/go-ipfs/p2p/protocol"
    16  	u "github.com/ipfs/go-ipfs/util"
    17  )
    18  
    19  var StatsCmd = &cmds.Command{
    20  	Helptext: cmds.HelpText{
    21  		Tagline:          "Query IPFS statistics",
    22  		ShortDescription: ``,
    23  	},
    24  
    25  	Subcommands: map[string]*cmds.Command{
    26  		"bw": statBwCmd,
    27  	},
    28  }
    29  
    30  var statBwCmd = &cmds.Command{
    31  	Helptext: cmds.HelpText{
    32  		Tagline:          "Print ipfs bandwidth information",
    33  		ShortDescription: ``,
    34  	},
    35  	Options: []cmds.Option{
    36  		cmds.StringOption("peer", "p", "specify a peer to print bandwidth for"),
    37  		cmds.StringOption("proto", "t", "specify a protocol to print bandwidth for"),
    38  		cmds.BoolOption("poll", "print bandwidth at an interval"),
    39  		cmds.StringOption("interval", "i", "time interval to wait between updating output"),
    40  	},
    41  
    42  	Run: func(req cmds.Request, res cmds.Response) {
    43  		nd, err := req.InvocContext().GetNode()
    44  		if err != nil {
    45  			res.SetError(err, cmds.ErrNormal)
    46  			return
    47  		}
    48  
    49  		// Must be online!
    50  		if !nd.OnlineMode() {
    51  			res.SetError(errNotOnline, cmds.ErrClient)
    52  			return
    53  		}
    54  
    55  		pstr, pfound, err := req.Option("peer").String()
    56  		if err != nil {
    57  			res.SetError(err, cmds.ErrNormal)
    58  			return
    59  		}
    60  
    61  		tstr, tfound, err := req.Option("proto").String()
    62  		if err != nil {
    63  			res.SetError(err, cmds.ErrNormal)
    64  			return
    65  		}
    66  		if pfound && tfound {
    67  			res.SetError(errors.New("please only specify peer OR protocol"), cmds.ErrClient)
    68  			return
    69  		}
    70  
    71  		var pid peer.ID
    72  		if pfound {
    73  			checkpid, err := peer.IDB58Decode(pstr)
    74  			if err != nil {
    75  				res.SetError(err, cmds.ErrNormal)
    76  				return
    77  			}
    78  			pid = checkpid
    79  		}
    80  
    81  		interval := time.Second
    82  		timeS, found, err := req.Option("interval").String()
    83  		if err != nil {
    84  			res.SetError(err, cmds.ErrNormal)
    85  			return
    86  		}
    87  		if found {
    88  			v, err := time.ParseDuration(timeS)
    89  			if err != nil {
    90  				res.SetError(err, cmds.ErrNormal)
    91  				return
    92  			}
    93  			interval = v
    94  		}
    95  
    96  		doPoll, _, err := req.Option("poll").Bool()
    97  		if err != nil {
    98  			res.SetError(err, cmds.ErrNormal)
    99  			return
   100  		}
   101  
   102  		out := make(chan interface{})
   103  		res.SetOutput((<-chan interface{})(out))
   104  
   105  		go func() {
   106  			defer close(out)
   107  			for {
   108  				if pfound {
   109  					stats := nd.Reporter.GetBandwidthForPeer(pid)
   110  					out <- &stats
   111  				} else if tfound {
   112  					protoId := protocol.ID(tstr)
   113  					stats := nd.Reporter.GetBandwidthForProtocol(protoId)
   114  					out <- &stats
   115  				} else {
   116  					totals := nd.Reporter.GetBandwidthTotals()
   117  					out <- &totals
   118  				}
   119  				if !doPoll {
   120  					return
   121  				}
   122  				select {
   123  				case <-time.After(interval):
   124  				case <-req.Context().Done():
   125  					return
   126  				}
   127  			}
   128  		}()
   129  	},
   130  	Type: metrics.Stats{},
   131  	Marshalers: cmds.MarshalerMap{
   132  		cmds.Text: func(res cmds.Response) (io.Reader, error) {
   133  			outCh, ok := res.Output().(<-chan interface{})
   134  			if !ok {
   135  				return nil, u.ErrCast()
   136  			}
   137  
   138  			polling, _, err := res.Request().Option("poll").Bool()
   139  			if err != nil {
   140  				return nil, err
   141  			}
   142  
   143  			first := true
   144  			marshal := func(v interface{}) (io.Reader, error) {
   145  				bs, ok := v.(*metrics.Stats)
   146  				if !ok {
   147  					return nil, u.ErrCast()
   148  				}
   149  				out := new(bytes.Buffer)
   150  				if !polling {
   151  					printStats(out, bs)
   152  				} else {
   153  					if first {
   154  						fmt.Fprintln(out, "Total Up\t Total Down\t Rate Up\t Rate Down")
   155  						first = false
   156  					}
   157  					fmt.Fprint(out, "\r")
   158  					fmt.Fprintf(out, "%s \t\t", humanize.Bytes(uint64(bs.TotalOut)))
   159  					fmt.Fprintf(out, " %s \t\t", humanize.Bytes(uint64(bs.TotalIn)))
   160  					fmt.Fprintf(out, " %s/s   \t", humanize.Bytes(uint64(bs.RateOut)))
   161  					fmt.Fprintf(out, " %s/s     ", humanize.Bytes(uint64(bs.RateIn)))
   162  				}
   163  				return out, nil
   164  
   165  			}
   166  
   167  			return &cmds.ChannelMarshaler{
   168  				Channel:   outCh,
   169  				Marshaler: marshal,
   170  				Res:       res,
   171  			}, nil
   172  		},
   173  	},
   174  }
   175  
   176  func printStats(out io.Writer, bs *metrics.Stats) {
   177  	fmt.Fprintln(out, "Bandwidth")
   178  	fmt.Fprintf(out, "TotalIn: %s\n", humanize.Bytes(uint64(bs.TotalIn)))
   179  	fmt.Fprintf(out, "TotalOut: %s\n", humanize.Bytes(uint64(bs.TotalOut)))
   180  	fmt.Fprintf(out, "RateIn: %s/s\n", humanize.Bytes(uint64(bs.RateIn)))
   181  	fmt.Fprintf(out, "RateOut: %s/s\n", humanize.Bytes(uint64(bs.RateOut)))
   182  }