receiver/carbonreceiver/internal/client/plaintext_client.go (118 lines of code) (raw):

// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package client // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/carbonreceiver/internal/client" import ( "fmt" "io" "net" "strconv" "strings" "time" ) // Graphite is a struct that defines the relevant properties of a graphite // connection. // This code was initially taken from // https://github.com/census-ecosystem/opencensus-go-exporter-graphite/tree/master/internal/client // and modified for the needs of testing the Carbon receiver package and is not // intended/tested to be used in production. type Graphite struct { Endpoint string Timeout time.Duration Conn io.Writer } // Transport is used as an enum to select the type of transport to be used. type Transport int // Available transport options: TCP and UDP. const ( TCP Transport = iota UDP ) const defaultTimeout = 5 // NewGraphite is a method that's used to create a new Graphite instance. // This code was initially taken from // https://github.com/census-ecosystem/opencensus-go-exporter-graphite/tree/master/internal/client // and modified for the needs of testing the Carbon receiver package and is not // intended/tested to be used in production. func NewGraphite(transport Transport, endpoint string) (*Graphite, error) { graphite := &Graphite{Endpoint: endpoint} err := graphite.connect(transport) if err != nil { return nil, err } return graphite, nil } // connect populates the Graphite.conn. func (g *Graphite) connect(transport Transport) error { if cl, ok := g.Conn.(io.Closer); ok { cl.Close() } if g.Timeout == 0 { g.Timeout = defaultTimeout * time.Second } var err error switch transport { case TCP: g.Conn, err = net.DialTimeout("tcp", g.Endpoint, g.Timeout) case UDP: var udpAddr *net.UDPAddr udpAddr, err = net.ResolveUDPAddr("udp", g.Endpoint) if err != nil { return err } g.Conn, err = net.DialUDP("udp", nil, udpAddr) if err != nil { return err } default: return fmt.Errorf("unknown transport %d", transport) } return err } // Disconnect closes the Graphite.conn field func (g *Graphite) Disconnect() (err error) { if cl, ok := g.Conn.(io.Closer); ok { err = cl.Close() } g.Conn = nil return err } // SendMetric method can be used to just pass a metric name and value and // have it be sent to the Graphite host func (g *Graphite) SendMetric(metric Metric) error { _, err := fmt.Fprint(g.Conn, metric.String()) if err != nil { return err } return nil } // SputterThenSendMetric method sends a bad partial metric, then the whole metric across. func (g *Graphite) SputterThenSendMetric(metric Metric) error { str := metric.String() for i := 0; i < 5; i++ { if _, err := fmt.Fprint(g.Conn, ""); err != nil { return err } if err := g.Disconnect(); err != nil { return err } if err := g.connect(TCP); err != nil { return err } } if _, err := fmt.Fprint(g.Conn, str); err != nil { return err } return nil } // SendMetrics method can be used to pass a set of metrics and // have it be sent to the Graphite host func (g *Graphite) SendMetrics(metrics []Metric) error { sb := strings.Builder{} for i, metric := range metrics { if _, err := sb.WriteString(metric.String()); err != nil { return err } if i == len(metrics)-1 { break } if err := sb.WriteByte('\n'); err != nil { return err } } _, err := fmt.Fprint(g.Conn, sb.String()) if err != nil { return err } return nil } // Metric contains the metric fields expected by Graphite. type Metric struct { Name string Value float64 Timestamp time.Time } // String formats a Metric to the format expected bt Graphite. func (m Metric) String() string { return fmt.Sprintf( "%s %s %d\n", m.Name, strconv.FormatFloat(m.Value, 'f', -1, 64), m.Timestamp.Unix(), ) }