@@ -51,31 +51,74 @@ func apiDataToString(data []*ApiData) string {
5151
5252//dataPoint is provided by user on the command line
5353//the format is this:
54- // M2:S100:60:1000,10,0,10,20,30,40,50,60,70,80,90,95,99,100
55- // <SAMPLES>,<PERCENTILE WIDTH>,<PERCENTILE DATA>
56- func ParseDataPoint (dataPoint string ) (* ApiData , error ) {
57- data := strings .Split (dataPoint , ":" )
58- if len (data ) < 4 {
59- return nil , fmt .Errorf ("Bad datapoint format" )
60- }
54+ // <METRIC>:<SUBJECT>:<TIME>[<SAMPLES>,<PERCENTILE WIDTH>,[<PERCENTILE DATA>]]
55+ // eg: M1:s1:-60:[100,50,[1,2,3,4,5,6]]
56+ // Multiple dataPoint can be splited by semicolons
57+ // eg: M1:s1:-120:0.1;M1:s1:-60:90.9
58+ // If timeInSecAgo is true, the time should be positive and is the number of seconds ago. Otherwise
59+ // it is the time format as defined by the api.
60+ func ParseDataPoint (dataPoint string , timeInSecAgo bool ) (map [string ][]* ApiData , error ) {
61+ dataPoint = strings .TrimRight (dataPoint , ";" )
62+ // split the data in multiple calls if multiple subjectIds are provided
63+ // we do this because a call cannot have the same metricId two times, but we should allow adding data
64+ // for the same metricId on multiple subject ids
65+ callsData := make (map [string ][]* ApiData )
6166
62- metricId , err := strconv .ParseInt (data [0 ][1 :], 10 , 64 )
63- if err != nil {
64- return nil , err
65- }
66- secAgo , err := strconv .Atoi (data [2 ])
67- if err != nil {
68- return nil , err
67+ // the data entries are separated by ";"
68+ for _ , entry := range strings .Split (dataPoint , ";" ) {
69+ // parse each data entry
70+ data := strings .Split (entry , ":" )
71+ if len (data ) < 4 {
72+ return nil , fmt .Errorf ("Bad datapoint format" )
73+ }
74+ metricId , err := strconv .ParseInt (data [0 ][1 :], 10 , 64 )
75+ if err != nil {
76+ return nil , err
77+ }
78+ time , err := strconv .Atoi (data [2 ])
79+ if err != nil {
80+ return nil , err
81+ }
82+ subjectId := data [1 ]
83+
84+ // Convert the time format if timeInSecAgo is true.
85+ if timeInSecAgo {
86+ time = - time
87+ }
88+
89+ // create the new ApiData object
90+ newDataPoint := DataPoint {time , data [3 ]}
91+ newApiData := & ApiData {metricId , subjectId , []DataPoint {newDataPoint }}
92+
93+ // find the right place for this ApiData in the result
94+ // if a callData for this subjectId exists, then the new data belongs to it
95+ if callData , found := callsData [subjectId ]; found {
96+ // search for an existing ApiData for this metricId
97+ var foundMetricId bool
98+ for _ , apiData := range callData {
99+ if apiData .MetricID == metricId {
100+ // found the apiData, append to it just the new dataPoint
101+ apiData .Data = append (apiData .Data , newDataPoint )
102+ foundMetricId = true
103+ break
104+ }
105+ }
106+ // a apiData with the same metric Id doesn't exists, create a new one
107+ if ! foundMetricId {
108+ callsData [subjectId ] = append (callsData [subjectId ], newApiData )
109+ }
110+ } else {
111+ // this is a new subjectId, create a new callData
112+ callsData [subjectId ] = []* ApiData {newApiData }
113+ }
69114 }
70- converted := ApiData {metricId , data [1 ], []DataPoint {DataPoint {- secAgo , data [3 ]}}}
71- return & converted , nil
115+ return callsData , nil
72116}
73117
74118// InsertData inserts a batch of data. Returns the number of pending actions.
75- func (api * Api ) InsertData (data * ApiData ) (string , error ) {
119+ func (api * Api ) InsertData (data [] * ApiData ) (string , error ) {
76120 postData := map [string ][]string {
77- "source" : {data .SubjectID },
78- "data" : {apiDataToString ([]* ApiData {data })},
121+ "data" : {apiDataToString (data )},
79122 }
80123 var result string
81124 if err := api .makeCall ("POST" , fmt .Sprintf ("/api/v1/app/%s/data/" , api .appID ), postData , true , & result ); err != nil {
@@ -89,7 +132,14 @@ func (api *Api) InsertData(data *ApiData) (string, error) {
89132func getBatchData (start , stop int , metricId int64 , subjectIds , aggregator string , aggregateSubjects bool ) string {
90133 var buffer bytes.Buffer
91134 var now = int (time .Now ().Unix ())
92- buffer .WriteString (fmt .Sprintf (`{"start":%d, "stop":%d, "ids":[{"metricId":%d, "subjectIds":[` , now - start , now - stop , metricId ))
135+ // negative and null values are seconds ago
136+ if start <= 0 {
137+ start = now + start
138+ }
139+ if stop <= 0 {
140+ stop = now + stop
141+ }
142+ buffer .WriteString (fmt .Sprintf (`{"start":%d, "stop":%d, "ids":[{"metricId":%d, "subjectIds":[` , start , stop , metricId ))
93143 for i , id := range strings .Split (subjectIds , "," ) {
94144 if i > 0 {
95145 buffer .WriteString ("," )
0 commit comments