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