Create init method on provider interface
This commit is contained in:
parent
b2a57ca1f3
commit
027093a5a5
52 changed files with 2760 additions and 131 deletions
237
vendor/github.com/Microsoft/ApplicationInsights-Go/appinsights/transmitter.go
generated
vendored
Normal file
237
vendor/github.com/Microsoft/ApplicationInsights-Go/appinsights/transmitter.go
generated
vendored
Normal file
|
@ -0,0 +1,237 @@
|
|||
package appinsights
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
type transmitter interface {
|
||||
Transmit(payload []byte, items TelemetryBufferItems) (*transmissionResult, error)
|
||||
}
|
||||
|
||||
type httpTransmitter struct {
|
||||
endpoint string
|
||||
}
|
||||
|
||||
type transmissionResult struct {
|
||||
statusCode int
|
||||
retryAfter *time.Time
|
||||
response *backendResponse
|
||||
}
|
||||
|
||||
// Structures returned by data collector
|
||||
type backendResponse struct {
|
||||
ItemsReceived int `json:"itemsReceived"`
|
||||
ItemsAccepted int `json:"itemsAccepted"`
|
||||
Errors itemTransmissionResults `json:"errors"`
|
||||
}
|
||||
|
||||
// This needs to be its own type because it implements sort.Interface
|
||||
type itemTransmissionResults []*itemTransmissionResult
|
||||
|
||||
type itemTransmissionResult struct {
|
||||
Index int `json:"index"`
|
||||
StatusCode int `json:"statusCode"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
const (
|
||||
successResponse = 200
|
||||
partialSuccessResponse = 206
|
||||
requestTimeoutResponse = 408
|
||||
tooManyRequestsResponse = 429
|
||||
tooManyRequestsOverExtendedTimeResponse = 439
|
||||
errorResponse = 500
|
||||
serviceUnavailableResponse = 503
|
||||
)
|
||||
|
||||
func newTransmitter(endpointAddress string) transmitter {
|
||||
return &httpTransmitter{endpointAddress}
|
||||
}
|
||||
|
||||
func (transmitter *httpTransmitter) Transmit(payload []byte, items TelemetryBufferItems) (*transmissionResult, error) {
|
||||
diagnosticsWriter.Printf("----------- Transmitting %d items ---------", len(items))
|
||||
startTime := time.Now()
|
||||
|
||||
// Compress the payload
|
||||
var postBody bytes.Buffer
|
||||
gzipWriter := gzip.NewWriter(&postBody)
|
||||
if _, err := gzipWriter.Write(payload); err != nil {
|
||||
diagnosticsWriter.Printf("Failed to compress the payload: %s", err.Error())
|
||||
gzipWriter.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gzipWriter.Close()
|
||||
|
||||
req, err := http.NewRequest("POST", transmitter.endpoint, &postBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Encoding", "gzip")
|
||||
req.Header.Set("Content-Type", "application/x-json-stream")
|
||||
req.Header.Set("Accept-Encoding", "gzip, deflate")
|
||||
|
||||
client := http.DefaultClient
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
diagnosticsWriter.Printf("Failed to transmit telemetry: %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
diagnosticsWriter.Printf("Failed to read response from server: %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
duration := time.Since(startTime)
|
||||
|
||||
result := &transmissionResult{statusCode: resp.StatusCode}
|
||||
|
||||
// Grab Retry-After header
|
||||
if retryAfterValue, ok := resp.Header[http.CanonicalHeaderKey("Retry-After")]; ok && len(retryAfterValue) == 1 {
|
||||
if retryAfterTime, err := time.Parse(time.RFC1123, retryAfterValue[0]); err == nil {
|
||||
result.retryAfter = &retryAfterTime
|
||||
}
|
||||
}
|
||||
|
||||
// Parse body, if possible
|
||||
response := &backendResponse{}
|
||||
if err := json.Unmarshal(body, &response); err == nil {
|
||||
result.response = response
|
||||
}
|
||||
|
||||
// Write diagnostics
|
||||
if diagnosticsWriter.hasListeners() {
|
||||
diagnosticsWriter.Printf("Telemetry transmitted in %s", duration)
|
||||
diagnosticsWriter.Printf("Response: %d", result.statusCode)
|
||||
if result.response != nil {
|
||||
diagnosticsWriter.Printf("Items accepted/received: %d/%d", result.response.ItemsAccepted, result.response.ItemsReceived)
|
||||
if len(result.response.Errors) > 0 {
|
||||
diagnosticsWriter.Printf("Errors:")
|
||||
for _, err := range result.response.Errors {
|
||||
if err.Index < len(items) {
|
||||
diagnosticsWriter.Printf("#%d - %d %s", err.Index, err.StatusCode, err.Message)
|
||||
diagnosticsWriter.Printf("Telemetry item:\n\t%s", err.Index, string(items[err.Index:err.Index+1].serialize()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (result *transmissionResult) IsSuccess() bool {
|
||||
return result.statusCode == successResponse ||
|
||||
// Partial response but all items accepted
|
||||
(result.statusCode == partialSuccessResponse &&
|
||||
result.response != nil &&
|
||||
result.response.ItemsReceived == result.response.ItemsAccepted)
|
||||
}
|
||||
|
||||
func (result *transmissionResult) IsFailure() bool {
|
||||
return result.statusCode != successResponse && result.statusCode != partialSuccessResponse
|
||||
}
|
||||
|
||||
func (result *transmissionResult) CanRetry() bool {
|
||||
if result.IsSuccess() {
|
||||
return false
|
||||
}
|
||||
|
||||
return result.statusCode == partialSuccessResponse ||
|
||||
result.retryAfter != nil ||
|
||||
(result.statusCode == requestTimeoutResponse ||
|
||||
result.statusCode == serviceUnavailableResponse ||
|
||||
result.statusCode == errorResponse ||
|
||||
result.statusCode == tooManyRequestsResponse ||
|
||||
result.statusCode == tooManyRequestsOverExtendedTimeResponse)
|
||||
}
|
||||
|
||||
func (result *transmissionResult) IsPartialSuccess() bool {
|
||||
return result.statusCode == partialSuccessResponse &&
|
||||
result.response != nil &&
|
||||
result.response.ItemsReceived != result.response.ItemsAccepted
|
||||
}
|
||||
|
||||
func (result *transmissionResult) IsThrottled() bool {
|
||||
return result.statusCode == tooManyRequestsResponse ||
|
||||
result.statusCode == tooManyRequestsOverExtendedTimeResponse ||
|
||||
result.retryAfter != nil
|
||||
}
|
||||
|
||||
func (result *itemTransmissionResult) CanRetry() bool {
|
||||
return result.StatusCode == requestTimeoutResponse ||
|
||||
result.StatusCode == serviceUnavailableResponse ||
|
||||
result.StatusCode == errorResponse ||
|
||||
result.StatusCode == tooManyRequestsResponse ||
|
||||
result.StatusCode == tooManyRequestsOverExtendedTimeResponse
|
||||
}
|
||||
|
||||
func (result *transmissionResult) GetRetryItems(payload []byte, items TelemetryBufferItems) ([]byte, TelemetryBufferItems) {
|
||||
if result.statusCode == partialSuccessResponse && result.response != nil {
|
||||
// Make sure errors are ordered by index
|
||||
sort.Sort(result.response.Errors)
|
||||
|
||||
var resultPayload bytes.Buffer
|
||||
resultItems := make(TelemetryBufferItems, 0)
|
||||
ptr := 0
|
||||
idx := 0
|
||||
|
||||
// Find each retryable error
|
||||
for _, responseResult := range result.response.Errors {
|
||||
if responseResult.CanRetry() {
|
||||
// Advance ptr to start of desired line
|
||||
for ; idx < responseResult.Index && ptr < len(payload); ptr++ {
|
||||
if payload[ptr] == '\n' {
|
||||
idx++
|
||||
}
|
||||
}
|
||||
|
||||
startPtr := ptr
|
||||
|
||||
// Read to end of line
|
||||
for ; idx == responseResult.Index && ptr < len(payload); ptr++ {
|
||||
if payload[ptr] == '\n' {
|
||||
idx++
|
||||
}
|
||||
}
|
||||
|
||||
// Copy item into output buffer
|
||||
resultPayload.Write(payload[startPtr:ptr])
|
||||
resultItems = append(resultItems, items[responseResult.Index])
|
||||
}
|
||||
}
|
||||
|
||||
return resultPayload.Bytes(), resultItems
|
||||
} else if result.CanRetry() {
|
||||
return payload, items
|
||||
} else {
|
||||
return payload[:0], items[:0]
|
||||
}
|
||||
}
|
||||
|
||||
// sort.Interface implementation for Errors[] list
|
||||
|
||||
func (results itemTransmissionResults) Len() int {
|
||||
return len(results)
|
||||
}
|
||||
|
||||
func (results itemTransmissionResults) Less(i, j int) bool {
|
||||
return results[i].Index < results[j].Index
|
||||
}
|
||||
|
||||
func (results itemTransmissionResults) Swap(i, j int) {
|
||||
tmp := results[i]
|
||||
results[i] = results[j]
|
||||
results[j] = tmp
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue