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  }