github.com/therealbill/libredis@v0.0.0-20161227004305-7d50abda5ccf/info/methods.go (about)

     1  package info
     2  
     3  import (
     4  	"reflect"
     5  	"strconv"
     6  	"strings"
     7  	"unicode"
     8  	"unicode/utf8"
     9  
    10  	"github.com/therealbill/libredis/structures"
    11  )
    12  
    13  // BuildAllInfoMap will call `INFO ALL` and return a mapping of map[string]string for each section in the output
    14  func BuildAllInfoMap(infostring string) map[string]map[string]string {
    15  	lines := strings.Split(infostring, "\r\n")
    16  	allmap := make(map[string]map[string]string)
    17  	var sectionname string
    18  	for _, line := range lines {
    19  		if len(line) > 0 {
    20  			if strings.Contains(line, "# ") {
    21  				sectionname = strings.Split(line, "# ")[1]
    22  				allmap[sectionname] = make(map[string]string)
    23  			} else {
    24  				splits := strings.Split(line, ":")
    25  				key := splits[0]
    26  				val := splits[1]
    27  				secmap := allmap[sectionname]
    28  				if secmap == nil {
    29  					allmap[sectionname] = make(map[string]string)
    30  				}
    31  				allmap[sectionname][key] = val
    32  			}
    33  		}
    34  	}
    35  	return allmap
    36  }
    37  
    38  // BuildMapFromInfoString will take the string from a Redis info call and
    39  // return a map[string]string
    40  func BuildMapFromInfoString(input string) map[string]string {
    41  	imap := make(map[string]string)
    42  	lines := strings.Split(input, "\r\n")
    43  	for _, line := range lines {
    44  		if len(line) > 0 {
    45  			if strings.Contains(line, "#") {
    46  				imap["section"] = strings.Split(line, "#")[1]
    47  			} else {
    48  				splits := strings.Split(line, ":")
    49  				key := splits[0]
    50  				val := splits[1]
    51  				imap[key] = val
    52  			}
    53  		}
    54  	}
    55  	return imap
    56  }
    57  
    58  // BuildInfoKeyspace builds out the InfoKeyspace struct
    59  func BuildInfoKeyspace(raw string) structures.InfoKeyspace {
    60  	var keyspace structures.InfoKeyspace
    61  	lines := strings.Split(raw, "\r\n")
    62  	section := ""
    63  	for _, line := range lines {
    64  		if len(line) > 0 {
    65  			if strings.Contains(line, "#") {
    66  				section = strings.Split(line, "# ")[1]
    67  			} else {
    68  				if section == "Keyspace" {
    69  					record := strings.Split(line, ":")
    70  					db := record[0][2:]
    71  					data := record[1]
    72  					splits := strings.Split(data, ",")
    73  					imap := make(map[string]int64)
    74  					dbIndex, _ := strconv.ParseInt(db, 10, 32)
    75  					imap["db"] = dbIndex
    76  					for _, entry := range splits {
    77  						keyvals := strings.Split(entry, "=")
    78  						key := keyvals[0]
    79  						val, _ := strconv.ParseInt(keyvals[1], 10, 32)
    80  						imap[key] = val
    81  					}
    82  					keyspace.Databases = append(keyspace.Databases, imap)
    83  				}
    84  			}
    85  		} else {
    86  			section = ""
    87  		}
    88  	}
    89  	return keyspace
    90  }
    91  
    92  // CommandStats returns the InfoCommandStats struct
    93  func CommandStats(commandstatstring string) (cmdstat structures.InfoCommandStats) {
    94  	lines := strings.Split(commandstatstring, "\r\n")
    95  	section := ""
    96  	for _, line := range lines {
    97  		if len(line) > 0 {
    98  			if strings.Contains(line, "# Commandstats") {
    99  				cmdstat.Stats = make(map[string]map[string]float64)
   100  				section = "Commandstats"
   101  			} else {
   102  				if section == "Commandstats" {
   103  					record := strings.Split(line, ":")
   104  					command := strings.Split(record[0], "_")[1]
   105  					data := record[1]
   106  					imap := make(map[string]float64)
   107  					splits := strings.Split(data, ",")
   108  					for _, entry := range splits {
   109  						keyvals := strings.Split(entry, "=")
   110  						key := keyvals[0]
   111  						val, _ := strconv.ParseFloat(keyvals[1], 64)
   112  						imap[key] = val
   113  					}
   114  					cmdstat.Stats[command] = imap
   115  				}
   116  			}
   117  		} else {
   118  			section = ""
   119  		}
   120  	}
   121  	return
   122  }
   123  
   124  // KeyspaceStats returns an InfoKeyspace struct for accessing keyspace stats
   125  func KeyspaceStats(infostring string) (stats structures.InfoKeyspace) {
   126  	trimmed := strings.TrimSpace(infostring)
   127  	stats = BuildInfoKeyspace(trimmed)
   128  	return
   129  }
   130  
   131  // GetAllInfo retuns a RedisInfoAll struct. This scturb has as it's members a
   132  // strict for each INFO section. Since the cost difference of running INFO all
   133  // and INFO <section> is negligible it mkes sens to just return it all and let
   134  // the user select what info they want out of it.
   135  func GetAllInfo(infostring string) (info structures.RedisInfoAll) {
   136  	allmap := BuildAllInfoMap(infostring)
   137  	var alldata structures.RedisInfoAll
   138  	all := reflect.ValueOf(&alldata).Elem()
   139  	for i := 0; i < all.NumField(); i++ {
   140  		p := all.Type().Field(i)
   141  		section := all.FieldByName(p.Name)
   142  		typeOfT := section.Type()
   143  		info := allmap[p.Name]
   144  		s := section
   145  		switch p.Name {
   146  		case "Keyspace":
   147  			alldata.Keyspace = KeyspaceStats(infostring)
   148  		case "Commandstats":
   149  			alldata.Commandstats = CommandStats(infostring)
   150  		default:
   151  			for i := 0; i < s.NumField(); i++ {
   152  				p := typeOfT.Field(i)
   153  				f := s.Field(i)
   154  				tag := p.Tag.Get("redis")
   155  				if p.Name == "Slaves" && tag == "slave*" {
   156  					for k, v := range info {
   157  						if strings.Contains(k, "slave") && strings.Contains(v, "ip=") {
   158  							idstring := strings.TrimLeft(k, "slave")
   159  							_, err := strconv.Atoi(string(idstring))
   160  							if err == nil {
   161  								var slave structures.InfoSlaves
   162  								pairs := strings.Split(v, ",")
   163  								for _, pstring := range pairs {
   164  									pdata := strings.Split(pstring, "=")
   165  									switch pdata[0] {
   166  									case "ip":
   167  										slave.IP = pdata[1]
   168  									case "port":
   169  										port, _ := strconv.Atoi(pdata[1])
   170  										slave.Port = port
   171  									case "state":
   172  										slave.State = pdata[1]
   173  									case "offset":
   174  										num, _ := strconv.Atoi(pdata[1])
   175  										slave.Offset = num
   176  									case "lag":
   177  										num, _ := strconv.Atoi(pdata[1])
   178  										slave.Lag = num
   179  									}
   180  								}
   181  								alldata.Replication.Slaves = append(alldata.Replication.Slaves, slave)
   182  							}
   183  						}
   184  					}
   185  				}
   186  				if len(info[tag]) != 0 {
   187  					if f.Type().Name() == "int" {
   188  						val, err := strconv.ParseInt(info[tag], 10, 64)
   189  						if err == nil {
   190  							f.SetInt(val)
   191  						}
   192  					}
   193  					if f.Type().Name() == "float64" {
   194  						val, err := strconv.ParseFloat(info[tag], 64)
   195  						if err == nil {
   196  							f.SetFloat(val)
   197  						}
   198  					}
   199  					if f.Type().Name() == "string" {
   200  						f.SetString(info[tag])
   201  					}
   202  					if f.Type().Name() == "bool" {
   203  						val, err := strconv.ParseInt(info[tag], 10, 64)
   204  						if err == nil && val != 0 {
   205  							f.SetBool(true)
   206  						}
   207  					}
   208  				}
   209  			}
   210  		}
   211  	}
   212  	return alldata
   213  
   214  }
   215  
   216  func upperFirst(s string) string {
   217  	if s == "" {
   218  		return ""
   219  	}
   220  	r, n := utf8.DecodeRuneInString(s)
   221  	return string(unicode.ToUpper(r)) + s[n:]
   222  }