// 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 }
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 }
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 }