github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/cmd/puppeth/wizard_netstats.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:33</date>
    10  //</624450070065975296>
    11  
    12  
    13  package main
    14  
    15  import (
    16  	"encoding/json"
    17  	"os"
    18  	"sort"
    19  	"strings"
    20  	"sync"
    21  
    22  	"github.com/ethereum/go-ethereum/core"
    23  	"github.com/ethereum/go-ethereum/log"
    24  	"github.com/olekukonko/tablewriter"
    25  )
    26  
    27  //
    28  //配置集,用于向用户提供有关如何执行各种任务的提示。
    29  func (w *wizard) networkStats() {
    30  	if len(w.servers) == 0 {
    31  		log.Info("No remote machines to gather stats from")
    32  		return
    33  	}
    34  //清除一些以前的配置以从当前扫描中重新填充
    35  	w.conf.ethstats = ""
    36  	w.conf.bootnodes = w.conf.bootnodes[:0]
    37  
    38  //遍历所有指定主机并检查其状态
    39  	var pend sync.WaitGroup
    40  
    41  	stats := make(serverStats)
    42  	for server, pubkey := range w.conf.Servers {
    43  		pend.Add(1)
    44  
    45  //同时收集每个服务器的服务状态
    46  		go func(server string, pubkey []byte) {
    47  			defer pend.Done()
    48  
    49  			stat := w.gatherStats(server, pubkey, w.servers[server])
    50  
    51  //所有状态检查完成,报告并检查下一个服务器
    52  			w.lock.Lock()
    53  			defer w.lock.Unlock()
    54  
    55  			delete(w.services, server)
    56  			for service := range stat.services {
    57  				w.services[server] = append(w.services[server], service)
    58  			}
    59  			stats[server] = stat
    60  		}(server, pubkey)
    61  	}
    62  	pend.Wait()
    63  
    64  //打印所有收集的统计数据并返回
    65  	stats.render()
    66  }
    67  
    68  //GatherStats收集特定远程服务器的服务统计信息。
    69  func (w *wizard) gatherStats(server string, pubkey []byte, client *sshClient) *serverStat {
    70  //收集一些全局统计信息以提供给向导
    71  	var (
    72  		genesis   string
    73  		ethstats  string
    74  		bootnodes []string
    75  	)
    76  //确保到远程服务器的ssh连接有效
    77  	logger := log.New("server", server)
    78  	logger.Info("Starting remote server health-check")
    79  
    80  	stat := &serverStat{
    81  		services: make(map[string]map[string]string),
    82  	}
    83  	if client == nil {
    84  		conn, err := dial(server, pubkey)
    85  		if err != nil {
    86  			logger.Error("Failed to establish remote connection", "err", err)
    87  			stat.failure = err.Error()
    88  			return stat
    89  		}
    90  		client = conn
    91  	}
    92  	stat.address = client.address
    93  
    94  //客户端以某种方式连接,运行运行运行状况检查
    95  	logger.Debug("Checking for nginx availability")
    96  	if infos, err := checkNginx(client, w.network); err != nil {
    97  		if err != ErrServiceUnknown {
    98  			stat.services["nginx"] = map[string]string{"offline": err.Error()}
    99  		}
   100  	} else {
   101  		stat.services["nginx"] = infos.Report()
   102  	}
   103  	logger.Debug("Checking for ethstats availability")
   104  	if infos, err := checkEthstats(client, w.network); err != nil {
   105  		if err != ErrServiceUnknown {
   106  			stat.services["ethstats"] = map[string]string{"offline": err.Error()}
   107  		}
   108  	} else {
   109  		stat.services["ethstats"] = infos.Report()
   110  		ethstats = infos.config
   111  	}
   112  	logger.Debug("Checking for bootnode availability")
   113  	if infos, err := checkNode(client, w.network, true); err != nil {
   114  		if err != ErrServiceUnknown {
   115  			stat.services["bootnode"] = map[string]string{"offline": err.Error()}
   116  		}
   117  	} else {
   118  		stat.services["bootnode"] = infos.Report()
   119  
   120  		genesis = string(infos.genesis)
   121  		bootnodes = append(bootnodes, infos.enode)
   122  	}
   123  	logger.Debug("Checking for sealnode availability")
   124  	if infos, err := checkNode(client, w.network, false); err != nil {
   125  		if err != ErrServiceUnknown {
   126  			stat.services["sealnode"] = map[string]string{"offline": err.Error()}
   127  		}
   128  	} else {
   129  		stat.services["sealnode"] = infos.Report()
   130  		genesis = string(infos.genesis)
   131  	}
   132  	logger.Debug("Checking for explorer availability")
   133  	if infos, err := checkExplorer(client, w.network); err != nil {
   134  		if err != ErrServiceUnknown {
   135  			stat.services["explorer"] = map[string]string{"offline": err.Error()}
   136  		}
   137  	} else {
   138  		stat.services["explorer"] = infos.Report()
   139  	}
   140  	logger.Debug("Checking for wallet availability")
   141  	if infos, err := checkWallet(client, w.network); err != nil {
   142  		if err != ErrServiceUnknown {
   143  			stat.services["wallet"] = map[string]string{"offline": err.Error()}
   144  		}
   145  	} else {
   146  		stat.services["wallet"] = infos.Report()
   147  	}
   148  	logger.Debug("Checking for faucet availability")
   149  	if infos, err := checkFaucet(client, w.network); err != nil {
   150  		if err != ErrServiceUnknown {
   151  			stat.services["faucet"] = map[string]string{"offline": err.Error()}
   152  		}
   153  	} else {
   154  		stat.services["faucet"] = infos.Report()
   155  	}
   156  	logger.Debug("Checking for dashboard availability")
   157  	if infos, err := checkDashboard(client, w.network); err != nil {
   158  		if err != ErrServiceUnknown {
   159  			stat.services["dashboard"] = map[string]string{"offline": err.Error()}
   160  		}
   161  	} else {
   162  		stat.services["dashboard"] = infos.Report()
   163  	}
   164  //
   165  	w.lock.Lock()
   166  	defer w.lock.Unlock()
   167  
   168  	if genesis != "" && w.conf.Genesis == nil {
   169  		g := new(core.Genesis)
   170  		if err := json.Unmarshal([]byte(genesis), g); err != nil {
   171  			log.Error("Failed to parse remote genesis", "err", err)
   172  		} else {
   173  			w.conf.Genesis = g
   174  		}
   175  	}
   176  	if ethstats != "" {
   177  		w.conf.ethstats = ethstats
   178  	}
   179  	w.conf.bootnodes = append(w.conf.bootnodes, bootnodes...)
   180  
   181  	return stat
   182  }
   183  
   184  //serverstat是服务配置参数和运行状况的集合
   185  //检查要打印给用户的报告。
   186  type serverStat struct {
   187  	address  string
   188  	failure  string
   189  	services map[string]map[string]string
   190  }
   191  
   192  //ServerStats是多个主机的服务器状态集合。
   193  type serverStats map[string]*serverStat
   194  
   195  //
   196  //并打印到标准输出。
   197  func (stats serverStats) render() {
   198  //开始收集服务统计信息和配置参数
   199  	table := tablewriter.NewWriter(os.Stdout)
   200  
   201  	table.SetHeader([]string{"Server", "Address", "Service", "Config", "Value"})
   202  	table.SetAlignment(tablewriter.ALIGN_LEFT)
   203  	table.SetColWidth(40)
   204  
   205  //查找黑客分隔符的所有列的最长行
   206  	separator := make([]string, 5)
   207  	for server, stat := range stats {
   208  		if len(server) > len(separator[0]) {
   209  			separator[0] = strings.Repeat("-", len(server))
   210  		}
   211  		if len(stat.address) > len(separator[1]) {
   212  			separator[1] = strings.Repeat("-", len(stat.address))
   213  		}
   214  		if len(stat.failure) > len(separator[1]) {
   215  			separator[1] = strings.Repeat("-", len(stat.failure))
   216  		}
   217  		for service, configs := range stat.services {
   218  			if len(service) > len(separator[2]) {
   219  				separator[2] = strings.Repeat("-", len(service))
   220  			}
   221  			for config, value := range configs {
   222  				if len(config) > len(separator[3]) {
   223  					separator[3] = strings.Repeat("-", len(config))
   224  				}
   225  				for _, val := range strings.Split(value, "\n") {
   226  					if len(val) > len(separator[4]) {
   227  						separator[4] = strings.Repeat("-", len(val))
   228  					}
   229  				}
   230  			}
   231  		}
   232  	}
   233  //按字母顺序填写服务器报告
   234  	servers := make([]string, 0, len(stats))
   235  	for server := range stats {
   236  		servers = append(servers, server)
   237  	}
   238  	sort.Strings(servers)
   239  
   240  	for i, server := range servers {
   241  //在所有服务器之间添加分隔符
   242  		if i > 0 {
   243  			table.Append(separator)
   244  		}
   245  //按字母顺序填写服务报告
   246  		services := make([]string, 0, len(stats[server].services))
   247  		for service := range stats[server].services {
   248  			services = append(services, service)
   249  		}
   250  		sort.Strings(services)
   251  
   252  		if len(services) == 0 {
   253  			if stats[server].failure != "" {
   254  				table.Append([]string{server, stats[server].failure, "", "", ""})
   255  			} else {
   256  				table.Append([]string{server, stats[server].address, "", "", ""})
   257  			}
   258  		}
   259  		for j, service := range services {
   260  //在所有服务之间添加空行
   261  			if j > 0 {
   262  				table.Append([]string{"", "", "", separator[3], separator[4]})
   263  			}
   264  //按字母顺序填写配置报告
   265  			configs := make([]string, 0, len(stats[server].services[service]))
   266  			for service := range stats[server].services[service] {
   267  				configs = append(configs, service)
   268  			}
   269  			sort.Strings(configs)
   270  
   271  			for k, config := range configs {
   272  				for l, value := range strings.Split(stats[server].services[service][config], "\n") {
   273  					switch {
   274  					case j == 0 && k == 0 && l == 0:
   275  						table.Append([]string{server, stats[server].address, service, config, value})
   276  					case k == 0 && l == 0:
   277  						table.Append([]string{"", "", service, config, value})
   278  					case l == 0:
   279  						table.Append([]string{"", "", "", config, value})
   280  					default:
   281  						table.Append([]string{"", "", "", "", value})
   282  					}
   283  				}
   284  			}
   285  		}
   286  	}
   287  	table.Render()
   288  }
   289