184 lines
4 KiB
Go
184 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
|
||
|
}
|