github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/model/annotation.go (about) 1 package model 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/hashicorp/go-multierror" 8 "github.com/pkg/errors" 9 "github.com/pyroscope-io/pyroscope/pkg/flameql" 10 ) 11 12 var ( 13 ErrAnnotationInvalidAppName = ValidationError{errors.New("invalid app name")} 14 ErrAnnotationInvalidTimestamp = ValidationError{errors.New("invalid timestamp")} 15 ErrAnnotationInvalidContent = ValidationError{errors.New("invalid content")} 16 ) 17 18 type Annotation struct { 19 AppName string `gorm:"index:idx_appname_timestamp,unique;not null;default:null"` 20 Timestamp time.Time `gorm:"index:idx_appname_timestamp,unique;not null;default:null"` 21 Content string `gorm:"not null;default:null"` 22 CreatedAt time.Time 23 UpdatedAt time.Time 24 } 25 26 type CreateAnnotation struct { 27 AppName string 28 Content string 29 Timestamp time.Time 30 } 31 32 // Parse parses and validates 33 // It adds a default timestamp (to time.Now) if not present 34 // And check required fields are set 35 func (a *CreateAnnotation) Parse() error { 36 var err error 37 38 if a.Timestamp.IsZero() { 39 a.Timestamp = time.Now() 40 } 41 42 if a.AppName == "" { 43 err = multierror.Append(err, ErrAnnotationInvalidAppName) 44 } else { 45 if parseErr := a.handleAppNameQuery(); parseErr != nil { 46 err = multierror.Append(err, parseErr) 47 } 48 } 49 50 if a.Content == "" { 51 err = multierror.Append(err, ErrAnnotationInvalidContent) 52 } 53 54 return err 55 } 56 57 func (a *CreateAnnotation) handleAppNameQuery() error { 58 if a.AppName == "" { 59 return ErrAnnotationInvalidAppName 60 } 61 62 // Strip labels 63 key, parseErr := flameql.ParseQuery(a.AppName) 64 if parseErr != nil { 65 return fmt.Errorf("%w: %v", ErrAnnotationInvalidAppName, parseErr) 66 } 67 68 // Handle when only tags are passed 69 if key == nil || key.AppName == "" { 70 return ErrAnnotationInvalidAppName 71 } 72 73 a.AppName = key.AppName 74 75 return nil 76 }