1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-01-08 10:45:04 +02:00
imgproxy/vendor/github.com/newrelic/go-agent/internal/errors.go
2018-10-25 19:34:16 +06:00

175 lines
4.0 KiB
Go

package internal
import (
"bytes"
"fmt"
"net/http"
"strconv"
"time"
"github.com/newrelic/go-agent/internal/jsonx"
)
const (
// PanicErrorKlass is the error klass used for errors generated by
// recovering panics in txn.End.
PanicErrorKlass = "panic"
)
func panicValueMsg(v interface{}) string {
switch val := v.(type) {
case error:
return val.Error()
default:
return fmt.Sprintf("%v", v)
}
}
// TxnErrorFromPanic creates a new TxnError from a panic.
func TxnErrorFromPanic(now time.Time, v interface{}) ErrorData {
return ErrorData{
When: now,
Msg: panicValueMsg(v),
Klass: PanicErrorKlass,
}
}
// TxnErrorFromResponseCode creates a new TxnError from an http response code.
func TxnErrorFromResponseCode(now time.Time, code int) ErrorData {
return ErrorData{
When: now,
Msg: http.StatusText(code),
Klass: strconv.Itoa(code),
}
}
// ErrorData contains the information about a recorded error.
type ErrorData struct {
When time.Time
Stack StackTrace
ExtraAttributes map[string]interface{}
Msg string
Klass string
}
// TxnError combines error data with information about a transaction. TxnError is used for
// both error events and traced errors.
type TxnError struct {
ErrorData
TxnEvent
}
// ErrorEvent and tracedError are separate types so that error events and traced errors can have
// different WriteJSON methods.
type ErrorEvent TxnError
type tracedError TxnError
// TxnErrors is a set of errors captured in a Transaction.
type TxnErrors []*ErrorData
// NewTxnErrors returns a new empty TxnErrors.
func NewTxnErrors(max int) TxnErrors {
return make([]*ErrorData, 0, max)
}
// Add adds a TxnError.
func (errors *TxnErrors) Add(e ErrorData) {
if len(*errors) < cap(*errors) {
*errors = append(*errors, &e)
}
}
func (h *tracedError) WriteJSON(buf *bytes.Buffer) {
buf.WriteByte('[')
jsonx.AppendFloat(buf, timeToFloatMilliseconds(h.When))
buf.WriteByte(',')
jsonx.AppendString(buf, h.FinalName)
buf.WriteByte(',')
jsonx.AppendString(buf, h.Msg)
buf.WriteByte(',')
jsonx.AppendString(buf, h.Klass)
buf.WriteByte(',')
buf.WriteByte('{')
buf.WriteString(`"agentAttributes"`)
buf.WriteByte(':')
agentAttributesJSON(h.Attrs, buf, destError)
buf.WriteByte(',')
buf.WriteString(`"userAttributes"`)
buf.WriteByte(':')
userAttributesJSON(h.Attrs, buf, destError, h.ErrorData.ExtraAttributes)
buf.WriteByte(',')
buf.WriteString(`"intrinsics"`)
buf.WriteByte(':')
intrinsicsJSON(&h.TxnEvent, buf)
if nil != h.Stack {
buf.WriteByte(',')
buf.WriteString(`"stack_trace"`)
buf.WriteByte(':')
h.Stack.WriteJSON(buf)
}
if h.CleanURL != "" {
buf.WriteByte(',')
buf.WriteString(`"request_uri"`)
buf.WriteByte(':')
jsonx.AppendString(buf, h.CleanURL)
}
buf.WriteByte('}')
buf.WriteByte(']')
}
// MarshalJSON is used for testing.
func (h *tracedError) MarshalJSON() ([]byte, error) {
buf := &bytes.Buffer{}
h.WriteJSON(buf)
return buf.Bytes(), nil
}
type harvestErrors []*tracedError
func newHarvestErrors(max int) harvestErrors {
return make([]*tracedError, 0, max)
}
// MergeTxnErrors merges a transaction's errors into the harvest's errors.
func MergeTxnErrors(errors *harvestErrors, errs TxnErrors, txnEvent TxnEvent) {
for _, e := range errs {
if len(*errors) == cap(*errors) {
return
}
*errors = append(*errors, &tracedError{
TxnEvent: txnEvent,
ErrorData: *e,
})
}
}
func (errors harvestErrors) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
if 0 == len(errors) {
return nil, nil
}
estimate := 1024 * len(errors)
buf := bytes.NewBuffer(make([]byte, 0, estimate))
buf.WriteByte('[')
jsonx.AppendString(buf, agentRunID)
buf.WriteByte(',')
buf.WriteByte('[')
for i, e := range errors {
if i > 0 {
buf.WriteByte(',')
}
e.WriteJSON(buf)
}
buf.WriteByte(']')
buf.WriteByte(']')
return buf.Bytes(), nil
}
func (errors harvestErrors) MergeIntoHarvest(h *Harvest) {}
func (errors harvestErrors) EndpointMethod() string {
return cmdErrorData
}