func (m *Memcached) gatherServer( address string, unix bool, acc plugins.Accumulator, ) error { var conn net.Conn if unix { conn, err := net.DialTimeout("unix", address, defaultTimeout) if err != nil { return err } defer conn.Close() } else { _, _, err := net.SplitHostPort(address) if err != nil { address = address + ":11211" } conn, err = net.DialTimeout("tcp", address, defaultTimeout) if err != nil { return err } defer conn.Close() } // Extend connection conn.SetDeadline(time.Now().Add(defaultTimeout)) // Read and write buffer rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) // Send command if _, err := fmt.Fprint(rw, "stats\r\n"); err != nil { return err } if err := rw.Flush(); err != nil { return err } values, err := parseResponse(rw.Reader) if err != nil { return err } // Add server address as a tag tags := map[string]string{"server": address} // Process values for _, key := range sendMetrics { if value, ok := values[key]; ok { // Mostly it is the number if iValue, errParse := strconv.ParseInt(value, 10, 64); errParse != nil { acc.Add(key, value, tags) } else { acc.Add(key, iValue, tags) } } } return nil }
func gatherPoolStats(pool poolInfo, acc plugins.Accumulator) error { lines, err := internal.ReadLines(pool.ioFilename) if err != nil { return err } if len(lines) != 3 { return err } keys := strings.Fields(lines[1]) values := strings.Fields(lines[2]) keyCount := len(keys) if keyCount != len(values) { return fmt.Errorf("Key and value count don't match Keys:%v Values:%v", keys, values) } tag := map[string]string{"pool": pool.name} for i := 0; i < keyCount; i++ { value, err := strconv.ParseInt(values[i], 10, 64) if err != nil { return err } acc.Add(keys[i], value, tag) } return nil }
func (z *Zfs) Gather(acc plugins.Accumulator) error { kstatMetrics := z.KstatMetrics if len(kstatMetrics) == 0 { kstatMetrics = []string{"arcstats", "zfetchstats", "vdev_cache_stats"} } kstatPath := z.KstatPath if len(kstatPath) == 0 { kstatPath = "/proc/spl/kstat/zfs" } tags := getTags(kstatPath) for _, metric := range kstatMetrics { lines, err := internal.ReadLines(kstatPath + "/" + metric) if err != nil { return err } for i, line := range lines { if i == 0 || i == 1 { continue } if len(line) < 1 { continue } rawData := strings.Split(line, " ") key := metric + "_" + rawData[0] rawValue := rawData[len(rawData)-1] value, _ := strconv.ParseInt(rawValue, 10, 64) acc.Add(key, value, tags) } } return nil }
func (n *Mesos) gatherUrl(addr *url.URL, acc plugins.Accumulator) error { resp, err := client.Get(fmt.Sprintf("%s/metrics/snapshot", addr.String())) if err != nil { return fmt.Errorf("Unabale to make HTTP request %s: %v", addr.String(), err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("Unexpected HTTP status %s: %v", addr.String(), resp.Status) } body, err := ioutil.ReadAll(resp.Body) if err != nil { return err } metrics := map[string]interface{}{} if err := json.Unmarshal(body, &metrics); err != nil { return err } tags := getTags(addr) for k, v := range metrics { name := strings.Replace(k, "/", "_", -1) acc.Add(name, v.(float64), tags) } return nil }
// Process pool data in Twemproxy stats func (ti *TwemproxyInstance) processPool( acc plugins.Accumulator, tags map[string]string, prefix string, data map[string]interface{}, ) { serverTags := make(map[string]map[string]string) for key, value := range data { switch key { case "client_connections", "forward_error", "client_err", "server_ejects", "fragments", "client_eof": if val, ok := value.(float64); ok { acc.Add(prefix+key, val, tags) } default: if data, ok := value.(map[string]interface{}); ok { if _, ok := serverTags[key]; !ok { serverTags[key] = copyTags(tags) serverTags[key]["server"] = key } ti.processServer(acc, serverTags[key], prefix, data) } } } }
// Process Twemproxy server stats func (ti *TwemproxyInstance) processStat( acc plugins.Accumulator, tags map[string]string, data map[string]interface{}, ) { if source, ok := data["source"]; ok { if val, ok := source.(string); ok { tags["source"] = val } } metrics := []string{"total_connections", "curr_connections", "timestamp"} for _, m := range metrics { if value, ok := data[m]; ok { if val, ok := value.(float64); ok { acc.Add(m, val, tags) } } } for _, pool := range ti.Pools { if poolStat, ok := data[pool]; ok { if data, ok := poolStat.(map[string]interface{}); ok { poolTags := copyTags(tags) poolTags["pool"] = pool ti.processPool(acc, poolTags, pool+"_", data) } } } }
func (e *Engine) AddEngineStats(keys []string, acc plugins.Accumulator, tags map[string]string) { engine := reflect.ValueOf(e).Elem() for _, key := range keys { acc.Add( key, engine.FieldByName(engineStats[key]).Interface(), tags, ) } }
// Flattens the map generated from the JSON object and stores its float values using a // plugins.Accumulator. It ignores any non-float values. // Parameters: // acc: the Accumulator to use // prefix: What the name of the measurement name should be prefixed by. // tags: telegraf tags to func processResponse(acc plugins.Accumulator, prefix string, tags map[string]string, v interface{}) { switch t := v.(type) { case map[string]interface{}: for k, v := range t { processResponse(acc, prefix+"_"+k, tags, v) } case float64: acc.Add(prefix, v, tags) } }
func (s *SystemStats) Gather(acc plugins.Accumulator) error { lv, err := s.ps.LoadAvg() if err != nil { return err } acc.Add("load1", lv.Load1, nil) acc.Add("load5", lv.Load5, nil) acc.Add("load15", lv.Load15, nil) return nil }
// Import HTTP stat data into Telegraf system func importMetric(r io.Reader, acc plugins.Accumulator, host string) (poolStat, error) { stats := make(poolStat) var currentPool string scanner := bufio.NewScanner(r) for scanner.Scan() { statLine := scanner.Text() keyvalue := strings.Split(statLine, ":") if len(keyvalue) < 2 { continue } fieldName := strings.Trim(keyvalue[0], " ") // We start to gather data for a new pool here if fieldName == PF_POOL { currentPool = strings.Trim(keyvalue[1], " ") stats[currentPool] = make(metric) continue } // Start to parse metric for current pool switch fieldName { case PF_ACCEPTED_CONN, PF_LISTEN_QUEUE, PF_MAX_LISTEN_QUEUE, PF_LISTEN_QUEUE_LEN, PF_IDLE_PROCESSES, PF_ACTIVE_PROCESSES, PF_TOTAL_PROCESSES, PF_MAX_ACTIVE_PROCESSES, PF_MAX_CHILDREN_REACHED, PF_SLOW_REQUESTS: fieldValue, err := strconv.ParseInt(strings.Trim(keyvalue[1], " "), 10, 64) if err == nil { stats[currentPool][fieldName] = fieldValue } } } // Finally, we push the pool metric for pool := range stats { tags := map[string]string{ "url": host, "pool": pool, } for k, v := range stats[pool] { acc.Add(strings.Replace(k, " ", "_", -1), v, tags) } } return stats, nil }
func (s *NetIOStats) Gather(acc plugins.Accumulator) error { netio, err := s.ps.NetIO() if err != nil { return fmt.Errorf("error getting net io info: %s", err) } for _, io := range netio { if len(s.Interfaces) != 0 { var found bool for _, name := range s.Interfaces { if name == io.Name { found = true break } } if !found { continue } } else if !s.skipChecks { iface, err := net.InterfaceByName(io.Name) if err != nil { continue } if iface.Flags&net.FlagLoopback == net.FlagLoopback { continue } if iface.Flags&net.FlagUp == 0 { continue } } tags := map[string]string{ "interface": io.Name, } acc.Add("bytes_sent", io.BytesSent, tags) acc.Add("bytes_recv", io.BytesRecv, tags) acc.Add("packets_sent", io.PacketsSent, tags) acc.Add("packets_recv", io.PacketsRecv, tags) acc.Add("err_in", io.Errin, tags) acc.Add("err_out", io.Errout, tags) acc.Add("drop_in", io.Dropin, tags) acc.Add("drop_out", io.Dropout, tags) } return nil }
func (l *Lustre2) GetLustreProcStats(fileglob string, wanted_fields []*mapping, acc plugins.Accumulator) error { files, err := filepath.Glob(fileglob) if err != nil { return err } for _, file := range files { /* Turn /proc/fs/lustre/obdfilter/<ost_name>/stats and similar * into just the object store target name * Assumpion: the target name is always second to last, * which is true in Lustre 2.1->2.5 */ path := strings.Split(file, "/") name := path[len(path)-2] tags := map[string]string{ "name": name, } lines, err := internal.ReadLines(file) if err != nil { return err } for _, line := range lines { fields := strings.Fields(line) for _, wanted := range wanted_fields { var data uint64 if fields[0] == wanted.inProc { wanted_field := wanted.field // if not set, assume field[1]. Shouldn't be field[0], as // that's a string if wanted_field == 0 { wanted_field = 1 } data, err = strconv.ParseUint((fields[wanted_field]), 10, 64) if err != nil { return err } report_name := wanted.inProc if wanted.reportAs != "" { report_name = wanted.reportAs } acc.Add(report_name, data, tags) } } } } return nil }
// Process backend server(redis/memcached) stats func (ti *TwemproxyInstance) processServer( acc plugins.Accumulator, tags map[string]string, prefix string, data map[string]interface{}, ) { for key, value := range data { switch key { default: if val, ok := value.(float64); ok { acc.Add(prefix+key, val, tags) } } } }
func (j *Jolokia) Gather(acc plugins.Accumulator) error { context := j.Context //"/jolokia/read" servers := j.Servers metrics := j.Metrics tags := j.Tags if tags == nil { tags = map[string]string{} } for _, server := range servers { for _, metric := range metrics { measurement := metric.Name jmxPath := metric.Jmx tags["server"] = server.Name tags["port"] = server.Port tags["host"] = server.Host // Prepare URL requestUrl, err := url.Parse("http://" + server.Host + ":" + server.Port + context + jmxPath) if err != nil { return err } if server.Username != "" || server.Password != "" { requestUrl.User = url.UserPassword(server.Username, server.Password) } out, _ := j.getAttr(requestUrl) if values, ok := out["value"]; ok { switch values.(type) { case map[string]interface{}: acc.AddFields(measurement, metric.filterFields(values.(map[string]interface{})), tags) case interface{}: acc.Add(measurement, values.(interface{}), tags) } } else { fmt.Printf("Missing key 'value' in '%s' output response\n", requestUrl.String()) } } } return nil }
func (z *Zookeeper) gatherServer(address string, acc plugins.Accumulator) error { _, _, err := net.SplitHostPort(address) if err != nil { address = address + ":2181" } c, err := net.DialTimeout("tcp", address, defaultTimeout) if err != nil { fmt.Fprintln(os.Stderr, err) return err } defer c.Close() fmt.Fprintf(c, "%s\n", "mntr") rdr := bufio.NewReader(c) scanner := bufio.NewScanner(rdr) for scanner.Scan() { line := scanner.Text() re := regexp.MustCompile(`^zk_(\w+)\s+([\w\.\-]+)`) parts := re.FindStringSubmatch(string(line)) service := strings.Split(address, ":") if len(parts) != 3 || len(service) != 2 { return fmt.Errorf("unexpected line in mntr response: %q", line) } tags := map[string]string{"server": service[0], "port": service[1]} measurement := strings.TrimPrefix(parts[1], "zk_") sValue := string(parts[2]) iVal, err := strconv.ParseInt(sValue, 10, 64) if err == nil { acc.Add(measurement, iVal, tags) } else { acc.Add(measurement, sValue, tags) } } return nil }
func (s *SwapStats) Gather(acc plugins.Accumulator) error { swap, err := s.ps.SwapStat() if err != nil { return fmt.Errorf("error getting swap memory info: %s", err) } swaptags := map[string]string(nil) acc.Add("total", swap.Total, swaptags) acc.Add("used", swap.Used, swaptags) acc.Add("free", swap.Free, swaptags) acc.Add("used_percent", swap.UsedPercent, swaptags) acc.Add("in", swap.Sin, swaptags) acc.Add("out", swap.Sout, swaptags) return nil }
// gatherInfoOutput gathers func gatherInfoOutput( rdr *bufio.Reader, acc plugins.Accumulator, tags map[string]string, ) error { scanner := bufio.NewScanner(rdr) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, "ERR") { break } if len(line) == 0 || line[0] == '#' { continue } parts := strings.SplitN(line, ":", 2) if len(parts) < 2 { continue } name := string(parts[0]) metric, ok := Tracking[name] if !ok { kline := strings.TrimSpace(string(parts[1])) gatherKeyspaceLine(name, kline, acc, tags) continue } val := strings.TrimSpace(parts[1]) ival, err := strconv.ParseUint(val, 10, 64) if err == nil { acc.Add(metric, ival, tags) continue } fval, err := strconv.ParseFloat(val, 64) if err != nil { return err } acc.Add(metric, fval, tags) } return nil }
func processResponse(acc plugins.Accumulator, prefix string, tags map[string]string, v interface{}) error { switch t := v.(type) { case map[string]interface{}: for k, v := range t { if err := processResponse(acc, prefix+"_"+k, tags, v); err != nil { return err } } case float64: acc.Add(prefix, v, tags) case bool, string, []interface{}: // ignored types return nil default: return fmt.Errorf("exec: got unexpected type %T with value %v (%s)", t, v, prefix) } return nil }
func (e *Elasticsearch) parseInterface(acc plugins.Accumulator, prefix string, tags map[string]string, v interface{}) error { switch t := v.(type) { case map[string]interface{}: for k, v := range t { if err := e.parseInterface(acc, prefix+"_"+k, tags, v); err != nil { return err } } case float64: acc.Add(prefix, t, tags) case bool, string, []interface{}: // ignored types return nil default: return fmt.Errorf("elasticsearch: got unexpected type %T with value %v (%s)", t, t, prefix) } return nil }
// Parse the special Keyspace line at end of redis stats // This is a special line that looks something like: // db0:keys=2,expires=0,avg_ttl=0 // And there is one for each db on the redis instance func gatherKeyspaceLine( name string, line string, acc plugins.Accumulator, tags map[string]string, ) { if strings.Contains(line, "keys=") { tags["database"] = name dbparts := strings.Split(line, ",") for _, dbp := range dbparts { kv := strings.Split(dbp, "=") ival, err := strconv.ParseUint(kv[1], 10, 64) if err == nil { acc.Add(kv[0], ival, tags) } } } }
func (m *Metric) PushMetrics(acc plugins.Accumulator) error { sess := session.New(&aws.Config{Region: aws.String(m.Region)}) svc := cloudwatch.New(sess) params := &cloudwatch.GetMetricStatisticsInput{ EndTime: aws.Time(time.Now()), Namespace: aws.String(m.Namespace), Period: aws.Int64(m.Period), StartTime: aws.Time(time.Now().Add(-time.Duration(m.Duration) * time.Second)), Statistics: aws.StringSlice(m.Statistics), Dimensions: convertDimensions(m.Dimensions), // Unit: aws.String(m.Unit), } printDebug(params) for _, metricName := range m.MetricNames { params.MetricName = aws.String(metricName) printDebug("requesting metric: ", metricName) resp, err := svc.GetMetricStatistics(params) if err != nil { fmt.Println(err.Error()) return err } printDebug(resp) for _, d := range resp.Datapoints { if d.Average != nil { label := strings.Join([]string{m.Prefix, *resp.Label, "average"}, "_") acc.Add(label, *d.Average, copyDims(m.Dimensions), *d.Timestamp) } if d.Maximum != nil { label := strings.Join([]string{m.Prefix, *resp.Label, "maximum"}, "_") acc.Add(label, *d.Maximum, copyDims(m.Dimensions), *d.Timestamp) } if d.Minimum != nil { label := strings.Join([]string{m.Prefix, *resp.Label, "minimum"}, "_") acc.Add(label, *d.Minimum, copyDims(m.Dimensions), *d.Timestamp) } if d.Sum != nil { label := strings.Join([]string{m.Prefix, *resp.Label, "sum"}, "_") acc.Add(label, *d.Sum, copyDims(m.Dimensions), *d.Timestamp) } } } return nil }
func (g *Prometheus) gatherURL(url string, acc plugins.Accumulator) error { resp, err := http.Get(url) if err != nil { return fmt.Errorf("error making HTTP request to %s: %s", url, err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("%s returned HTTP status %s", url, resp.Status) } format := expfmt.ResponseFormat(resp.Header) decoder := expfmt.NewDecoder(resp.Body, format) options := &expfmt.DecodeOptions{ Timestamp: model.Now(), } sampleDecoder := &expfmt.SampleDecoder{ Dec: decoder, Opts: options, } for { var samples model.Vector err := sampleDecoder.Decode(&samples) if err == io.EOF { break } else if err != nil { return fmt.Errorf("error getting processing samples for %s: %s", url, err) } for _, sample := range samples { tags := map[string]string{} for key, value := range sample.Metric { if key == model.MetricNameLabel { continue } tags[string(key)] = string(value) } acc.Add(string(sample.Metric[model.MetricNameLabel]), float64(sample.Value), tags) } } return nil }
func structPrinter(s *State, acc plugins.Accumulator) { e := reflect.ValueOf(s).Elem() for tLevelFNum := 0; tLevelFNum < e.NumField(); tLevelFNum++ { name := e.Type().Field(tLevelFNum).Name nameNumField := e.FieldByName(name).NumField() for sLevelFNum := 0; sLevelFNum < nameNumField; sLevelFNum++ { sName := e.FieldByName(name).Type().Field(sLevelFNum).Name sValue := e.FieldByName(name).Field(sLevelFNum).Interface() lname := strings.ToLower(name) lsName := strings.ToLower(sName) acc.Add(fmt.Sprintf("%s_%s", lname, lsName), sValue, nil) } } }
func (s *MemStats) Gather(acc plugins.Accumulator) error { vm, err := s.ps.VMStat() if err != nil { return fmt.Errorf("error getting virtual memory info: %s", err) } vmtags := map[string]string(nil) acc.Add("total", vm.Total, vmtags) acc.Add("available", vm.Available, vmtags) acc.Add("used", vm.Used, vmtags) acc.Add("free", vm.Free, vmtags) acc.Add("used_percent", 100*float64(vm.Used)/float64(vm.Total), vmtags) acc.Add("available_percent", 100*float64(vm.Available)/float64(vm.Total), vmtags) return nil }
func (_ *SystemStats) Gather(acc plugins.Accumulator) error { loadavg := sigar.LoadAverage{} if err := loadavg.Get(); err != nil { return err } uptime := sigar.Uptime{} if err := uptime.Get(); err != nil { return err } acc.Add("load1", loadavg.One, nil) acc.Add("load5", loadavg.Five, nil) acc.Add("load15", loadavg.Fifteen, nil) acc.Add("uptime", uptime.Length, nil) acc.Add("uptime_format", uptime.Format(), nil) return nil }
func readAerospikeStats(stats map[string]string, acc plugins.Accumulator, host, namespace string) { for key, value := range stats { tags := map[string]string{ "host": host, } if namespace != "" { tags["namespace"] = namespace } // We are going to ignore all string based keys val, err := strconv.ParseInt(value, 10, 64) if err == nil { if strings.Contains(key, "-") { key = strings.Replace(key, "-", "_", -1) } acc.Add(key, val, tags) } } }
func (p *Postgresql) accRow(row scanner, acc plugins.Accumulator, serv *Server) error { var columnVars []interface{} var dbname bytes.Buffer // this is where we'll store the column name with its *interface{} columnMap := make(map[string]*interface{}) for _, column := range serv.OrderedColumns { columnMap[column] = new(interface{}) } // populate the array of interface{} with the pointers in the right order for i := 0; i < len(columnMap); i++ { columnVars = append(columnVars, columnMap[serv.OrderedColumns[i]]) } // deconstruct array of variables and send to Scan err := row.Scan(columnVars...) if err != nil { return err } // extract the database name from the column map dbnameChars := (*columnMap["datname"]).([]uint8) for i := 0; i < len(dbnameChars); i++ { dbname.WriteString(string(dbnameChars[i])) } tags := map[string]string{"server": serv.Address, "db": dbname.String()} for col, val := range columnMap { _, ignore := ignoredColumns[col] if !ignore { acc.Add(col, *val, tags) } } return nil }
func (b *Bcache) gatherBcache(bdev string, acc plugins.Accumulator) error { tags := getTags(bdev) metrics, err := filepath.Glob(bdev + "/stats_total/*") if len(metrics) < 0 { return errors.New("Can't read any stats file") } file, err := ioutil.ReadFile(bdev + "/dirty_data") if err != nil { return err } rawValue := strings.TrimSpace(string(file)) value := prettyToBytes(rawValue) acc.Add("dirty_data", value, tags) for _, path := range metrics { key := filepath.Base(path) file, err := ioutil.ReadFile(path) rawValue := strings.TrimSpace(string(file)) if err != nil { return err } if key == "bypassed" { value := prettyToBytes(rawValue) acc.Add(key, value, tags) } else { value, _ := strconv.ParseUint(rawValue, 10, 64) acc.Add(key, value, tags) } } return nil }
func (m *Mysql) gatherServer(serv string, acc plugins.Accumulator) error { if serv == "localhost" { serv = "" } db, err := sql.Open("mysql", serv) if err != nil { return err } defer db.Close() rows, err := db.Query(`SHOW /*!50002 GLOBAL */ STATUS`) if err != nil { return err } for rows.Next() { var name string var val interface{} err = rows.Scan(&name, &val) if err != nil { return err } var found bool for _, mapped := range mappings { if strings.HasPrefix(name, mapped.onServer) { i, _ := strconv.Atoi(string(val.([]byte))) acc.Add(mapped.inExport+name[len(mapped.onServer):], i, nil) found = true } } if found { continue } switch name { case "Queries": i, err := strconv.ParseInt(string(val.([]byte)), 10, 64) if err != nil { return err } acc.Add("queries", i, nil) case "Slow_queries": i, err := strconv.ParseInt(string(val.([]byte)), 10, 64) if err != nil { return err } acc.Add("slow_queries", i, nil) } } return nil }
func (j *Jolokia) Gather(acc plugins.Accumulator) error { context := j.Context //"/jolokia/read" servers := j.Servers metrics := j.Metrics var tags = map[string]string{ "group": "application_server", } for _, server := range servers { for _, metric := range metrics { measurement := metric.Name jmxPath := metric.Jmx tags["server"] = server.Name tags["port"] = server.Port tags["host"] = server.Host url := "http://" + server.Host + ":" + server.Port + context + jmxPath //fmt.Println(url) out, _ := getAttr(url) if values, ok := out["value"]; ok { switch values.(type) { case map[string]interface{}: acc.AddFields(measurement, metric.filterFields(values.(map[string]interface{})), tags) case interface{}: acc.Add(measurement, values.(interface{}), tags) } } else { fmt.Println("Missing key value") } } } return nil }