txndata.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package cat
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "github.com/newrelic/go-agent/internal/jsonx"
  7. )
  8. // TxnDataHeader represents a decoded TxnData header.
  9. type TxnDataHeader struct {
  10. GUID string
  11. TripID string
  12. PathHash string
  13. }
  14. var (
  15. errInvalidTxnDataJSON = errors.New("invalid transaction data JSON")
  16. errInvalidTxnDataGUID = errors.New("GUID is not a string")
  17. errInvalidTxnDataTripID = errors.New("trip ID is not a string or null")
  18. errInvalidTxnDataPathHash = errors.New("path hash is not a string or null")
  19. )
  20. // MarshalJSON marshalls a TxnDataHeader as raw JSON.
  21. func (txnData *TxnDataHeader) MarshalJSON() ([]byte, error) {
  22. // Note that, although there are two and four element versions of this header
  23. // in the wild, we will only ever generate the four element version.
  24. buf := bytes.NewBufferString("[")
  25. jsonx.AppendString(buf, txnData.GUID)
  26. // Write the unused second field.
  27. buf.WriteString(",false,")
  28. jsonx.AppendString(buf, txnData.TripID)
  29. buf.WriteString(",")
  30. jsonx.AppendString(buf, txnData.PathHash)
  31. buf.WriteString("]")
  32. return buf.Bytes(), nil
  33. }
  34. // UnmarshalJSON unmarshalls a TxnDataHeader from raw JSON.
  35. func (txnData *TxnDataHeader) UnmarshalJSON(data []byte) error {
  36. var ok bool
  37. var v interface{}
  38. if err := json.Unmarshal(data, &v); err != nil {
  39. return err
  40. }
  41. arr, ok := v.([]interface{})
  42. if !ok {
  43. return errInvalidTxnDataJSON
  44. }
  45. if len(arr) < 2 {
  46. return errUnexpectedArraySize{
  47. label: "unexpected number of transaction data elements",
  48. expected: 2,
  49. actual: len(arr),
  50. }
  51. }
  52. if txnData.GUID, ok = arr[0].(string); !ok {
  53. return errInvalidTxnDataGUID
  54. }
  55. // Ignore the unused second field.
  56. // Set up defaults for the optional values.
  57. txnData.TripID = ""
  58. txnData.PathHash = ""
  59. if len(arr) >= 3 {
  60. // Per the cross agent tests, an explicit null is valid here.
  61. if nil != arr[2] {
  62. if txnData.TripID, ok = arr[2].(string); !ok {
  63. return errInvalidTxnDataTripID
  64. }
  65. }
  66. if len(arr) >= 4 {
  67. // Per the cross agent tests, an explicit null is also valid here.
  68. if nil != arr[3] {
  69. if txnData.PathHash, ok = arr[3].(string); !ok {
  70. return errInvalidTxnDataPathHash
  71. }
  72. }
  73. }
  74. }
  75. return nil
  76. }