Example #1
0
// Choose a random server in the cluster to write to until a successful write
// occurs, logging each unsuccessful. If all servers fail, return error.
func (g *Graphite) Write(metrics []telegraf.Metric) error {
	// Prepare data
	var bp []string
	s, err := serializers.NewGraphiteSerializer(g.Prefix, g.Template)
	if err != nil {
		return err
	}

	for _, metric := range metrics {
		gMetrics, err := s.Serialize(metric)
		if err != nil {
			log.Printf("Error serializing some metrics to graphite: %s", err.Error())
		}
		bp = append(bp, gMetrics...)
	}
	graphitePoints := strings.Join(bp, "\n") + "\n"

	// This will get set to nil if a successful write occurs
	err = errors.New("Could not write to any Graphite server in cluster\n")

	// Send data to a random server
	p := rand.Perm(len(g.conns))
	for _, n := range p {
		if g.Timeout > 0 {
			g.conns[n].SetWriteDeadline(time.Now().Add(time.Duration(g.Timeout) * time.Second))
		}
		if _, e := g.conns[n].Write([]byte(graphitePoints)); e != nil {
			// Error
			log.Println("ERROR: " + e.Error())
			// Let's try the next one
		} else {
			// Success
			err = nil
			break
		}
	}
	// try to reconnect
	if err != nil {
		g.Connect()
	}
	return err
}
Example #2
0
func (i *Instrumental) Write(metrics []telegraf.Metric) error {
	if i.conn == nil {
		err := i.Connect()
		if err != nil {
			return fmt.Errorf("FAILED to (re)connect to Instrumental. Error: %s\n", err)
		}
	}

	s, err := serializers.NewGraphiteSerializer(i.Prefix, i.Template)
	if err != nil {
		return err
	}

	var points []string
	var metricType string
	var toSerialize telegraf.Metric
	var newTags map[string]string

	for _, metric := range metrics {
		// Pull the metric_type out of the metric's tags. We don't want the type
		// to show up with the other tags pulled from the system, as they go in the
		// beginning of the line instead.
		// e.g we want:
		//
		//  increment some_prefix.host.tag1.tag2.tag3.field value timestamp
		//
		// vs
		//
		//  increment some_prefix.host.tag1.tag2.tag3.counter.field value timestamp
		//
		newTags = metric.Tags()
		metricType = newTags["metric_type"]
		delete(newTags, "metric_type")

		toSerialize, _ = telegraf.NewMetric(
			metric.Name(),
			newTags,
			metric.Fields(),
			metric.Time(),
		)

		stats, err := s.Serialize(toSerialize)
		if err != nil {
			log.Printf("E! Error serializing a metric to Instrumental: %s", err)
		}

		switch metricType {
		case "counter":
			fallthrough
		case "histogram":
			metricType = "increment"
		default:
			metricType = "gauge"
		}

		for _, stat := range stats {
			// decompose "metric.name value time"
			splitStat := strings.SplitN(stat, " ", 3)
			metric := splitStat[0]
			value := splitStat[1]
			time := splitStat[2]

			// replace invalid components of metric name with underscore
			clean_metric := MetricNameReplacer.ReplaceAllString(metric, "_")

			if !ValueIncludesBadChar.MatchString(value) {
				points = append(points, fmt.Sprintf("%s %s %s %s", metricType, clean_metric, value, time))
			} else if i.Debug {
				log.Printf("E! Instrumental unable to send bad stat: %s", stat)
			}
		}
	}

	allPoints := strings.Join(points, "\n") + "\n"
	_, err = fmt.Fprintf(i.conn, allPoints)

	log.Println("D! Instrumental: " + allPoints)

	if err != nil {
		if err == io.EOF {
			i.Close()
		}

		return err
	}

	// force the connection closed after sending data
	// to deal with various disconnection scenarios and eschew holding
	// open idle connections en masse
	i.Close()

	return nil
}
Example #3
0
func (i *Instrumental) Write(metrics []telegraf.Metric) error {
	if i.conn == nil {
		err := i.Connect()
		if err != nil {
			return fmt.Errorf("FAILED to (re)connect to Instrumental. Error: %s\n", err)
		}
	}

	s, err := serializers.NewGraphiteSerializer(i.Prefix, i.Template)
	if err != nil {
		return err
	}

	var points []string
	var metricType string
	var toSerialize telegraf.Metric
	var newTags map[string]string

	for _, metric := range metrics {
		// Pull the metric_type out of the metric's tags. We don't want the type
		// to show up with the other tags pulled from the system, as they go in the
		// beginning of the line instead.
		// e.g we want:
		//
		//  increment some_prefix.host.tag1.tag2.tag3.field value timestamp
		//
		// vs
		//
		//  increment some_prefix.host.tag1.tag2.tag3.counter.field value timestamp
		//
		newTags = metric.Tags()
		metricType = newTags["metric_type"]
		delete(newTags, "metric_type")

		toSerialize, _ = telegraf.NewMetric(
			metric.Name(),
			newTags,
			metric.Fields(),
			metric.Time(),
		)

		stats, err := s.Serialize(toSerialize)
		if err != nil {
			log.Printf("Error serializing a metric to Instrumental: %s", err)
		}

		switch metricType {
		case "counter":
			fallthrough
		case "histogram":
			metricType = "increment"
		default:
			metricType = "gauge"
		}

		for _, stat := range stats {
			if !StatIncludesBadChar.MatchString(stat) {
				points = append(points, fmt.Sprintf("%s %s", metricType, stat))
			} else if i.Debug {
				log.Printf("Unable to send bad stat: %s", stat)
			}
		}
	}

	allPoints := strings.Join(points, "\n") + "\n"
	_, err = fmt.Fprintf(i.conn, allPoints)

	if i.Debug {
		log.Println(allPoints)
	}

	if err != nil {
		if err == io.EOF {
			i.Close()
		}

		return err
	}

	return nil
}