1
0
mirror of https://github.com/golang/go synced 2024-11-18 18:54:42 -07:00

internal/telemetry: pass the http.Client to the ocagent

This will allow us to configure the connection at need.
It will also allow us to intercept the content for tests.

Change-Id: Id7d34f2d56f233eae112bea97cccab1f2a88de55
Reviewed-on: https://go-review.googlesource.com/c/tools/+/190798
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
This commit is contained in:
Ian Cottrell 2019-08-15 22:43:07 -04:00 committed by Ian Cottrell
parent 547ecf7b1e
commit fa80cb575d
2 changed files with 67 additions and 32 deletions

View File

@ -113,7 +113,10 @@ gopls flags are:
// If no arguments are passed it will invoke the server sub command, as a // If no arguments are passed it will invoke the server sub command, as a
// temporary measure for compatibility. // temporary measure for compatibility.
func (app *Application) Run(ctx context.Context, args ...string) error { func (app *Application) Run(ctx context.Context, args ...string) error {
export.AddExporters(ocagent.Connect(app.name, app.OCAgent)) ocConfig := ocagent.Discover()
//TODO: we should not need to adjust the discovered configuration
ocConfig.Address = app.OCAgent
export.AddExporters(ocagent.Connect(ocConfig))
app.Serve.app = app app.Serve.app = app
if len(args) == 0 { if len(args) == 0 {
tool.Main(ctx, &app.Serve, args) tool.Main(ctx, &app.Serve, args)

View File

@ -14,6 +14,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
"path/filepath"
"sync" "sync"
"time" "time"
@ -23,12 +24,28 @@ import (
"golang.org/x/tools/internal/telemetry/tag" "golang.org/x/tools/internal/telemetry/tag"
) )
const DefaultAddress = "http://localhost:55678" type Config struct {
const exportRate = 2 * time.Second Start time.Time
Host string
Process uint32
Client *http.Client
Service string
Address string
Rate time.Duration
}
// Discover finds the local agent to export to, it will return nil if there
// is not one running.
// TODO: Actually implement a discovery protocol rather than a hard coded address
func Discover() *Config {
return &Config{
Address: "http://localhost:55678",
}
}
type exporter struct { type exporter struct {
mu sync.Mutex mu sync.Mutex
address string config Config
node *wire.Node node *wire.Node
spans []*wire.Span spans []*wire.Span
metrics []*wire.Metric metrics []*wire.Metric
@ -37,35 +54,48 @@ type exporter struct {
// Connect creates a process specific exporter with the specified // Connect creates a process specific exporter with the specified
// serviceName and the address of the ocagent to which it will upload // serviceName and the address of the ocagent to which it will upload
// its telemetry. // its telemetry.
func Connect(service, address string) export.Exporter { func Connect(config *Config) export.Exporter {
if address == "off" { if config == nil || config.Address == "off" {
return nil return nil
} }
hostname, _ := os.Hostname() exporter := &exporter{config: *config}
exporter := &exporter{ if exporter.config.Start.IsZero() {
address: address, exporter.config.Start = time.Now()
node: &wire.Node{ }
Identifier: &wire.ProcessIdentifier{ if exporter.config.Host == "" {
HostName: hostname, hostname, _ := os.Hostname()
Pid: uint32(os.Getpid()), exporter.config.Host = hostname
StartTimestamp: convertTimestamp(time.Now()), }
}, if exporter.config.Process == 0 {
LibraryInfo: &wire.LibraryInfo{ exporter.config.Process = uint32(os.Getpid())
Language: wire.LanguageGo, }
ExporterVersion: "0.0.1", if exporter.config.Client == nil {
CoreLibraryVersion: "x/tools", exporter.config.Client = http.DefaultClient
}, }
ServiceInfo: &wire.ServiceInfo{ if exporter.config.Service == "" {
Name: service, exporter.config.Service = filepath.Base(os.Args[0])
}, }
if exporter.config.Rate == 0 {
exporter.config.Rate = 2 * time.Second
}
exporter.node = &wire.Node{
Identifier: &wire.ProcessIdentifier{
HostName: exporter.config.Host,
Pid: exporter.config.Process,
StartTimestamp: convertTimestamp(exporter.config.Start),
},
LibraryInfo: &wire.LibraryInfo{
Language: wire.LanguageGo,
ExporterVersion: "0.0.1",
CoreLibraryVersion: "x/tools",
},
ServiceInfo: &wire.ServiceInfo{
Name: exporter.config.Service,
}, },
} }
if exporter.address == "" {
exporter.address = DefaultAddress
}
go func() { go func() {
for _ = range time.Tick(exportRate) { for _ = range time.Tick(exporter.config.Rate) {
exporter.flush() exporter.Flush()
} }
}() }()
return exporter return exporter
@ -87,7 +117,7 @@ func (e *exporter) Metric(ctx context.Context, data telemetry.MetricData) {
e.metrics = append(e.metrics, convertMetric(data)) e.metrics = append(e.metrics, convertMetric(data))
} }
func (e *exporter) flush() { func (e *exporter) Flush() {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
spans := e.spans spans := e.spans
@ -117,19 +147,21 @@ func (e *exporter) send(endpoint string, message interface{}) {
errorInExport("ocagent failed to marshal message for %v: %v", endpoint, err) errorInExport("ocagent failed to marshal message for %v: %v", endpoint, err)
return return
} }
uri := e.address + endpoint uri := e.config.Address + endpoint
req, err := http.NewRequest("POST", uri, bytes.NewReader(blob)) req, err := http.NewRequest("POST", uri, bytes.NewReader(blob))
if err != nil { if err != nil {
errorInExport("ocagent failed to build request for %v: %v", uri, err) errorInExport("ocagent failed to build request for %v: %v", uri, err)
return return
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req) res, err := e.config.Client.Do(req)
if err != nil { if err != nil {
errorInExport("ocagent failed to send message: %v \n", err) errorInExport("ocagent failed to send message: %v \n", err)
return return
} }
res.Body.Close() if res.Body != nil {
res.Body.Close()
}
return return
} }