terraform/vendor/github.com/newrelic/go-agent/internal/errors.go

180 lines
4.1 KiB
Go

package internal
import (
"bytes"
"fmt"
"net/http"
"reflect"
"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{}) TxnError {
return TxnError{
When: now,
Msg: panicValueMsg(v),
Klass: PanicErrorKlass,
}
}
// TxnErrorFromError creates a new TxnError from an error.
func TxnErrorFromError(now time.Time, err error) TxnError {
return TxnError{
When: now,
Msg: err.Error(),
Klass: reflect.TypeOf(err).String(),
}
}
// TxnErrorFromResponseCode creates a new TxnError from an http response code.
func TxnErrorFromResponseCode(now time.Time, code int) TxnError {
return TxnError{
When: now,
Msg: http.StatusText(code),
Klass: strconv.Itoa(code),
}
}
// TxnError is an error captured in a Transaction.
type TxnError struct {
When time.Time
Stack *StackTrace
Msg string
Klass string
}
// TxnErrors is a set of errors captured in a Transaction.
type TxnErrors []*TxnError
// NewTxnErrors returns a new empty TxnErrors.
func NewTxnErrors(max int) TxnErrors {
return make([]*TxnError, 0, max)
}
// Add adds a TxnError.
func (errors *TxnErrors) Add(e TxnError) {
if len(*errors) < cap(*errors) {
*errors = append(*errors, &e)
}
}
func (h *harvestError) WriteJSON(buf *bytes.Buffer) {
buf.WriteByte('[')
jsonx.AppendFloat(buf, timeToFloatMilliseconds(h.When))
buf.WriteByte(',')
jsonx.AppendString(buf, h.txnName)
buf.WriteByte(',')
jsonx.AppendString(buf, h.Msg)
buf.WriteByte(',')
jsonx.AppendString(buf, h.Klass)
buf.WriteByte(',')
buf.WriteByte('{')
w := jsonFieldsWriter{buf: buf}
if nil != h.Stack {
w.writerField("stack_trace", h.Stack)
}
w.writerField("agentAttributes", agentAttributesJSONWriter{
attributes: h.attrs,
dest: destError,
})
w.writerField("userAttributes", userAttributesJSONWriter{
attributes: h.attrs,
dest: destError,
})
w.rawField("intrinsics", JSONString("{}"))
if h.requestURI != "" {
w.stringField("request_uri", h.requestURI)
}
buf.WriteByte('}')
buf.WriteByte(']')
}
// MarshalJSON is used for testing.
func (h *harvestError) MarshalJSON() ([]byte, error) {
buf := &bytes.Buffer{}
h.WriteJSON(buf)
return buf.Bytes(), nil
}
type harvestError struct {
TxnError
txnName string
requestURI string
attrs *Attributes
}
type harvestErrors struct {
errors []*harvestError
}
func newHarvestErrors(max int) *harvestErrors {
return &harvestErrors{
errors: make([]*harvestError, 0, max),
}
}
func harvestErrorFromTxnError(e *TxnError, txnName string, requestURI string, attrs *Attributes) *harvestError {
return &harvestError{
TxnError: *e,
txnName: txnName,
requestURI: requestURI,
attrs: attrs,
}
}
func addTxnError(errors *harvestErrors, e *TxnError, txnName string, requestURI string, attrs *Attributes) {
he := harvestErrorFromTxnError(e, txnName, requestURI, attrs)
errors.errors = append(errors.errors, he)
}
// MergeTxnErrors merges a transaction's errors into the harvest's errors.
func MergeTxnErrors(errors *harvestErrors, errs TxnErrors, txnName string, requestURI string, attrs *Attributes) {
for _, e := range errs {
if len(errors.errors) == cap(errors.errors) {
return
}
addTxnError(errors, e, txnName, requestURI, attrs)
}
}
func (errors *harvestErrors) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
if 0 == len(errors.errors) {
return nil, nil
}
estimate := 1024 * len(errors.errors)
buf := bytes.NewBuffer(make([]byte, 0, estimate))
buf.WriteByte('[')
jsonx.AppendString(buf, agentRunID)
buf.WriteByte(',')
buf.WriteByte('[')
for i, e := range errors.errors {
if i > 0 {
buf.WriteByte(',')
}
e.WriteJSON(buf)
}
buf.WriteByte(']')
buf.WriteByte(']')
return buf.Bytes(), nil
}
func (errors *harvestErrors) MergeIntoHarvest(h *Harvest) {}