github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/custom_event.go (about) 1 package internal 2 3 import ( 4 "bytes" 5 "fmt" 6 "regexp" 7 "time" 8 ) 9 10 // https://newrelic.atlassian.net/wiki/display/eng/Custom+Events+in+New+Relic+Agents 11 12 var ( 13 eventTypeRegexRaw = `^[a-zA-Z0-9:_ ]+$` 14 eventTypeRegex = regexp.MustCompile(eventTypeRegexRaw) 15 16 errEventTypeLength = fmt.Errorf("event type exceeds length limit of %d", 17 attributeKeyLengthLimit) 18 // ErrEventTypeRegex will be returned to caller of app.RecordCustomEvent 19 // if the event type is not valid. 20 ErrEventTypeRegex = fmt.Errorf("event type must match %s", eventTypeRegexRaw) 21 errNumAttributes = fmt.Errorf("maximum of %d attributes exceeded", 22 customEventAttributeLimit) 23 ) 24 25 // CustomEvent is a custom event. 26 type CustomEvent struct { 27 eventType string 28 timestamp time.Time 29 truncatedParams map[string]interface{} 30 } 31 32 // WriteJSON prepares JSON in the format expected by the collector. 33 func (e *CustomEvent) WriteJSON(buf *bytes.Buffer) { 34 w := jsonFieldsWriter{buf: buf} 35 buf.WriteByte('[') 36 buf.WriteByte('{') 37 w.stringField("type", e.eventType) 38 w.floatField("timestamp", timeToFloatSeconds(e.timestamp)) 39 buf.WriteByte('}') 40 41 buf.WriteByte(',') 42 buf.WriteByte('{') 43 w = jsonFieldsWriter{buf: buf} 44 for key, val := range e.truncatedParams { 45 writeAttributeValueJSON(&w, key, val) 46 } 47 buf.WriteByte('}') 48 49 buf.WriteByte(',') 50 buf.WriteByte('{') 51 buf.WriteByte('}') 52 buf.WriteByte(']') 53 } 54 55 // MarshalJSON is used for testing. 56 func (e *CustomEvent) MarshalJSON() ([]byte, error) { 57 buf := bytes.NewBuffer(make([]byte, 0, 256)) 58 59 e.WriteJSON(buf) 60 61 return buf.Bytes(), nil 62 } 63 64 func eventTypeValidate(eventType string) error { 65 if len(eventType) > attributeKeyLengthLimit { 66 return errEventTypeLength 67 } 68 if !eventTypeRegex.MatchString(eventType) { 69 return ErrEventTypeRegex 70 } 71 return nil 72 } 73 74 // CreateCustomEvent creates a custom event. 75 func CreateCustomEvent(eventType string, params map[string]interface{}, now time.Time) (*CustomEvent, error) { 76 if err := eventTypeValidate(eventType); nil != err { 77 return nil, err 78 } 79 80 if len(params) > customEventAttributeLimit { 81 return nil, errNumAttributes 82 } 83 84 truncatedParams := make(map[string]interface{}) 85 for key, val := range params { 86 val, err := ValidateUserAttribute(key, val) 87 if nil != err { 88 return nil, err 89 } 90 truncatedParams[key] = val 91 } 92 93 return &CustomEvent{ 94 eventType: eventType, 95 timestamp: now, 96 truncatedParams: truncatedParams, 97 }, nil 98 } 99 100 // MergeIntoHarvest implements Harvestable. 101 func (e *CustomEvent) MergeIntoHarvest(h *Harvest) { 102 h.CustomEvents.Add(e) 103 }