Dial UDP connection for submitting traces exactly once
@@ -8,6 +8,7 @@ package trace
import (
"context"
+ "errors"
"io"
"math/rand"
"net"
@@ -43,6 +44,13 @@ var disabled bool = false
var enabledMtx sync.RWMutex
+var udpConn *net.UDPConn
+
+// used to initialize udpConn inside sendSample
+var udpInitOnce sync.Once
+var udpInitFunc = func() { initUDPConn(localVeneurAddress) }
+var udpConnUninitializedErr = errors.New("UDP connection is not yet initialized")
+
// Make an unexported `key` type that we use as a String such
// that we don't get lint warnings from using it as a key in
// Context. See https://blog.golang.org/context#TOC_3.2.
@@ -329,29 +337,38 @@ func sendSample(sample *ssf.SSFSpan) error {
return nil
}
- serverAddr, err := net.ResolveUDPAddr("udp", localVeneurAddress)
+ udpInitOnce.Do(udpInitFunc)
+ if udpConn == nil {
+ return udpConnUninitializedErr
+ }
+
+ data, err := proto.Marshal(sample)
if err != nil {
return err
}
- conn, err := net.DialUDP("udp", nil, serverAddr)
+ _, err = udpConn.Write(data)
if err != nil {
return err
}
- defer conn.Close()
+ return nil
+}
- data, err := proto.Marshal(sample)
+// initUDPConn will initialize the global UDP connection.
+// It will panic if it encounters an error.
+// It should only be called via the corresponding sync.Once
+func initUDPConn(address string) {
+ serverAddr, err := net.ResolveUDPAddr("udp", localVeneurAddress)
if err != nil {
- return err
+ panic(err)
}
- _, err = conn.Write(data)
+ conn, err := net.DialUDP("udp", nil, serverAddr)
if err != nil {
- return err
+ panic(err)
}
-
- return nil
+ udpConn = conn
}
// stripPackageName strips the package name from a function
