code: func (info *nodeInfos) Report() map[string]string {
  	report := map[string]string{
  		"Data directory":           info.datadir,
  		"Listener port":            strconv.Itoa(info.port),
  		"Peer count (all total)":   strconv.Itoa(info.peersTotal),
  		"Peer count (light nodes)": strconv.Itoa(info.peersLight),
  		"Ethstats username":        info.ethstats,
  	}
  	if info.gasTarget > 0 {
  		// Miner or signer node
  		report["Gas price (minimum accepted)"] = fmt.Sprintf("%0.3f GWei", info.gasPrice)
  		report["Gas floor (baseline target)"] = fmt.Sprintf("%0.3f MGas", info.gasTarget)
  		report["Gas ceil  (target maximum)"] = fmt.Sprintf("%0.3f MGas", info.gasLimit)
  
  		if info.etherbase != "" {
  			// Ethash proof-of-work miner
  			report["Ethash directory"] = info.ethashdir
  			report["Miner account"] = info.etherbase
  		}
  		if info.keyJSON != "" {
  			// Clique proof-of-authority signer
  			var key struct {
  				Address string `json:"address"`
  			}
  			if err := json.Unmarshal([]byte(info.keyJSON), &key); err == nil {
  				report["Signer account"] = common.HexToAddress(key.Address).Hex()
  			} else {
  				log.Error("Failed to retrieve signer address", "err", err)
  			}
  		}
  	}
  	return report
  }
docs: // Report converts the typed struct into a plain string->string map, containing
  // most - but not all - fields for reporting to the user.