github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/errors.go (about)

     1  package internal
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/lulzWill/go-agent/internal/jsonx"
    11  )
    12  
    13  const (
    14  	// PanicErrorKlass is the error klass used for errors generated by
    15  	// recovering panics in txn.End.
    16  	PanicErrorKlass = "panic"
    17  )
    18  
    19  func panicValueMsg(v interface{}) string {
    20  	switch val := v.(type) {
    21  	case error:
    22  		return val.Error()
    23  	default:
    24  		return fmt.Sprintf("%v", v)
    25  	}
    26  }
    27  
    28  // TxnErrorFromPanic creates a new TxnError from a panic.
    29  func TxnErrorFromPanic(now time.Time, v interface{}) ErrorData {
    30  	return ErrorData{
    31  		When:  now,
    32  		Msg:   panicValueMsg(v),
    33  		Klass: PanicErrorKlass,
    34  	}
    35  }
    36  
    37  // TxnErrorFromResponseCode creates a new TxnError from an http response code.
    38  func TxnErrorFromResponseCode(now time.Time, code int) ErrorData {
    39  	return ErrorData{
    40  		When:  now,
    41  		Msg:   http.StatusText(code),
    42  		Klass: strconv.Itoa(code),
    43  	}
    44  }
    45  
    46  // ErrorData contains the information about a recorded error.
    47  type ErrorData struct {
    48  	When            time.Time
    49  	Stack           StackTrace
    50  	ExtraAttributes map[string]interface{}
    51  	Msg             string
    52  	Klass           string
    53  }
    54  
    55  // TxnError combines error data with information about a transaction.  TxnError is used for
    56  // both error events and traced errors.
    57  type TxnError struct {
    58  	ErrorData
    59  	TxnEvent
    60  }
    61  
    62  // ErrorEvent and tracedError are separate types so that error events and traced errors can have
    63  // different WriteJSON methods.
    64  type ErrorEvent TxnError
    65  
    66  type tracedError TxnError
    67  
    68  // TxnErrors is a set of errors captured in a Transaction.
    69  type TxnErrors []*ErrorData
    70  
    71  // NewTxnErrors returns a new empty TxnErrors.
    72  func NewTxnErrors(max int) TxnErrors {
    73  	return make([]*ErrorData, 0, max)
    74  }
    75  
    76  // Add adds a TxnError.
    77  func (errors *TxnErrors) Add(e ErrorData) {
    78  	if len(*errors) < cap(*errors) {
    79  		*errors = append(*errors, &e)
    80  	}
    81  }
    82  
    83  func (h *tracedError) WriteJSON(buf *bytes.Buffer) {
    84  	buf.WriteByte('[')
    85  	jsonx.AppendFloat(buf, timeToFloatMilliseconds(h.When))
    86  	buf.WriteByte(',')
    87  	jsonx.AppendString(buf, h.FinalName)
    88  	buf.WriteByte(',')
    89  	jsonx.AppendString(buf, h.Msg)
    90  	buf.WriteByte(',')
    91  	jsonx.AppendString(buf, h.Klass)
    92  	buf.WriteByte(',')
    93  
    94  	buf.WriteByte('{')
    95  	buf.WriteString(`"agentAttributes"`)
    96  	buf.WriteByte(':')
    97  	agentAttributesJSON(h.Attrs, buf, destError)
    98  	buf.WriteByte(',')
    99  	buf.WriteString(`"userAttributes"`)
   100  	buf.WriteByte(':')
   101  	userAttributesJSON(h.Attrs, buf, destError, h.ErrorData.ExtraAttributes)
   102  	buf.WriteByte(',')
   103  	buf.WriteString(`"intrinsics"`)
   104  	buf.WriteByte(':')
   105  	intrinsicsJSON(&h.TxnEvent, buf)
   106  	if nil != h.Stack {
   107  		buf.WriteByte(',')
   108  		buf.WriteString(`"stack_trace"`)
   109  		buf.WriteByte(':')
   110  		h.Stack.WriteJSON(buf)
   111  	}
   112  	if h.CleanURL != "" {
   113  		buf.WriteByte(',')
   114  		buf.WriteString(`"request_uri"`)
   115  		buf.WriteByte(':')
   116  		jsonx.AppendString(buf, h.CleanURL)
   117  	}
   118  	buf.WriteByte('}')
   119  
   120  	buf.WriteByte(']')
   121  }
   122  
   123  // MarshalJSON is used for testing.
   124  func (h *tracedError) MarshalJSON() ([]byte, error) {
   125  	buf := &bytes.Buffer{}
   126  	h.WriteJSON(buf)
   127  	return buf.Bytes(), nil
   128  }
   129  
   130  type harvestErrors []*tracedError
   131  
   132  func newHarvestErrors(max int) harvestErrors {
   133  	return make([]*tracedError, 0, max)
   134  }
   135  
   136  // MergeTxnErrors merges a transaction's errors into the harvest's errors.
   137  func MergeTxnErrors(errors *harvestErrors, errs TxnErrors, txnEvent TxnEvent) {
   138  	for _, e := range errs {
   139  		if len(*errors) == cap(*errors) {
   140  			return
   141  		}
   142  		*errors = append(*errors, &tracedError{
   143  			TxnEvent:  txnEvent,
   144  			ErrorData: *e,
   145  		})
   146  	}
   147  }
   148  
   149  func (errors harvestErrors) Data(agentRunID string, harvestStart time.Time) ([]byte, error) {
   150  	if 0 == len(errors) {
   151  		return nil, nil
   152  	}
   153  	estimate := 1024 * len(errors)
   154  	buf := bytes.NewBuffer(make([]byte, 0, estimate))
   155  	buf.WriteByte('[')
   156  	jsonx.AppendString(buf, agentRunID)
   157  	buf.WriteByte(',')
   158  	buf.WriteByte('[')
   159  	for i, e := range errors {
   160  		if i > 0 {
   161  			buf.WriteByte(',')
   162  		}
   163  		e.WriteJSON(buf)
   164  	}
   165  	buf.WriteByte(']')
   166  	buf.WriteByte(']')
   167  	return buf.Bytes(), nil
   168  }
   169  
   170  func (errors harvestErrors) MergeIntoHarvest(h *Harvest) {}