mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-01-08 10:45:04 +02:00
175 lines
4.0 KiB
Go
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
|
|
}
|