Skip to content

Commit 83c7460

Browse files
committed
Sync from Bitbucket
1 parent 9ad1761 commit 83c7460

File tree

8 files changed

+338
-42
lines changed

8 files changed

+338
-42
lines changed

build.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/bin/bash
2-
# Tip: to remove '\r' use sed -i 's/\r//g' build.sh
3-
export GOPATH=`pwd`/cli
2+
export GOPATH=`pwd`
43
mkdir -p bin
54
CGO_ENABLED=0 go build -a -tags netgo -ldflags '-w' -o bin/coscale-cli coscale

src/coscale/api/api.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ type Object interface {
1818
GetId() int64
1919
}
2020

21+
const (
22+
DEFAULT_STRING_VALUE string = `!>dUmmy<!`
23+
)
24+
2125
const (
2226
connectionTimeout time.Duration = 30 * time.Second
2327
readWriteTimeout time.Duration = 30 * time.Second

src/coscale/api/data.go

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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) {
89132
func 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(",")

src/coscale/api/event.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@ func (e Event) GetId() int64 {
1717
return e.ID
1818
}
1919

20+
// EventData describes the event data uploaded to api
21+
type EventData struct {
22+
ID int64
23+
Timestamp int64
24+
Stoptime int64
25+
Message string
26+
Attribute string
27+
Subject string
28+
Version int64
29+
UpdateTime int64
30+
}
31+
32+
func (e EventData) GetId() int64 {
33+
return e.ID
34+
}
35+
2036
func (api *Api) CreateEvent(name, description, attributeDescriptions, source, typeString string) (string, error) {
2137
data := map[string][]string{
2238
"name": {name},
@@ -58,6 +74,14 @@ func (api *Api) DeleteEvent(event *Event) error {
5874
return nil
5975
}
6076

77+
//GetEventData will return the eventdata by the event Id and eventdata Id
78+
func (api *Api) GetEventData(eventId, eventdataId int64, eventData *EventData) error {
79+
if err := api.makeCall("GET", fmt.Sprintf("/api/v1/app/%s/events/%d/data/get/%d/", api.appID, eventId, eventdataId), nil, false, &eventData); err != nil {
80+
return err
81+
}
82+
return nil
83+
}
84+
6185
func (api *Api) InsertEventData(id int64, message, subject, attribute string, timestamp, stopTime int64) (string, error) {
6286
data := map[string][]string{
6387
"message": {message},
@@ -73,10 +97,26 @@ func (api *Api) InsertEventData(id int64, message, subject, attribute string, ti
7397
return result, nil
7498
}
7599

76-
func (api *Api) GetEventData(id int64) (string, error) {
100+
func (api *Api) UpdateEventData(eventId, eventdataId int64, eventData *EventData) (string, error) {
101+
data := map[string][]string{
102+
"message": {eventData.Message},
103+
"timestamp": {fmt.Sprintf("%d", eventData.Timestamp)},
104+
"stopTime": {fmt.Sprintf("%d", eventData.Stoptime)},
105+
"subject": {eventData.Subject},
106+
"attribute": {eventData.Attribute},
107+
"version": {fmt.Sprintf("%d", eventData.Version)},
108+
}
77109
var result string
78-
if err := api.makeCall("GET", fmt.Sprintf("/api/v1/app/%s/events/%d/data/?start=1434431175", api.appID, id), nil, true, &result); err != nil {
110+
if err := api.makeCall("PUT", fmt.Sprintf("/api/v1/app/%s/events/%d/data/%d/", api.appID, eventId, eventData.ID), data, true, &result); err != nil {
79111
return "", err
80112
}
81113
return result, nil
82114
}
115+
116+
// DeleteEventData is used to delete a data entry for a event
117+
func (api *Api) DeleteEventData(eventId, eventdataId int64) error {
118+
if err := api.makeCall("DELETE", fmt.Sprintf("/api/v1/app/%s/events/%d/data/%d/", api.appID, eventId, eventdataId), nil, false, nil); err != nil {
119+
return err
120+
}
121+
return nil
122+
}

src/coscale/command/command.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
)
2020

2121
const (
22-
DEFAULT_FLAG_VALUE string = `!>dUmmy<!`
22+
DEFAULT_FLAG_VALUE string = api.DEFAULT_STRING_VALUE
2323
)
2424

2525
const (
@@ -34,6 +34,7 @@ type Command struct {
3434
Name string
3535
UsageLine string
3636
Long string
37+
Deprecated bool
3738
SubCommands []*Command
3839
Capi *api.Api //api connector
3940
Flag flag.FlagSet
@@ -176,9 +177,9 @@ Usage:
176177
177178
{{.Long | trim}}{{else}}
178179
{{.Name | printf "Actions for command \"%s\":"}}
179-
{{range .SubCommands}}
180+
{{range .SubCommands}}{{if not .Deprecated}}
180181
{{.Name | printf "%s"}}
181-
{{.UsageLine | printf "%-11s"}}{{end}}
182+
{{.UsageLine | printf "%-11s"}}{{end}}{{end}}
182183
{{end}}
183184
184185
The json objects are returned formatted by default, but can be returned on 1 line by using:

src/coscale/command/data.go

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,30 +52,76 @@ Optional:
5252
},
5353
{
5454
Name: "insert",
55-
UsageLine: `data insert (--datapoint)`,
55+
UsageLine: `data insert (--data)`,
5656
Long: `
57-
Create new EventData for a given event.
57+
Insert data for metrics into the datastore.
5858
59-
The flags for data event action are:
59+
The flags for data insert action are:
6060
Mandatory:
61+
--data
62+
To send data for DOUBLE metric data typ use the following format:
63+
"M<metric id>:S<subject Id>:<time>:<value/s>"
64+
eg: --data="M1:S100:1454580954:1.2
65+
66+
To send data for HISTOGRAM metric data type use the following format:
67+
"M<metric id>:S<subject Id>:<seconds ago>:[<no of samples>,<percentile width>,[<percentile data>]]"
68+
eg: --data="M1:S1:-60:[100,50,[1,2,3,4,5,6]]"
69+
70+
Sending multiple data entries is possible by using semicolon as separator.
71+
eg: --data="M1:S100:-60:1.2;M1:S100:0:2"
72+
73+
The time is formatted as follows:
74+
Positive numbers are interpreted as unix timestamps in seconds.
75+
Zero is interpreted as the current time.
76+
Negative numbers are interpreted as a seconds ago from the current time.
77+
78+
Deprecated:
6179
--datapoint
62-
Data format is:"M<metric id>:<subject Id>:<seconds ago>:<value/s>" eg:"M1:S100:120:1,2"
80+
To send data for DOUBLE metric data typ use the following format:
81+
"M<metric id>:S<subject Id>:<seconds ago>:<value/s>"
82+
eg: --datapoint="M1:S100:120:1.2
83+
84+
To send data for HISTOGRAM metric data type use the following format:
85+
"M<metric id>:S<subject Id>:<seconds ago>:[<no of samples>,<percentile width>,[<percentile data>]]"
86+
eg: --datapoint="M1:S1:60:[100,50,[1,2,3,4,5,6]]"
6387
`,
6488
Run: func(cmd *Command, args []string) {
6589
var datapoint string
90+
var data string
91+
6692
cmd.Flag.Usage = func() { cmd.PrintUsage() }
93+
6794
cmd.Flag.StringVar(&datapoint, "datapoint", DEFAULT_FLAG_VALUE, "")
95+
cmd.Flag.StringVar(&data, "data", DEFAULT_FLAG_VALUE, "")
6896
cmd.ParseArgs(args)
69-
if datapoint == DEFAULT_FLAG_VALUE {
97+
98+
if datapoint == DEFAULT_FLAG_VALUE && data == DEFAULT_FLAG_VALUE {
7099
cmd.PrintUsage()
71100
os.Exit(EXIT_FLAG_ERROR)
72101
}
73-
data, err := api.ParseDataPoint(datapoint)
102+
103+
timeInSecAgo := false
104+
if data == DEFAULT_FLAG_VALUE {
105+
timeInSecAgo = true
106+
data = datapoint
107+
}
108+
109+
// ParseDataPoint coult return data for multiple calls for same metricIDs with different subjectID
110+
callsData, err := api.ParseDataPoint(data, timeInSecAgo)
74111
if err != nil {
75112
cmd.PrintUsage()
76113
os.Exit(EXIT_FLAG_ERROR)
77114
}
78-
cmd.PrintResult(cmd.Capi.InsertData(data))
115+
var result string
116+
var resErr error
117+
// if datapoint contain multiple subject id, then we will have multiple api calls
118+
for _, callData := range callsData {
119+
result, resErr = cmd.Capi.InsertData(callData)
120+
if resErr != nil {
121+
break
122+
}
123+
}
124+
cmd.PrintResult(result, resErr)
79125
},
80126
},
81127
}

0 commit comments

Comments
 (0)