traefik/vendor/github.com/instana/go-sensor/agent.go
2019-02-18 16:52:03 +01:00

183 lines
4 KiB
Go

package instana
import (
"bytes"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"os"
"strconv"
"time"
)
const (
agentDiscoveryURL = "/com.instana.plugin.golang.discovery"
agentTracesURL = "/com.instana.plugin.golang/traces."
agentDataURL = "/com.instana.plugin.golang."
agentEventURL = "/com.instana.plugin.generic.event"
agentDefaultHost = "localhost"
agentDefaultPort = 42699
agentHeader = "Instana Agent"
)
type agentResponse struct {
Pid uint32 `json:"pid"`
HostID string `json:"agentUuid"`
}
type discoveryS struct {
PID int `json:"pid"`
Name string `json:"name"`
Args []string `json:"args"`
Fd string `json:"fd"`
Inode string `json:"inode"`
}
type fromS struct {
PID string `json:"e"`
HostID string `json:"h"`
}
type agentS struct {
sensor *sensorS
fsm *fsmS
from *fromS
host string
client *http.Client
}
func (r *agentS) init() {
r.client = &http.Client{Timeout: 5 * time.Second}
r.fsm = r.initFsm()
r.setFrom(&fromS{})
}
func (r *agentS) makeURL(prefix string) string {
return r.makeHostURL(r.host, prefix)
}
func (r *agentS) makeHostURL(host string, prefix string) string {
envPort := os.Getenv("INSTANA_AGENT_PORT")
port := agentDefaultPort
if r.sensor.options.AgentPort > 0 {
return r.makeFullURL(host, r.sensor.options.AgentPort, prefix)
}
if envPort == "" {
return r.makeFullURL(host, port, prefix)
}
port, err := strconv.Atoi(envPort)
if err != nil {
return r.makeFullURL(host, agentDefaultPort, prefix)
}
return r.makeFullURL(host, port, prefix)
}
func (r *agentS) makeFullURL(host string, port int, prefix string) string {
var buffer bytes.Buffer
buffer.WriteString("http://")
buffer.WriteString(host)
buffer.WriteString(":")
buffer.WriteString(strconv.Itoa(port))
buffer.WriteString(prefix)
if prefix[len(prefix)-1:] == "." && r.from.PID != "" {
buffer.WriteString(r.from.PID)
}
return buffer.String()
}
func (r *agentS) head(url string) (string, error) {
return r.request(url, "HEAD", nil)
}
func (r *agentS) request(url string, method string, data interface{}) (string, error) {
return r.fullRequestResponse(url, method, data, nil, "")
}
func (r *agentS) requestResponse(url string, method string, data interface{}, ret interface{}) (string, error) {
return r.fullRequestResponse(url, method, data, ret, "")
}
func (r *agentS) requestHeader(url string, method string, header string) (string, error) {
return r.fullRequestResponse(url, method, nil, nil, header)
}
func (r *agentS) fullRequestResponse(url string, method string, data interface{}, body interface{}, header string) (string, error) {
var j []byte
var ret string
var err error
var resp *http.Response
var req *http.Request
if data != nil {
j, err = json.Marshal(data)
}
if err == nil {
if j != nil {
req, err = http.NewRequest(method, url, bytes.NewBuffer(j))
} else {
req, err = http.NewRequest(method, url, nil)
}
if err == nil {
req.Header.Set("Content-Type", "application/json")
resp, err = r.client.Do(req)
if err == nil {
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
err = errors.New(resp.Status)
} else {
log.debug("agent response:", url, resp.Status)
if body != nil {
var b []byte
b, err = ioutil.ReadAll(resp.Body)
json.Unmarshal(b, body)
}
if header != "" {
ret = resp.Header.Get(header)
}
}
}
}
}
if err != nil {
// Ignore errors while in announced stated (before ready) as
// this is the time where the entity is registering in the Instana
// backend and it will return 404 until it's done.
if !r.sensor.agent.fsm.fsm.Is("announced") {
log.info(err, url)
}
}
return ret, err
}
func (r *agentS) setFrom(from *fromS) {
r.from = from
}
func (r *agentS) setHost(host string) {
r.host = host
}
func (r *agentS) reset() {
r.fsm.reset()
}
func (r *sensorS) initAgent() *agentS {
log.debug("initializing agent")
ret := new(agentS)
ret.sensor = r
ret.init()
return ret
}