Codebase list golang-github-bluebreezecf-opentsdb-goclient / 47b887e
New upstream version 0.0~git20160515.0.539764b Tim Potter 7 years ago
18 changed file(s) with 3059 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Apache License
1
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by the
13 copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all other
16 entities that control, are controlled by, or are under common control
17 with that entity. For the purposes of this definition, "control" means
18 (i) the power, direct or indirect, to cause the direction or management
19 of such entity, whether by contract or otherwise, or (ii) ownership
20 of fifty percent (50%) or more of the outstanding shares, or (iii)
21 beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity exercising
24 permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation source,
28 and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical transformation
31 or translation of a Source form, including but not limited to compiled
32 object code, generated documentation, and conversions to other media
33 types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a copyright
37 notice that is included in or attached to the work (an example is provided
38 in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object form,
41 that is based on (or derived from) the Work and for which the editorial
42 revisions, annotations, elaborations, or other modifications represent,
43 as a whole, an original work of authorship. For the purposes of this
44 License, Derivative Works shall not include works that remain separable
45 from, or merely link (or bind by name) to the interfaces of, the Work
46 and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including the
49 original version of the Work and any modifications or additions to
50 that Work or Derivative Works thereof, that is intentionally submitted
51 to Licensor for inclusion in the Work by the copyright owner or by an
52 individual or Legal Entity authorized to submit on behalf of the copyright
53 owner. For the purposes of this definition, "submitted" means any form of
54 electronic, verbal, or written communication sent to the Licensor or its
55 representatives, including but not limited to communication on electronic
56 mailing lists, source code control systems, and issue tracking systems
57 that are managed by, or on behalf of, the Licensor for the purpose of
58 discussing and improving the Work, but excluding communication that is
59 conspicuously marked or otherwise designated in writing by the copyright
60 owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License.
67 Subject to the terms and conditions of this License, each Contributor
68 hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,
69 royalty-free, irrevocable copyright license to reproduce, prepare
70 Derivative Works of, publicly display, publicly perform, sublicense, and
71 distribute the Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License.
74 Subject to the terms and conditions of this License, each Contributor
75 hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,
76 royalty- free, irrevocable (except as stated in this section) patent
77 license to make, have made, use, offer to sell, sell, import, and
78 otherwise transfer the Work, where such license applies only to those
79 patent claims licensable by such Contributor that are necessarily
80 infringed by their Contribution(s) alone or by combination of
81 their Contribution(s) with the Work to which such Contribution(s)
82 was submitted. If You institute patent litigation against any entity
83 (including a cross-claim or counterclaim in a lawsuit) alleging that the
84 Work or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses granted
86 to You under this License for that Work shall terminate as of the date
87 such litigation is filed.
88
89 4. Redistribution.
90 You may reproduce and distribute copies of the Work or Derivative Works
91 thereof in any medium, with or without modifications, and in Source or
92 Object form, provided that You meet the following conditions:
93
94 a. You must give any other recipients of the Work or Derivative Works
95 a copy of this License; and
96
97 b. You must cause any modified files to carry prominent notices stating
98 that You changed the files; and
99
100 c. You must retain, in the Source form of any Derivative Works that
101 You distribute, all copyright, patent, trademark, and attribution
102 notices from the Source form of the Work, excluding those notices
103 that do not pertain to any part of the Derivative Works; and
104
105 d. If the Work includes a "NOTICE" text file as part of its
106 distribution, then any Derivative Works that You distribute must
107 include a readable copy of the attribution notices contained
108 within such NOTICE file, excluding those notices that do not
109 pertain to any part of the Derivative Works, in at least one of
110 the following places: within a NOTICE text file distributed as part
111 of the Derivative Works; within the Source form or documentation,
112 if provided along with the Derivative Works; or, within a display
113 generated by the Derivative Works, if and wherever such third-party
114 notices normally appear. The contents of the NOTICE file are for
115 informational purposes only and do not modify the License. You
116 may add Your own attribution notices within Derivative Works that
117 You distribute, alongside or as an addendum to the NOTICE text
118 from the Work, provided that such additional attribution notices
119 cannot be construed as modifying the License. You may add Your own
120 copyright statement to Your modifications and may provide additional
121 or different license terms and conditions for use, reproduction, or
122 distribution of Your modifications, or for any such Derivative Works
123 as a whole, provided Your use, reproduction, and distribution of the
124 Work otherwise complies with the conditions stated in this License.
125
126 5. Submission of Contributions.
127 Unless You explicitly state otherwise, any Contribution intentionally
128 submitted for inclusion in the Work by You to the Licensor shall be
129 under the terms and conditions of this License, without any additional
130 terms or conditions. Notwithstanding the above, nothing herein shall
131 supersede or modify the terms of any separate license agreement you may
132 have executed with Licensor regarding such Contributions.
133
134 6. Trademarks.
135 This License does not grant permission to use the trade names, trademarks,
136 service marks, or product names of the Licensor, except as required for
137 reasonable and customary use in describing the origin of the Work and
138 reproducing the content of the NOTICE file.
139
140 7. Disclaimer of Warranty.
141 Unless required by applicable law or agreed to in writing, Licensor
142 provides the Work (and each Contributor provides its Contributions) on
143 an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
144 express or implied, including, without limitation, any warranties or
145 conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR
146 A PARTICULAR PURPOSE. You are solely responsible for determining the
147 appropriateness of using or redistributing the Work and assume any risks
148 associated with Your exercise of permissions under this License.
149
150 8. Limitation of Liability.
151 In no event and under no legal theory, whether in tort (including
152 negligence), contract, or otherwise, unless required by applicable law
153 (such as deliberate and grossly negligent acts) or agreed to in writing,
154 shall any Contributor be liable to You for damages, including any direct,
155 indirect, special, incidental, or consequential damages of any character
156 arising as a result of this License or out of the use or inability to
157 use the Work (including but not limited to damages for loss of goodwill,
158 work stoppage, computer failure or malfunction, or any and all other
159 commercial damages or losses), even if such Contributor has been advised
160 of the possibility of such damages.
161
162 9. Accepting Warranty or Additional Liability.
163 While redistributing the Work or Derivative Works thereof, You may
164 choose to offer, and charge a fee for, acceptance of support, warranty,
165 indemnity, or other liability obligations and/or rights consistent with
166 this License. However, in accepting such obligations, You may act only
167 on Your own behalf and on Your sole responsibility, not on behalf of
168 any other Contributor, and only if You agree to indemnify, defend, and
169 hold each Contributor harmless for any liability incurred by, or claims
170 asserted against, such Contributor by reason of your accepting any such
171 warranty or additional liability.
172
173 END OF TERMS AND CONDITIONS
0 ##opentsdb-goclient
1
2 ###Backgroud
3 OpenTSDB is a distributed, scalable Time Series Database (TSDB) written on top of HBase.
4 OpenTSDB was written to address a common need: store, index and serve metrics collected
5 from computer systems (network gear, operating systems, applications) at a large scale,
6 and make this data easily accessible and graphable.
7
8 I am about to use OpenTSDB, but currently there is no useable go-sdk for OpenTSDB. So I
9 develop the opentsdb-goclient for convenience according to the [OpenTSDB Rest API Doc] (http://opentsdb.net/docs/build/html/api_http/index.html#api-endpoints)
10
11 ###How to use sample
12 If you want to see how does the sample (sample.go) run, you can execute the following commands:
13 ```shell
14 cd $GOPATH
15 mkdir -p $GOPATH/src/github.com/bluebreezecf
16 cd $GOPATH/src/github.com/bluebreezecf
17 git clone https://github.com/bluebreezecf/opentsdb-goclient.git
18
19 vi sample.go //Use the real host and port of an existing OpenTSDB in Line 33: OpentsdbHost: "127.0.0.1:4242"
20 go run sample.go
21
22 ```
23
24 ###Current supporting rest apis
25 ```shell
26 GET /api/aggregators
27 GET,POST,DELETE /api/annotation
28 POST,DELETE /api/annotation/bulk
29 GET /api/config
30 GET /api/dropcaches
31 POST /api/put
32 GET /api/query
33 GET /api/query/last
34 GET /api/serializers
35 GET /api/stats
36 GET /api/suggest
37 POST /api/uid/assign
38 GET,POST,DELETE /api/uid/tsmeta
39 GET,POST,DELETE /api/uid/uidmeta
40 GET /api/version
41 ```
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // aggregators.go contains the structs and methods for the implementation of /api/aggregators.
19 //
20 package client
21
22 import (
23 "bytes"
24 "encoding/json"
25 "fmt"
26 )
27
28 // AggregatorsResponse acts as the implementation of Response in the /api/aggregators scene.
29 // It holds the status code and the response values defined in the
30 // (http://opentsdb.net/docs/build/html/api_http/aggregators.html).
31 //
32 type AggregatorsResponse struct {
33 StatusCode int
34 Aggregators []string `json:"aggregators"`
35 }
36
37 func (aggreResp *AggregatorsResponse) SetStatus(code int) {
38 aggreResp.StatusCode = code
39 }
40
41 func (aggreResp *AggregatorsResponse) GetCustomParser() func(respCnt []byte) error {
42 return func(respCnt []byte) error {
43 return json.Unmarshal([]byte(fmt.Sprintf("{%s:%s}", `"aggregators"`, string(respCnt))), &aggreResp)
44 }
45 }
46
47 func (aggreResp *AggregatorsResponse) String() string {
48 buffer := bytes.NewBuffer(nil)
49 content, _ := json.Marshal(aggreResp)
50 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
51 return buffer.String()
52 }
53
54 func (c *clientImpl) Aggregators() (*AggregatorsResponse, error) {
55 aggregatorsEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, AggregatorPath)
56 aggreResp := AggregatorsResponse{}
57 if err := c.sendRequest(GetMethod, aggregatorsEndpoint, "", &aggreResp); err != nil {
58 return nil, err
59 }
60 return &aggreResp, nil
61 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // annotation.go contains the structs and methods for the implementation of
19 // /api/annotation and /api/annotation/bulk.
20 //
21 package client
22
23 import (
24 "bytes"
25 "encoding/json"
26 "errors"
27 "fmt"
28 "strings"
29 )
30
31 // Annotation is the structure used to hold
32 // the querying parameters when calling /api/annotation.
33 // Each attributes in Annotation matches the definition in
34 // (http://opentsdb.net/docs/build/html/api_http/annotation/index.html).
35 //
36 // Annotations are very basic objects used to record a note of an arbitrary
37 // event at some point, optionally associated with a timeseries. Annotations
38 // are not meant to be used as a tracking or event based system, rather they
39 // are useful for providing links to such systems by displaying a notice on
40 // graphs or via API query calls.
41 //
42 type Annotation struct {
43 // A Unix epoch timestamp, in seconds, marking the time when the annotation event should be recorded.
44 // The value is required with non-zero value.
45 StartTime int64 `json:"startTime,omitempty"`
46
47 // An optional end time for the event if it has completed or been resolved.
48 EndTime int64 `json:"endTime,omitempty"`
49
50 // A TSUID if the annotation is associated with a timeseries.
51 // This may be optional if the note was for a global event
52 Tsuid string `json:"tsuid,omitempty"`
53
54 // An optional brief description of the event. As this may appear on GnuPlot graphs,
55 // the description should be very short, ideally less than 25 characters.
56 Description string `json:"description,omitempty"`
57
58 // An optional detailed notes about the event
59 Notes string `json:"notes,omitempty"`
60
61 // An optional key/value map to store custom fields and values
62 Custom map[string]string `json:"custom,omitempty"`
63 }
64
65 // AnnotationResponse acts as the implementation of Response in the /api/annotation scene.
66 // It holds the status code and the response values defined in the
67 // (http://opentsdb.net/docs/build/html/api_http/aggregators.html).
68 //
69 type AnnotationResponse struct {
70 StatusCode int
71 Annotation
72 ErrorInfo map[string]interface{} `json:"error,omitempty"`
73 }
74
75 func (annotResp *AnnotationResponse) SetStatus(code int) {
76 annotResp.StatusCode = code
77 }
78
79 func (annotResp *AnnotationResponse) GetCustomParser() func(respCnt []byte) error {
80 return func(respCnt []byte) error {
81 originContents := string(respCnt)
82 var resultBytes []byte
83 if strings.Contains(originContents, "startTime") ||
84 strings.Contains(originContents, "error") {
85 resultBytes = respCnt
86 } else if annotResp.StatusCode == 204 {
87 // The OpenTSDB deletes an annotation successfully and with no body content.
88 return nil
89 }
90 return json.Unmarshal(resultBytes, &annotResp)
91 }
92 }
93
94 func (annotResp *AnnotationResponse) String() string {
95 buffer := bytes.NewBuffer(nil)
96 content, _ := json.Marshal(annotResp)
97 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
98 return buffer.String()
99 }
100
101 func (c *clientImpl) QueryAnnotation(queryAnnoParam map[string]interface{}) (*AnnotationResponse, error) {
102 if queryAnnoParam == nil || len(queryAnnoParam) == 0 {
103 return nil, errors.New("The given query annotation param is nil")
104 }
105 buffer := bytes.NewBuffer(nil)
106 size := len(queryAnnoParam)
107 i := 0
108 for k, v := range queryAnnoParam {
109 buffer.WriteString(fmt.Sprintf("%s=%v", k, v))
110 if i < size-1 {
111 buffer.WriteString("&")
112 } else {
113 break
114 }
115 i++
116 }
117 annoEndpoint := fmt.Sprintf("%s%s?%s", c.tsdbEndpoint, AnnotationPath, buffer.String())
118 annResp := AnnotationResponse{}
119 if err := c.sendRequest(GetMethod, annoEndpoint, "", &annResp); err != nil {
120 return nil, err
121 }
122 return &annResp, nil
123 }
124
125 func (c *clientImpl) UpdateAnnotation(annotation Annotation) (*AnnotationResponse, error) {
126 return c.operateAnnotation(PostMethod, &annotation)
127 }
128
129 func (c *clientImpl) DeleteAnnotation(annotation Annotation) (*AnnotationResponse, error) {
130 return c.operateAnnotation(DeleteMethod, &annotation)
131 }
132
133 func (c *clientImpl) operateAnnotation(method string, annotation *Annotation) (*AnnotationResponse, error) {
134 if !c.isValidOperateMethod(method) {
135 return nil, errors.New("The given method for operating an annotation is invalid.")
136 }
137 annoEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, AnnotationPath)
138 resultBytes, err := json.Marshal(annotation)
139 if err != nil {
140 return nil, errors.New(fmt.Sprintf("Failed to marshal annotation: %v", err))
141 }
142 annResp := AnnotationResponse{}
143 if err = c.sendRequest(method, annoEndpoint, string(resultBytes), &annResp); err != nil {
144 return nil, err
145 }
146 return &annResp, nil
147 }
148
149 // BulkAnnotatResponse acts as the implementation of Response in the /api/annotation/bulk scene.
150 // It holds the status code and the response values defined in the
151 // (http://opentsdb.net/docs/build/html/api_http/annotation/bulk.html)
152 // for both bulk update and delete scenes.
153 //
154 type BulkAnnotatResponse struct {
155 StatusCode int
156 UpdateAnnotations []Annotation `json:"InvolvedAnnotations,omitempty"`
157 ErrorInfo map[string]interface{} `json:"error,omitempty"`
158 BulkDeleteResp
159 }
160
161 type BulkAnnoDeleteInfo struct {
162 // A list of TSUIDs with annotations that should be deleted. This may be empty
163 // or null (for JSON) in which case the global flag should be set.
164 Tsuids []string `json:"tsuids,omitempty"`
165
166 // A timestamp for the start of the request.
167 StartTime int64 `json:"startTime,omitempty"`
168
169 // An optional end time for the event if it has completed or been resolved.
170 EndTime int64 `json:"endTime,omitempty"`
171
172 // An optional flag indicating whether or not global annotations should be deleted for the range
173 Global bool `json:"global,omitempty"`
174 }
175
176 type BulkDeleteResp struct {
177 BulkAnnoDeleteInfo
178
179 // Total number of annotations to be deleted successfully for current bulk
180 // delete operation. The value is only used in the reponse of bulk deleting,
181 // not in the bulk deleting parameters.
182 TotalDeleted int64 `json:"totalDeleted,omitempty"`
183 }
184
185 func (bulkAnnotResp *BulkAnnotatResponse) SetStatus(code int) {
186 bulkAnnotResp.StatusCode = code
187 }
188
189 func (bulkAnnotResp *BulkAnnotatResponse) GetCustomParser() func(respCnt []byte) error {
190 return func(respCnt []byte) error {
191 originContents := string(respCnt)
192 var resultBytes []byte
193 if strings.Contains(originContents, "startTime") {
194 resultBytes = []byte(fmt.Sprintf("{%s:%s}", `"InvolvedAnnotations"`, originContents))
195 } else if strings.Contains(originContents, "error") || strings.Contains(originContents, "totalDeleted") {
196 resultBytes = respCnt
197 } else {
198 return errors.New(fmt.Sprintf("Unrecognized bulk annotation response info: %s", originContents))
199 }
200 return json.Unmarshal(resultBytes, &bulkAnnotResp)
201 }
202 }
203
204 func (bulkAnnotResp *BulkAnnotatResponse) String() string {
205 buffer := bytes.NewBuffer(nil)
206 content, _ := json.Marshal(bulkAnnotResp)
207 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
208 return buffer.String()
209 }
210
211 func (c *clientImpl) BulkUpdateAnnotations(annotations []Annotation) (*BulkAnnotatResponse, error) {
212 if annotations == nil || len(annotations) == 0 {
213 return nil, errors.New("The given annotations are empty.")
214 }
215 bulkAnnoEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, BulkAnnotationPath)
216 reqBodyCnt, err := marshalAnnotations(annotations)
217 if err != nil {
218 return nil, errors.New(fmt.Sprintf("Failed to marshal annotations: %v", err))
219 }
220 bulkAnnoResp := BulkAnnotatResponse{}
221 if err = c.sendRequest(PostMethod, bulkAnnoEndpoint, reqBodyCnt, &bulkAnnoResp); err != nil {
222 return nil, err
223 }
224 return &bulkAnnoResp, nil
225 }
226
227 func (c *clientImpl) BulkDeleteAnnotations(bulkDelParam BulkAnnoDeleteInfo) (*BulkAnnotatResponse, error) {
228 bulkAnnoEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, BulkAnnotationPath)
229 resultBytes, err := json.Marshal(bulkDelParam)
230 if err != nil {
231 return nil, errors.New(fmt.Sprintf("Failed to marshal bulk delete param: %v", err))
232 }
233 bulkAnnoResp := BulkAnnotatResponse{}
234 if err = c.sendRequest(DeleteMethod, bulkAnnoEndpoint, string(resultBytes), &bulkAnnoResp); err != nil {
235 return nil, err
236 }
237 return &bulkAnnoResp, nil
238 }
239
240 func marshalAnnotations(annotations []Annotation) (string, error) {
241 buffer := bytes.NewBuffer(nil)
242 size := len(annotations)
243 buffer.WriteString("[")
244 for index, item := range annotations {
245 result, err := json.Marshal(item)
246 if err != nil {
247 return "", err
248 }
249 buffer.Write(result)
250 if index < size-1 {
251 buffer.WriteString(",")
252 }
253 }
254 buffer.WriteString("]")
255 return buffer.String(), nil
256 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // client.go contains the global interface and implementation struct
19 // definition of the OpenTSDB Client, as well as the common private
20 // and public methods used by all the rest-api implementation files,
21 // whose names are just like put.go, query.go, and so on.
22 //
23 package client
24
25 import (
26 "encoding/json"
27 "errors"
28 "fmt"
29 "io/ioutil"
30 "net"
31 "net/http"
32 "strings"
33 "time"
34
35 "github.com/bluebreezecf/opentsdb-goclient/config"
36 )
37
38 const (
39 DefaultDialTimeout = 5 * time.Second
40 KeepAliveTimeout = 30 * time.Second
41 GetMethod = "GET"
42 PostMethod = "POST"
43 PutMethod = "PUT"
44 DeleteMethod = "DELETE"
45
46 PutPath = "/api/put"
47 PutRespWithSummary = "summary"
48 PutRespWithDetails = "details"
49
50 QueryPath = "/api/query"
51 QueryLastPath = "/api/query/last"
52 // The three keys in the rateOption parameter of the QueryParam
53 QueryRateOptionCounter = "counter" // The corresponding value type is bool
54 QueryRateOptionCounterMax = "counterMax" // The corresponding value type is int,int64
55 QueryRateOptionResetValue = "resetValue" // The corresponding value type is int,int64
56
57 AggregatorPath = "/api/aggregators"
58 ConfigPath = "/api/config"
59 SerializersPath = "/api/serializers"
60 StatsPath = "/api/stats"
61 SuggestPath = "/api/suggest"
62 // Only the one of the three query type can be used in SuggestParam, UIDMetaData:
63 TypeMetrics = "metrics"
64 TypeTagk = "tagk"
65 TypeTagv = "tagv"
66
67 VersionPath = "/api/version"
68 DropcachesPath = "/api/dropcaches"
69 AnnotationPath = "/api/annotation"
70 AnQueryStartTime = "start_time"
71 AnQueryTSUid = "tsuid"
72 BulkAnnotationPath = "/api/annotation/bulk"
73 UIDMetaDataPath = "/api/uid/uidmeta"
74 UIDAssignPath = "/api/uid/assign"
75 TSMetaDataPath = "/api/uid/tsmeta"
76
77 // The above three constants are used in /put
78 DefaultMaxPutPointsNum = 75
79 DefaultDetectDeltaNum = 3
80 // Unit is bytes, and assumes that config items of 'tsd.http.request.enable_chunked = true'
81 // and 'tsd.http.request.max_chunk = 40960' are all in the opentsdb.conf:
82 DefaultMaxContentLength = 40960
83 )
84
85 var (
86 DefaultTransport = &http.Transport{
87 MaxIdleConnsPerHost: 10,
88 Dial: (&net.Dialer{
89 Timeout: DefaultDialTimeout,
90 KeepAlive: KeepAliveTimeout,
91 }).Dial,
92 }
93 )
94
95 // Client defines the sdk methods, by which other go applications can
96 // commnicate with the OpenTSDB via the pre-defined rest-apis.
97 // Each method defined in the interface of Client is in the correspondance
98 // a rest-api definition in (http://opentsdb.net/docs/build/html/api_http/index.html#api-endpoints).
99 type Client interface {
100
101 // Ping detects whether the target OpenTSDB is reachable or not.
102 // If error occurs during the detection, an error instance will be returned, or nil otherwise.
103 Ping() error
104
105 // Put is the implementation of 'POST /api/put' endpoint.
106 // This endpoint allows for storing data in OpenTSDB over HTTP as an alternative to the Telnet interface.
107 //
108 // datas is a slice of DataPoint holding at least one instance.
109 // queryParam can only be github.com/bluebreezecf/opentsdb-goclient/client.PutRespWithSummary,
110 // github.com/bluebreezecf/opentsdb-goclient/client.PutRespWithDetails or the empty string "";
111 // It means get put summary response info by using PutRespWithSummary, and
112 // with PutRespWithDetails means get put detailed response.
113 //
114 // When put operation is successful, a pointer of PutResponse will be returned with the corresponding
115 // status code and response info. Otherwise, an error instance will be returned, when the given parameters
116 // are invalid, it failed to parese the response, or OpenTSDB is un-connectable right now.
117 Put(datas []DataPoint, queryParam string) (*PutResponse, error)
118
119 // Query is the implementation of 'GET /api/query' endpoint.
120 // It is probably the most useful endpoint in the API, /api/query enables extracting data from the storage
121 // system in various formats determined by the serializer selected.
122 //
123 // param is a instance of QueryParam holding current query parameters.
124 //
125 // When query operation is successful, a pointer of QueryResponse will be returned with the corresponding
126 // status code and response info. Otherwise, an error instance will be returned, when the given parameter
127 // is invalid, it failed to parese the response, or OpenTSDB is un-connectable right now.
128 Query(param QueryParam) (*QueryResponse, error)
129
130 // QueryLast is the implementation of 'GET /api/query/last' endpoint.
131 // It is introduced firstly in v2.1, and fully supported in v2.2. So it should be aware that this api works
132 // well since v2.2 of opentsdb.
133 //
134 // param is a instance of QueryLastParam holding current query parameters.
135 //
136 // When query operation is successful, a pointer of QueryLastResponse will be returned with the corresponding
137 // status code and response info. Otherwise, an error instance will be returned, when the given parameter
138 // is invalid, it failed to parese the response, or OpenTSDB is un-connectable right now.
139 QueryLast(param QueryLastParam) (*QueryLastResponse, error)
140
141 // Aggregators is the implementation of 'GET /api/aggregators' endpoint.
142 // It simply lists the names of implemented aggregation functions used in timeseries queries.
143 //
144 // When query operation is successful, a pointer of AggregatorsResponse will be returned with the corresponding
145 // status code and response info. Otherwise, an error instance will be returned, when it failed to parese the
146 // response, or OpenTSDB is un-connectable right now.
147 Aggregators() (*AggregatorsResponse, error)
148
149 // Config is the implementation of 'GET /api/config' endpoint.
150 // It returns information about the running configuration of the TSD.
151 // It is read only and cannot be used to set configuration options.
152 //
153 // When query operation is successful, a pointer of ConfigResponse will be returned with the corresponding
154 // status code and response info. Otherwise, an error instance will be returned, when it failed to parese the
155 // response, or OpenTSDB is un-connectable right now.
156 Config() (*ConfigResponse, error)
157
158 // Serializers is the implementation of 'GET /api/serializers' endpoint.
159 // It lists the serializer plugins loaded by the running TSD. Information given includes the name,
160 // implemented methods, content types and methods.
161 //
162 // When query operation is successful, a pointer of SerialResponse will be returned with the corresponding
163 // status code and response info. Otherwise, an error instance will be returned, when it failed to parese the
164 // response, or OpenTSDB is un-connectable right now.
165 Serializers() (*SerialResponse, error)
166
167 // Stats is the implementation of 'GET /api/stats' endpoint.
168 // It provides a list of statistics for the running TSD. These statistics are automatically recorded
169 // by a running TSD every 5 minutes but may be accessed via this endpoint. All statistics are read only.
170 //
171 // When query operation is successful, a pointer of StatsResponse will be returned with the corresponding
172 // status code and response info. Otherwise, an error instance will be returned, when it failed to parese the
173 // response, or OpenTSDB is un-connectable right now.
174 Stats() (*StatsResponse, error)
175
176 // Suggest is the implementation of 'GET /api/suggest' endpoint.
177 // It provides a means of implementing an "auto-complete" call that can be accessed repeatedly as a user
178 // types a request in a GUI. It does not offer full text searching or wildcards, rather it simply matches
179 // the entire string passed in the query on the first characters of the stored data.
180 // For example, passing a query of type=metrics&q=sys will return the top 25 metrics in the system that start with sys.
181 // Matching is case sensitive, so sys will not match System.CPU. Results are sorted alphabetically.
182 //
183 // sugParm is an instance of SuggestParam storing parameters by invoking /api/suggest.
184 //
185 // When query operation is successful, a pointer of SuggestResponse will be returned with the corresponding
186 // status code and response info. Otherwise, an error instance will be returned, if the given parameter is invalid,
187 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
188 Suggest(sugParm SuggestParam) (*SuggestResponse, error)
189
190 // Version is the implementation of 'GET /api/version' endpoint.
191 // It returns information about the running version of OpenTSDB.
192 //
193 // When query operation is successful, a pointer of VersionResponse will be returned with the corresponding
194 // status code and response info. Otherwise, an error instance will be returned, when it failed to parese the
195 // response, or OpenTSDB is un-connectable right now.
196 Version() (*VersionResponse, error)
197
198 // Dropcaches is the implementation of 'GET /api/dropcaches' endpoint.
199 // It purges the in-memory data cached in OpenTSDB. This includes all UID to name
200 // and name to UID maps for metrics, tag names and tag values.
201 //
202 // When query operation is successful, a pointer of DropcachesResponse will be returned with the corresponding
203 // status code and response info. Otherwise, an error instance will be returned, when it failed to parese the
204 // response, or OpenTSDB is un-connectable right now.
205 Dropcaches() (*DropcachesResponse, error)
206
207 // QueryAnnotation is the implementation of 'GET /api/annotation' endpoint.
208 // It retrieves a single annotation stored in the OpenTSDB backend.
209 //
210 // queryAnnoParam is a map storing parameters of a target queried annotation.
211 // The key can be such as client.AnQueryStartTime, client.AnQueryTSUid.
212 //
213 // When query operation is handlering properly by the OpenTSDB backend, a pointer of AnnotationResponse
214 // will be returned with the corresponding status code and response info (including the potential error
215 // messages replied by OpenTSDB).
216 //
217 // Otherwise, an error instance will be returned, if the given parameter is invalid,
218 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
219 //
220 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
221 QueryAnnotation(queryAnnoParam map[string]interface{}) (*AnnotationResponse, error)
222
223 // UpdateAnnotation is the implementation of 'POST /api/annotation' endpoint.
224 // It creates or modifies an annotation stored in the OpenTSDB backend.
225 //
226 // annotation is an annotation to be processed in the OpenTSDB backend.
227 //
228 // When modification operation is handlering properly by the OpenTSDB backend, a pointer of AnnotationResponse
229 // will be returned with the corresponding status code and response info (including the potential error
230 // messages replied by OpenTSDB).
231 //
232 // Otherwise, an error instance will be returned, if the given parameter is invalid,
233 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
234 //
235 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
236 UpdateAnnotation(annotation Annotation) (*AnnotationResponse, error)
237
238 // DeleteAnnotation is the implementation of 'DELETE /api/annotation' endpoint.
239 // It deletes an annotation stored in the OpenTSDB backend.
240 //
241 // annotation is an annotation to be deleted in the OpenTSDB backend.
242 //
243 // When deleting operation is handlering properly by the OpenTSDB backend, a pointer of AnnotationResponse
244 // will be returned with the corresponding status code and response info (including the potential error
245 // messages replied by OpenTSDB).
246 //
247 // Otherwise, an error instance will be returned, if the given parameter is invalid,
248 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
249 //
250 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
251 DeleteAnnotation(annotation Annotation) (*AnnotationResponse, error)
252
253 // BulkUpdateAnnotations is the implementation of 'POST /api/annotation/bulk' endpoint.
254 // It creates or modifies a list of annotation stored in the OpenTSDB backend.
255 //
256 // annotations is a list of annotations to be processed (to be created or modified) in the OpenTSDB backend.
257 //
258 // When bulk modification operation is handlering properly by the OpenTSDB backend, a pointer of BulkAnnotatResponse
259 // will be returned with the corresponding status code and response info (including the potential error
260 // messages replied by OpenTSDB).
261 //
262 // Otherwise, an error instance will be returned, if the given parameter is invalid,
263 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
264 //
265 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
266 BulkUpdateAnnotations(annotations []Annotation) (*BulkAnnotatResponse, error)
267
268 // BulkDeleteAnnotations is the implementation of 'DELETE /api/annotation/bulk' endpoint.
269 // It deletes a list of annotation stored in the OpenTSDB backend.
270 //
271 // bulkDelParam contains the bulk deleting info in current invoking 'DELETE /api/annotation/bulk'.
272 //
273 // When bulk deleting operation is handlering properly by the OpenTSDB backend, a pointer of BulkAnnotatResponse
274 // will be returned with the corresponding status code and response info (including the potential error
275 // messages replied by OpenTSDB).
276 //
277 // Otherwise, an error instance will be returned, if the given parameter is invalid,
278 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
279 //
280 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
281 BulkDeleteAnnotations(bulkDelParam BulkAnnoDeleteInfo) (*BulkAnnotatResponse, error)
282
283 // QueryUIDMetaData is the implementation of 'GET /api/uid/uidmeta' endpoint.
284 // It retrieves a single UIDMetaData stored in the OpenTSDB backend with the given query parameters.
285 //
286 // metaQueryParam is a map storing parameters of a target queried UIDMetaData.
287 // It must contain two key/value pairs with the key "uid" and "type".
288 // "type" should be one of client.TypeMetrics ("metric"), client.TypeTagk ("tagk"), and client.TypeTagv ("tagv")
289 //
290 // When query operation is handlering properly by the OpenTSDB backend, a pointer of UIDMetaDataResponse
291 // will be returned with the corresponding status code and response info (including the potential error
292 // messages replied by OpenTSDB).
293 //
294 // Otherwise, an error instance will be returned, if the given parameter is invalid,
295 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
296 //
297 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
298 QueryUIDMetaData(metaQueryParam map[string]string) (*UIDMetaDataResponse, error)
299
300 // UpdateUIDMetaData is the implementation of 'POST /api/uid/uidmeta' endpoint.
301 // It modifies a UIDMetaData.
302 //
303 // uidMetaData is an instance of UIDMetaData to be modified
304 //
305 // When update operation is handlering properly by the OpenTSDB backend, a pointer of UIDMetaDataResponse
306 // will be returned with the corresponding status code and response info (including the potential error
307 // messages replied by OpenTSDB).
308 //
309 // Otherwise, an error instance will be returned, if the given parameter is invalid,
310 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
311 //
312 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
313 UpdateUIDMetaData(uidMetaData UIDMetaData) (*UIDMetaDataResponse, error)
314
315 // DeleteUIDMetaData is the implementation of 'DELETE /api/uid/uidmeta' endpoint.
316 // It deletes a target UIDMetaData.
317 //
318 // uidMetaData is an instance of UIDMetaData whose correspance is to be deleted.
319 // The values of uid and type in uidMetaData is required.
320 //
321 // When delete operation is handlering properly by the OpenTSDB backend, a pointer of UIDMetaDataResponse
322 // will be returned with the corresponding status code and response info (including the potential error
323 // messages replied by OpenTSDB).
324 //
325 // Otherwise, an error instance will be returned, if the given parameter is invalid,
326 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
327 //
328 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
329 DeleteUIDMetaData(uidMetaData UIDMetaData) (*UIDMetaDataResponse, error)
330
331 // AssignUID is the implementation of 'POST /api/uid/assigin' endpoint.
332 // It enables assigning UIDs to new metrics, tag names and tag values. Multiple types and names can be provided
333 // in a single call and the API will process each name individually, reporting which names were assigned UIDs
334 // successfully, along with the UID assigned, and which failed due to invalid characters or had already been assigned.
335 // Assignment can be performed via query string or content data.
336 //
337 // assignParam is an instance of UIDAssignParam holding the parameters to invoke 'POST /api/uid/assigin'.
338 //
339 // When assigin operation is handlering properly by the OpenTSDB backend, a pointer of UIDAssignResponse
340 // will be returned with the corresponding status code and response info (including the potential error
341 // messages replied by OpenTSDB).
342 //
343 // Otherwise, an error instance will be returned, if the given parameter is invalid,
344 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
345 //
346 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
347 AssignUID(assignParam UIDAssignParam) (*UIDAssignResponse, error)
348
349 // QueryTSMetaData is the implementation of 'GET /api/uid/tsmeta' endpoint.
350 // It retrieves a single TSMetaData stored in the OpenTSDB backend with the given query parameters.
351 //
352 // tsuid is a tsuid of a target queried TSMetaData.
353 //
354 // When query operation is handlering properly by the OpenTSDB backend, a pointer of TSMetaDataResponse
355 // will be returned with the corresponding status code and response info (including the potential error
356 // messages replied by OpenTSDB).
357 //
358 // Otherwise, an error instance will be returned, if the given parameter is invalid,
359 // or when it failed to parese the response, or OpenTSDB is un-connectable right now.
360 //
361 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
362 QueryTSMetaData(tsuid string) (*TSMetaDataResponse, error)
363
364 // UpdateTSMetaData is the implementation of 'POST /api/uid/tsmeta' endpoint.
365 // It modifies a target TSMetaData with the given fields.
366 //
367 // tsMetaData is an instance of UIDMetaData whose correspance is to be modified
368 //
369 // When update operation is handlering properly by the OpenTSDB backend, a pointer of TSMetaDataResponse
370 // will be returned with the corresponding status code and response info (including the potential error
371 // messages replied by OpenTSDB).
372 //
373 // Otherwise, an error instance will be returned, when it failed to parese the response,
374 // or OpenTSDB is un-connectable right now.
375 //
376 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
377 UpdateTSMetaData(tsMetaData TSMetaData) (*TSMetaDataResponse, error)
378
379 // DeleteTSMetaData is the implementation of 'DELETE /api/uid/tsmeta' endpoint.
380 // It deletes a target TSMetaData.
381 //
382 // tsMetaData is an instance of UIDMetaData whose correspance is to be deleted
383 //
384 // When delete operation is handlering properly by the OpenTSDB backend, a pointer of TSMetaDataResponse
385 // will be returned with the corresponding status code and response info (including the potential error
386 // messages replied by OpenTSDB).
387 //
388 // Otherwise, an error instance will be returned, when it failed to parese the response,
389 // or OpenTSDB is un-connectable right now.
390 //
391 // Note that: the returned non-nil error instance is only responsed by opentsdb-client, not the OpenTSDB backend.
392 DeleteTSMetaData(tsMetaData TSMetaData) (*TSMetaDataResponse, error)
393 }
394
395 // NewClient creates an instance of http client which implements the
396 // pre-defined rest apis of OpenTSDB.
397 // A non-nil error instance returned means currently the target OpenTSDB
398 // designated with the given endpoint is not connectable.
399 func NewClient(opentsdbCfg config.OpenTSDBConfig) (Client, error) {
400 opentsdbCfg.OpentsdbHost = strings.TrimSpace(opentsdbCfg.OpentsdbHost)
401 if len(opentsdbCfg.OpentsdbHost) <= 0 {
402 return nil, errors.New("The OpentsdbEndpoint of the given config should not be empty.")
403 }
404 transport := opentsdbCfg.Transport
405 if transport == nil {
406 transport = DefaultTransport
407 }
408 client := &http.Client{
409 Transport: transport,
410 }
411 if opentsdbCfg.MaxPutPointsNum <= 0 {
412 opentsdbCfg.MaxPutPointsNum = DefaultMaxPutPointsNum
413 }
414 if opentsdbCfg.DetectDeltaNum <= 0 {
415 opentsdbCfg.DetectDeltaNum = DefaultDetectDeltaNum
416 }
417 if opentsdbCfg.MaxContentLength <= 0 {
418 opentsdbCfg.MaxContentLength = DefaultMaxContentLength
419 }
420 tsdbEndpoint := fmt.Sprintf("http://%s", opentsdbCfg.OpentsdbHost)
421 clientImpl := clientImpl{
422 tsdbEndpoint: tsdbEndpoint,
423 client: client,
424 opentsdbCfg: opentsdbCfg,
425 }
426 return &clientImpl, nil
427 }
428
429 // The private implementation of Client interface.
430 type clientImpl struct {
431 tsdbEndpoint string
432 client *http.Client
433 opentsdbCfg config.OpenTSDBConfig
434 }
435
436 // Response defines the common behaviours all the specific response for
437 // different rest-apis shound obey.
438 // Currently it is an abstraction used in (*clientImpl).sendRequest()
439 // to stored the different kinds of response contents for all the rest-apis.
440 type Response interface {
441
442 // SetStatus can be used to set the actual http status code of
443 // the related http response for the specific Response instance
444 SetStatus(code int)
445
446 // GetCustomParser can be used to retrive a custom-defined parser.
447 // Returning nil means current specific Response instance doesn't
448 // need a custom-defined parse process, and just uses the default
449 // json unmarshal method to parse the contents of the http response.
450 GetCustomParser() func(respCnt []byte) error
451
452 // Return the contents of the specific Response instance with
453 // the string format
454 String() string
455 }
456
457 // sendRequest dispatches the http request with the given method name, url and body contents.
458 // reqBodyCnt is "" means there is no contents in the request body.
459 // If the tsdb server responses properly, the error is nil and parsedResp is the parsed
460 // response with the specific type. Otherwise, the returned error is not nil.
461 func (c *clientImpl) sendRequest(method, url, reqBodyCnt string, parsedResp Response) error {
462 req, err := http.NewRequest(method, url, strings.NewReader(reqBodyCnt))
463 if err != nil {
464 return errors.New(fmt.Sprintf("Failed to create request for %s %s: %v", method, url, err))
465 }
466 req.Header.Set("Content-Type", "application/json; charset=UTF-8")
467 resp, err := c.client.Do(req)
468 if err != nil {
469 return errors.New(fmt.Sprintf("Failed to send request for %s %s: %v", method, url, err))
470 }
471 defer resp.Body.Close()
472 var jsonBytes []byte
473 if jsonBytes, err = ioutil.ReadAll(resp.Body); err != nil {
474 return errors.New(fmt.Sprintf("Failed to read response for %s %s: %v", method, url, err))
475 }
476
477 parsedResp.SetStatus(resp.StatusCode)
478 parser := parsedResp.GetCustomParser()
479 if parser == nil {
480 if err = json.Unmarshal(jsonBytes, parsedResp); err != nil {
481 return errors.New(fmt.Sprintf("Failed to parse response for %s %s: %v", method, url, err))
482 }
483 } else {
484 if err = parser(jsonBytes); err != nil {
485 return err
486 }
487 }
488
489 return nil
490 }
491
492 func (c *clientImpl) isValidOperateMethod(method string) bool {
493 method = strings.TrimSpace(strings.ToUpper(method))
494 if len(method) == 0 {
495 return false
496 }
497 methods := []string{PostMethod, PutMethod, DeleteMethod}
498 exists := false
499 for _, item := range methods {
500 if method == item {
501 exists = true
502 break
503 }
504 }
505 return exists
506 }
507
508 func (c *clientImpl) Ping() error {
509 conn, err := net.DialTimeout("tcp", c.opentsdbCfg.OpentsdbHost, DefaultDialTimeout)
510 if err != nil {
511 return errors.New(fmt.Sprintf("The target OpenTSDB is unreachable: %v", err))
512 }
513 if conn != nil {
514 defer conn.Close()
515 }
516 return nil
517 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // config.go contains the structs and methods for the implementation of /api/config and /api/config/filters.
19 //
20 package client
21
22 import (
23 "bytes"
24 "encoding/json"
25 "fmt"
26 )
27
28 type ConfigResponse struct {
29 StatusCode int
30 Configs map[string]string `json:"configs"`
31 }
32
33 func (cfgResp *ConfigResponse) SetStatus(code int) {
34 cfgResp.StatusCode = code
35 }
36
37 func (cfgResp *ConfigResponse) GetCustomParser() func(respCnt []byte) error {
38 return func(respCnt []byte) error {
39 return json.Unmarshal([]byte(fmt.Sprintf("{%s:%s}", `"Configs"`, string(respCnt))), &cfgResp)
40 }
41 }
42
43 func (cfgResp *ConfigResponse) String() string {
44 buffer := bytes.NewBuffer(nil)
45 content, _ := json.Marshal(cfgResp)
46 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
47 return buffer.String()
48 }
49
50 func (c *clientImpl) Config() (*ConfigResponse, error) {
51 configEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, ConfigPath)
52 cfgResp := ConfigResponse{}
53 if err := c.sendRequest(GetMethod, configEndpoint, "", &cfgResp); err != nil {
54 return nil, err
55 }
56 return &cfgResp, nil
57 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // dropcaches.go contains the structs and methods for the implementation of /api/dropcaches.
19 //
20 package client
21
22 import (
23 "bytes"
24 "encoding/json"
25 "fmt"
26 )
27
28 type DropcachesResponse struct {
29 StatusCode int
30 DropcachesInfo map[string]string `json:"DropcachesInfo"`
31 }
32
33 func (dropResp *DropcachesResponse) SetStatus(code int) {
34 dropResp.StatusCode = code
35 }
36
37 func (dropResp *DropcachesResponse) GetCustomParser() func(respCnt []byte) error {
38 return func(respCnt []byte) error {
39 return json.Unmarshal([]byte(fmt.Sprintf("{%s:%s}", `"DropcachesInfo"`, string(respCnt))), &dropResp)
40 }
41 }
42
43 func (dropResp *DropcachesResponse) String() string {
44 buffer := bytes.NewBuffer(nil)
45 content, _ := json.Marshal(dropResp)
46 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
47 return buffer.String()
48 }
49
50 func (c *clientImpl) Dropcaches() (*DropcachesResponse, error) {
51 dropEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, DropcachesPath)
52 dropResp := DropcachesResponse{}
53 if err := c.sendRequest(GetMethod, dropEndpoint, "", &dropResp); err != nil {
54 return nil, err
55 }
56 return &dropResp, nil
57 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // put.go contains the structs and methods for the implementation of /api/put.
19 //
20 package client
21
22 import (
23 "bytes"
24 "encoding/json"
25 "errors"
26 "fmt"
27 "strings"
28 )
29
30 // DataPoint is the structure used to hold
31 // the values of a metric item. Each attributes
32 // in DataPoint matches the definition in
33 // (http://opentsdb.net/docs/build/html/api_http/put.html).
34 //
35 type DataPoint struct {
36 // The name of the metric which is about to be stored, and is required with non-empty value.
37 Metric string `json:"metric"`
38
39 // A Unix epoch style timestamp in seconds or milliseconds.
40 // The timestamp must not contain non-numeric characters.
41 // One can use time.Now().Unix() to set this attribute.
42 // This attribute is also required with non-zero value.
43 Timestamp int64 `json:"timestamp"`
44
45 // The real type of Value only could be int, int64, float64, or string, and is required.
46 Value interface{} `json:"value"`
47
48 // A map of tag name/tag value pairs. At least one pair must be supplied.
49 // Don't use too many tags, keep it to a fairly small number, usually up to 4 or 5 tags
50 // (By default, OpenTSDB supports a maximum of 8 tags, which can be modified by add
51 // configuration item 'tsd.storage.max_tags' in opentsdb.conf).
52 Tags map[string]string `json:"tags"`
53 }
54
55 func (data *DataPoint) String() string {
56 content, _ := json.Marshal(data)
57 return string(content)
58 }
59
60 // PutError holds the error message for each putting DataPoint instance.
61 // Only calling PUT() with "details" query parameter, the reponse of
62 // the failed put data operation can contain an array PutError instance
63 // to show the details for each failure.
64 type PutError struct {
65 Data DataPoint `json:"datapoint"`
66 ErrorMsg string `json:"error"`
67 }
68
69 func (putErr *PutError) String() string {
70 return fmt.Sprintf("%s:%s", putErr.ErrorMsg, putErr.Data.String())
71 }
72
73 // PutResponse acts as the implementation of Response
74 // in the /api/put scene.
75 // It holds the status code and the response values defined in
76 // the (http://opentsdb.net/docs/build/html/api_http/put.html).
77 type PutResponse struct {
78 StatusCode int
79 Failed int64 `json:"failed"`
80 Success int64 `json:"success"`
81 Errors []PutError `json:"errors,omitempty"`
82 }
83
84 func (putResp *PutResponse) SetStatus(code int) {
85 putResp.StatusCode = code
86 }
87
88 func (putResp *PutResponse) String() string {
89 buffer := bytes.NewBuffer(nil)
90 content, _ := json.Marshal(putResp)
91 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
92 return buffer.String()
93 }
94
95 func (putResp *PutResponse) GetCustomParser() func(respCnt []byte) error {
96 return nil
97 }
98
99 func (c *clientImpl) Put(datas []DataPoint, queryParam string) (*PutResponse, error) {
100 err := validateDataPoint(datas)
101 if err != nil {
102 return nil, err
103 }
104 if !isValidPutParam(queryParam) {
105 return nil, errors.New("The given query param is invalid.")
106 }
107 var putEndpoint = ""
108 if !isEmptyPutParam(queryParam) {
109 putEndpoint = fmt.Sprintf("%s%s?%s", c.tsdbEndpoint, PutPath, queryParam)
110 } else {
111 putEndpoint = fmt.Sprintf("%s%s", c.tsdbEndpoint, PutPath)
112 }
113
114 dataGroups, err := c.splitProperGroups(datas)
115 if err != nil {
116 return nil, err
117 }
118
119 responses := make([]PutResponse, 0)
120 for _, datapoints := range dataGroups {
121 // The datas have been marshalled successfully in splitProperGroups(),
122 // so now the returned error is always nil.
123 reqBodyCnt, _ := getPutBodyContents(datapoints)
124 putResp := PutResponse{}
125 if err = c.sendRequest(PostMethod, putEndpoint, reqBodyCnt, &putResp); err != nil {
126 // This kind of error only occurs during the process of sending request,
127 // not including the scene of inserting datapoints into opentsdb.
128 // So just return error once it happens.
129 return nil, err
130 }
131 responses = append(responses, putResp)
132 }
133
134 globalResp := PutResponse{}
135 globalResp.StatusCode = 200
136 for _, resp := range responses {
137 globalResp.Failed = globalResp.Failed + resp.Failed
138 globalResp.Success = globalResp.Success + resp.Success
139 globalResp.Errors = append(globalResp.Errors, resp.Errors...)
140 if resp.StatusCode != 200 && globalResp.StatusCode == 200 {
141 globalResp.StatusCode = resp.StatusCode
142 }
143 }
144 if globalResp.StatusCode == 200 {
145 return &globalResp, nil
146 }
147 return nil, parsePutErrorMsg(&globalResp)
148 }
149
150 // splitProperGroups splits the given datapoints into groups, whose content size is
151 // not larger than c.opentsdbCfg.MaxContentLength.
152 // This method is an assurement of avoiding Put failure, when the content length of
153 // the given datapoints in a single /api/put request exceeded the value of
154 // tsd.http.request.max_chunk in the opentsdb config file.
155 func (c *clientImpl) splitProperGroups(datapoints []DataPoint) ([][]DataPoint, error) {
156 datasBytes, err := json.Marshal(&datapoints)
157 if err != nil {
158 return nil, fmt.Errorf("Failed to marshal the datapoints to be put: %v", err)
159 }
160 datapointGroups := make([][]DataPoint, 0)
161 if len(datasBytes) > c.opentsdbCfg.MaxContentLength {
162 datapointsSize := len(datapoints)
163 endIndex := datapointsSize
164 if endIndex > c.opentsdbCfg.MaxPutPointsNum {
165 endIndex = c.opentsdbCfg.MaxPutPointsNum
166 }
167 startIndex := 0
168 for endIndex <= datapointsSize {
169 tempdps := datapoints[startIndex:endIndex]
170 tempSize := len(tempdps)
171 // After successful unmarshal, the above marshal is definitly without error
172 tempdpsBytes, _ := json.Marshal(&tempdps)
173 if len(tempdpsBytes) <= c.opentsdbCfg.MaxContentLength {
174 datapointGroups = append(datapointGroups, tempdps)
175 startIndex = endIndex
176 endIndex = startIndex + tempSize
177 if endIndex > datapointsSize {
178 endIndex = datapointsSize
179 }
180 } else {
181 endIndex = endIndex - c.opentsdbCfg.DetectDeltaNum
182 }
183 if startIndex >= datapointsSize {
184 break
185 }
186 }
187 } else {
188 datapointGroups = append(datapointGroups, datapoints)
189 }
190 return datapointGroups, nil
191 }
192
193 func parsePutErrorMsg(resp *PutResponse) error {
194 buf := bytes.Buffer{}
195 buf.WriteString(fmt.Sprintf("Failed to put %d datapoint(s) into opentsdb, statuscode %d:\n", resp.Failed, resp.StatusCode))
196 if len(resp.Errors) > 0 {
197 for _, putError := range resp.Errors {
198 buf.WriteString(fmt.Sprintf("\t%s\n", putError.String()))
199 }
200 }
201 return errors.New(buf.String())
202 }
203
204 func getPutBodyContents(datas []DataPoint) (string, error) {
205 if len(datas) == 1 {
206 result, err := json.Marshal(datas[0])
207 if err != nil {
208 return "", errors.New(fmt.Sprintf("Failed to marshal datapoint: %v", err))
209 }
210 return string(result), nil
211 } else {
212 reqBodyCnt, err := marshalDataPoints(datas)
213 if err != nil {
214 return "", errors.New(fmt.Sprintf("Failed to marshal datapoint: %v", err))
215 }
216 return reqBodyCnt, nil
217 }
218 }
219
220 func marshalDataPoints(datas []DataPoint) (string, error) {
221 buffer := bytes.NewBuffer(nil)
222 size := len(datas)
223 buffer.WriteString("[")
224 for index, item := range datas {
225 result, err := json.Marshal(item)
226 if err != nil {
227 return "", err
228 }
229 buffer.Write(result)
230 if index < size-1 {
231 buffer.WriteString(",")
232 }
233 }
234 buffer.WriteString("]")
235 return buffer.String(), nil
236 }
237
238 func validateDataPoint(datas []DataPoint) error {
239 if datas == nil || len(datas) == 0 {
240 return errors.New("The given datapoint is empty.")
241 }
242 for _, data := range datas {
243 if !isValidDataPoint(&data) {
244 return errors.New("The value of the given datapoint is invalid.")
245 }
246 }
247 return nil
248 }
249
250 func isValidDataPoint(data *DataPoint) bool {
251 if data.Metric == "" || data.Timestamp == 0 || len(data.Tags) < 1 || data.Value == nil {
252 return false
253 }
254 switch data.Value.(type) {
255 case int64:
256 return true
257 case int:
258 return true
259 case float64:
260 return true
261 case float32:
262 return true
263 case string:
264 return true
265 default:
266 return false
267 }
268 }
269
270 func isValidPutParam(param string) bool {
271 if isEmptyPutParam(param) {
272 return true
273 }
274 param = strings.TrimSpace(param)
275 if param != PutRespWithSummary && param != PutRespWithDetails {
276 return false
277 }
278 return true
279 }
280
281 func isEmptyPutParam(param string) bool {
282 return strings.TrimSpace(param) == ""
283 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // query.go contains the structs and methods for the implementation of /api/query.
19 //
20 package client
21
22 import (
23 "bytes"
24 "encoding/json"
25 "errors"
26 "fmt"
27 "sort"
28 "strconv"
29 "strings"
30 )
31
32 // QueryParam is the structure used to hold
33 // the querying parameters when calling /api/query.
34 // Each attributes in QueryParam matches the definition in
35 // (http://opentsdb.net/docs/build/html/api_http/query/index.html).
36 //
37 type QueryParam struct {
38 // The start time for the query. This can be a relative or absolute timestamp.
39 // The data type can only be string, int, or int64.
40 // The value is required with non-zero value of the target type.
41 Start interface{} `json:"start"`
42
43 // An end time for the query. If not supplied, the TSD will assume the local
44 // system time on the server. This may be a relative or absolute timestamp.
45 // The data type can only be string, or int64.
46 // The value is optional.
47 End interface{} `json:"end,omitempty"`
48
49 // One or more sub queries used to select the time series to return.
50 // These may be metric m or TSUID tsuids queries
51 // The value is required with at least one element
52 Queries []SubQuery `json:"queries"`
53
54 // An optional value is used to show whether or not to return annotations with a query.
55 // The default is to return annotations for the requested timespan but this flag can disable the return.
56 // This affects both local and global notes and overrides globalAnnotations
57 NoAnnotations bool `json:"noAnnotations,omitempty"`
58
59 // An optional value is used to show whether or not the query should retrieve global
60 // annotations for the requested timespan.
61 GlobalAnnotations bool `json:"globalAnnotations,omitempty"`
62
63 // An optional value is used to show whether or not to output data point timestamps in milliseconds or seconds.
64 // If this flag is not provided and there are multiple data points within a second,
65 // those data points will be down sampled using the query's aggregation function.
66 MsResolution bool `json:"msResolution,omitempty"`
67
68 // An optional value is used to show whether or not to output the TSUIDs associated with timeseries in the results.
69 // If multiple time series were aggregated into one set, multiple TSUIDs will be returned in a sorted manner.
70 ShowTSUIDs bool `json:"showTSUIDs,omitempty"`
71
72 // An optional value is used to show whether or not can be paased to the JSON with a POST to delete any data point
73 // that match the given query.
74 Delete bool `json:"delete,omitempty"`
75 }
76
77 func (query *QueryParam) String() string {
78 content, _ := json.Marshal(query)
79 return string(content)
80 }
81
82 // SubQuery is the structure used to hold
83 // the subquery parameters when calling /api/query.
84 // Each attributes in SubQuery matches the definition in
85 // (http://opentsdb.net/docs/build/html/api_http/query/index.html).
86 //
87 type SubQuery struct {
88 // The name of an aggregation function to use.
89 // The value is required with non-empty one in the range of
90 // the response of calling /api/aggregators.
91 //
92 // By default, the potential values and corresponding descriptions are as followings:
93 // "sum": Adds all of the data points for a timestamp.
94 // "min": Picks the smallest data point for each timestamp.
95 // "max": Picks the largest data point for each timestamp.
96 // "avg": Averages the values for the data points at each timestamp.
97 Aggregator string `json:"aggregator"`
98
99 // The name of a metric stored in the system.
100 // The value is reqiured with non-empty value.
101 Metric string `json:"metric"`
102
103 // An optional value is used to show whether or not the data should be
104 // converted into deltas before returning. This is useful if the metric is a
105 // continously incrementing counter and you want to view the rate of change between data points.
106 Rate bool `json:"rate,omitempty"`
107
108 // rateOptions represents monotonically increasing counter handling options.
109 // The value is optional.
110 // Currently there is only three kind of value can be set to this map:
111 // Only three keys can be set into the rateOption parameter of the QueryParam is
112 // QueryRateOptionCounter (value type is bool), QueryRateOptionCounterMax (value type is int,int64)
113 // QueryRateOptionResetValue (value type is int,int64)
114 RateParams map[string]interface{} `json:"rateOptions,omitempty"`
115
116 // An optional value downsampling function to reduce the amount of data returned.
117 Downsample string `json:"downsample,omitempty"`
118
119 // An optional value to drill down to specific timeseries or group results by tag,
120 // supply one or more map values in the same format as the query string. Tags are converted to filters in 2.2.
121 // Note that if no tags are specified, all metrics in the system will be aggregated into the results.
122 // It will be deprecated in OpenTSDB 2.2.
123 Tags map[string]string `json:"tags,omitempty"`
124
125 // An optional value used to filter the time series emitted in the results.
126 // Note that if no filters are specified, all time series for the given
127 // metric will be aggregated into the results.
128 Fiters []Filter `json:"filters,omitempty"`
129 }
130
131 // Filter is the structure used to hold the filter parameters when calling /api/query.
132 // Each attributes in Filter matches the definition in
133 // (http://opentsdb.net/docs/build/html/api_http/query/index.html).
134 //
135 type Filter struct {
136 // The name of the filter to invoke. The value is required with a non-empty
137 // value in the range of calling /api/config/filters.
138 Type string `json:"type"`
139
140 // The tag key to invoke the filter on, required with a non-empty value
141 Tagk string `json:"tagk"`
142
143 // The filter expression to evaluate and depends on the filter being used, required with a non-empty value
144 FilterExp string `json:"filter"`
145
146 // An optional value to show whether or not to group the results by each value matched by the filter.
147 // By default all values matching the filter will be aggregated into a single series.
148 GroupBy bool `json:"groupBy"`
149 }
150
151 // QueryResponse acts as the implementation of Response in the /api/query scene.
152 // It holds the status code and the response values defined in the
153 // (http://opentsdb.net/docs/build/html/api_http/query/index.html).
154 //
155 type QueryResponse struct {
156 StatusCode int
157 QueryRespCnts []QueryRespItem `json:"queryRespCnts"`
158 ErrorMsg map[string]interface{} `json:"error"`
159 }
160
161 func (queryResp *QueryResponse) String() string {
162 buffer := bytes.NewBuffer(nil)
163 content, _ := json.Marshal(queryResp)
164 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
165 return buffer.String()
166 }
167
168 func (queryResp *QueryResponse) SetStatus(code int) {
169 queryResp.StatusCode = code
170 }
171
172 func (queryResp *QueryResponse) GetCustomParser() func(respCnt []byte) error {
173 return func(respCnt []byte) error {
174 originRespStr := string(respCnt)
175 var respStr string
176 if queryResp.StatusCode == 200 && strings.Contains(originRespStr, "[") && strings.Contains(originRespStr, "]") {
177 respStr = fmt.Sprintf("{%s:%s}", `"queryRespCnts"`, originRespStr)
178 } else {
179 respStr = originRespStr
180 }
181 return json.Unmarshal([]byte(respStr), &queryResp)
182 }
183 }
184
185 // QueryRespItem acts as the implementation of Response in the /api/query scene.
186 // It holds the response item defined in the
187 // (http://opentsdb.net/docs/build/html/api_http/query/index.html).
188 //
189 type QueryRespItem struct {
190 // Name of the metric retreived for the time series
191 Metric string `json:"metric"`
192
193 // A list of tags only returned when the results are for a single time series.
194 // If results are aggregated, this value may be null or an empty map
195 Tags map[string]string `json:"tags"`
196
197 // If more than one timeseries were included in the result set, i.e. they were aggregated,
198 // this will display a list of tag names that were found in common across all time series.
199 // Note that: Api Doc uses 'aggreatedTags', but actual response uses 'aggregateTags'
200 AggregatedTags []string `json:"aggregateTags"`
201
202 // Retrieved datapoints after being processed by the aggregators. Each data point consists
203 // of a timestamp and a value, the format determined by the serializer.
204 // For the JSON serializer, the timestamp will always be a Unix epoch style integer followed
205 // by the value as an integer or a floating point.
206 // For example, the default output is "dps"{"<timestamp>":<value>}.
207 // By default the timestamps will be in seconds. If the msResolution flag is set, then the
208 // timestamps will be in milliseconds.
209 //
210 // Because the elements of map is out of order, using common way to iterate Dps will not get
211 // datapoints with timestamps out of order.
212 // So be aware that one should use '(qri *QueryRespItem) GetDataPoints() []*DataPoint' to
213 // acquire the real ascending datapoints.
214 Dps map[string]interface{} `json:"dps"`
215
216 // If the query retrieved annotations for timeseries over the requested timespan, they will
217 // be returned in this group. Annotations for every timeseries will be merged into one set
218 // and sorted by start_time. Aggregator functions do not affect annotations, all annotations
219 // will be returned for the span.
220 // The value is optional.
221 Annotations []Annotation `json:"annotations,omitempty"`
222
223 // If requested by the user, the query will scan for global annotations during
224 // the timespan and the results returned in this group.
225 // The value is optional.
226 GlobalAnnotations []Annotation `json:"globalAnnotations,omitempty"`
227 }
228
229 // GetDataPoints returns the real ascending datapoints from the information of the related QueryRespItem.
230 func (qri *QueryRespItem) GetDataPoints() []*DataPoint {
231 datapoints := make([]*DataPoint, 0)
232 timestampStrs := qri.getSortedTimestampStrs()
233 for _, timestampStr := range timestampStrs {
234 timestamp, _ := strconv.ParseInt(timestampStr, 10, 64)
235 datapoint := &DataPoint{
236 Metric: qri.Metric,
237 Value: qri.Dps[timestampStr],
238 Tags: qri.Tags,
239 Timestamp: timestamp,
240 }
241 datapoints = append(datapoints, datapoint)
242 }
243 return datapoints
244 }
245
246 // getSortedTimestampStrs returns a slice of the ascending timestamp with
247 // string format for the Dps of the related QueryRespItem instance.
248 func (qri *QueryRespItem) getSortedTimestampStrs() []string {
249 timestampStrs := make([]string, 0)
250 for timestampStr := range qri.Dps {
251 timestampStrs = append(timestampStrs, timestampStr)
252 }
253 sort.Strings(timestampStrs)
254 return timestampStrs
255 }
256
257 // GetLatestDataPoint returns latest datapoint for the related QueryRespItem instance.
258 func (qri *QueryRespItem) GetLatestDataPoint() *DataPoint {
259 timestampStrs := qri.getSortedTimestampStrs()
260 size := len(timestampStrs)
261 if size == 0 {
262 return nil
263 }
264 timestamp, _ := strconv.ParseInt(timestampStrs[size-1], 10, 64)
265 datapoint := &DataPoint{
266 Metric: qri.Metric,
267 Value: qri.Dps[timestampStrs[size-1]],
268 Tags: qri.Tags,
269 Timestamp: timestamp,
270 }
271 return datapoint
272 }
273
274 func (c *clientImpl) Query(param QueryParam) (*QueryResponse, error) {
275 if !isValidQueryParam(&param) {
276 return nil, errors.New("The given query param is invalid.\n")
277 }
278 queryEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, QueryPath)
279 reqBodyCnt, err := getQueryBodyContents(&param)
280 if err != nil {
281 return nil, err
282 }
283 queryResp := QueryResponse{}
284 if err = c.sendRequest(PostMethod, queryEndpoint, reqBodyCnt, &queryResp); err != nil {
285 return nil, err
286 }
287 return &queryResp, nil
288 }
289
290 func getQueryBodyContents(param interface{}) (string, error) {
291 result, err := json.Marshal(param)
292 if err != nil {
293 return "", errors.New(fmt.Sprintf("Failed to marshal query param: %v\n", err))
294 }
295 return string(result), nil
296 }
297
298 func isValidQueryParam(param *QueryParam) bool {
299 if param.Queries == nil || len(param.Queries) == 0 {
300 return false
301 }
302 if !isValidTimePoint(param.Start) {
303 return false
304 }
305 for _, query := range param.Queries {
306 if len(query.Aggregator) == 0 || len(query.Metric) == 0 {
307 return false
308 }
309 for k, _ := range query.RateParams {
310 if k != QueryRateOptionCounter && k != QueryRateOptionCounterMax && k != QueryRateOptionResetValue {
311 return false
312 }
313 }
314 }
315 return true
316 }
317
318 func isValidTimePoint(timePoint interface{}) bool {
319 if timePoint == nil {
320 return false
321 }
322 switch v := timePoint.(type) {
323 case int:
324 if v <= 0 {
325 return false
326 }
327 case int64:
328 if v <= 0 {
329 return false
330 }
331 case string:
332 if v == "" {
333 return false
334 }
335
336 default:
337 return false
338 }
339 return true
340 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // query_last.go contains the structs and methods for the implementation of /api/query/last,
19 // which is fully supported since v2.2 of opentsdb.
20 //
21 package client
22
23 import (
24 "bytes"
25 "encoding/json"
26 "errors"
27 "fmt"
28 "strings"
29 )
30
31 // QueryLastParam is the structure used to hold
32 // the querying parameters when calling /api/query/last.
33 // Each attributes in QueryLastParam matches the definition in
34 // (http://opentsdb.net/docs/build/html/api_http/query/last.html).
35 //
36 type QueryLastParam struct {
37 // One or more sub queries used to select the time series to return.
38 // These may be metric m or TSUID tsuids queries
39 // The value is required with at least one element
40 Queries []SubQueryLast `json:"queries"`
41
42 // An optional flag is used to determine whether or not to resolve the TSUIDs of results to
43 // their metric and tag names. The default value is false.
44 ResolveNames bool `json:"resolveNames"`
45
46 // An optional number of hours is used to search in the past for data. If set to 0 then the
47 // timestamp of the meta data counter for the time series is used.
48 BackScan int `json:"backScan"`
49 }
50
51 func (query *QueryLastParam) String() string {
52 content, _ := json.Marshal(query)
53 return string(content)
54 }
55
56 // SubQueryLast is the structure used to hold
57 // the subquery parameters when calling /api/query/last.
58 // Each attributes in SubQueryLast matches the definition in
59 // (http://opentsdb.net/docs/build/html/api_http/query/last.html).
60 //
61 type SubQueryLast struct {
62 // The name of a metric stored in the system.
63 // The value is reqiured with non-empty value.
64 Metric string `json:"metric"`
65
66 // An optional value to drill down to specific timeseries or group results by tag,
67 // supply one or more map values in the same format as the query string. Tags are converted to filters in 2.2.
68 // Note that if no tags are specified, all metrics in the system will be aggregated into the results.
69 // It will be deprecated in OpenTSDB 2.2.
70 Tags map[string]string `json:"tags,omitempty"`
71 }
72
73 // QueryLastResponse acts as the implementation of Response in the /api/query/last scene.
74 // It holds the status code and the response values defined in the
75 // (http://opentsdb.net/docs/build/html/api_http/query/last.html).
76 //
77 type QueryLastResponse struct {
78 StatusCode int
79 QueryRespCnts []QueryRespLastItem `json:"queryRespCnts,omitempty"`
80 ErrorMsg map[string]interface{} `json:"error"`
81 }
82
83 func (queryLastResp *QueryLastResponse) String() string {
84 buffer := bytes.NewBuffer(nil)
85 content, _ := json.Marshal(queryLastResp)
86 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
87 return buffer.String()
88 }
89
90 func (queryLastResp *QueryLastResponse) SetStatus(code int) {
91 queryLastResp.StatusCode = code
92 }
93
94 func (queryLastResp *QueryLastResponse) GetCustomParser() func(respCnt []byte) error {
95 return func(respCnt []byte) error {
96 originRespStr := string(respCnt)
97 var respStr string
98 if queryLastResp.StatusCode == 200 && strings.Contains(originRespStr, "[") && strings.Contains(originRespStr, "]") {
99 respStr = fmt.Sprintf("{%s:%s}", `"queryRespCnts"`, originRespStr)
100 } else {
101 respStr = originRespStr
102 }
103 return json.Unmarshal([]byte(respStr), &queryLastResp)
104 }
105 }
106
107 // QueryRespLastItem acts as the implementation of Response in the /api/query/last scene.
108 // It holds the response item defined in the
109 // (http://opentsdb.net/docs/build/html/api_http/query/last.html).
110 //
111 type QueryRespLastItem struct {
112 // Name of the metric retreived for the time series.
113 // Only returned if resolve was set to true.
114 Metric string `json:"metric"`
115
116 // A list of tags only returned when the results are for a single time series.
117 // If results are aggregated, this value may be null or an empty map.
118 // Only returned if resolve was set to true.
119 Tags map[string]string `json:"tags"`
120
121 // A Unix epoch timestamp, in milliseconds, when the data point was written.
122 Timestamp int64 `json:"timestamp"`
123
124 // The value of the data point enclosed in quotation marks as a string
125 Value string `json:"value"`
126
127 // The hexadecimal TSUID for the time series
128 Tsuid string `json:"tsuid"`
129 }
130
131 func (c *clientImpl) QueryLast(param QueryLastParam) (*QueryLastResponse, error) {
132 if !isValidQueryLastParam(&param) {
133 return nil, errors.New("The given query param is invalid.\n")
134 }
135 queryEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, QueryLastPath)
136 reqBodyCnt, err := getQueryBodyContents(&param)
137 if err != nil {
138 return nil, err
139 }
140 queryResp := QueryLastResponse{}
141 if err = c.sendRequest(PostMethod, queryEndpoint, reqBodyCnt, &queryResp); err != nil {
142 return nil, err
143 }
144 return &queryResp, nil
145 }
146
147 func isValidQueryLastParam(param *QueryLastParam) bool {
148 if param.Queries == nil || len(param.Queries) == 0 {
149 return false
150 }
151 for _, query := range param.Queries {
152 if len(query.Metric) == 0 {
153 return false
154 }
155 }
156 return true
157 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // serializers.go contains the structs and methods for the implementation of /api/serializers.
19 //
20 package client
21
22 import (
23 "bytes"
24 "encoding/json"
25 "fmt"
26 )
27
28 type SerialResponse struct {
29 StatusCode int
30 Serializers []Serializer `json:"Serializers"`
31 }
32
33 type Serializer struct {
34 SerializerName string `json:"serializer"`
35 Formatters []string `json:"formatters"`
36 Parsers []string `json:"parsers"`
37 Class string `json:"class,omitempty"`
38 ResContType string `json:"response_content_type,omitempty"`
39 ReqContType string `json:"request_content_type,omitempty"`
40 }
41
42 func (serialResp *SerialResponse) SetStatus(code int) {
43 serialResp.StatusCode = code
44 }
45
46 func (serialResp *SerialResponse) GetCustomParser() func(respCnt []byte) error {
47 return func(respCnt []byte) error {
48 return json.Unmarshal([]byte(fmt.Sprintf("{%s:%s}", `"Serializers"`, string(respCnt))), &serialResp)
49 }
50 }
51
52 func (serialResp *SerialResponse) String() string {
53 buffer := bytes.NewBuffer(nil)
54 content, _ := json.Marshal(serialResp)
55 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
56 return buffer.String()
57 }
58
59 func (c *clientImpl) Serializers() (*SerialResponse, error) {
60 serialEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, SerializersPath)
61 serialResp := SerialResponse{}
62 if err := c.sendRequest(GetMethod, serialEndpoint, "", &serialResp); err != nil {
63 return nil, err
64 }
65 return &serialResp, nil
66 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // stats.go contains the structs and methods for the implementation of /api/stats.
19 //
20 package client
21
22 import (
23 "bytes"
24 "encoding/json"
25 "fmt"
26 )
27
28 type StatsResponse struct {
29 StatusCode int
30 Metrics []MetricInfo `json:"Metrics"`
31 }
32
33 type MetricInfo struct {
34 Metric string `json:"metric"`
35 Timestamp int64 `json:"timestamp"`
36 Value interface{} `json:"value"`
37 Tags map[string]string `json:"tags"`
38 }
39
40 func (statsResp *StatsResponse) SetStatus(code int) {
41 statsResp.StatusCode = code
42 }
43
44 func (statsResp *StatsResponse) GetCustomParser() func(respCnt []byte) error {
45 return func(respCnt []byte) error {
46 return json.Unmarshal([]byte(fmt.Sprintf("{%s:%s}", `"Metrics"`, string(respCnt))), &statsResp)
47 }
48 }
49
50 func (statsResp *StatsResponse) String() string {
51 buffer := bytes.NewBuffer(nil)
52 content, _ := json.Marshal(statsResp)
53 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
54 return buffer.String()
55 }
56
57 func (c *clientImpl) Stats() (*StatsResponse, error) {
58 statsEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, StatsPath)
59 statsResp := StatsResponse{}
60 if err := c.sendRequest(GetMethod, statsEndpoint, "", &statsResp); err != nil {
61 return nil, err
62 }
63 return &statsResp, nil
64 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // suggest.go contains the structs and methods for the implementation of /api/suggest.
19 //
20 package client
21
22 import (
23 "bytes"
24 "encoding/json"
25 "errors"
26 "fmt"
27 "strings"
28 )
29
30 // SuggestParam is the structure used to hold
31 // the querying parameters when calling /api/suggest.
32 // Each attributes in SuggestParam matches the definition in
33 // (http://opentsdb.net/docs/build/html/api_http/suggest.html).
34 //
35 type SuggestParam struct {
36 // The type of data to auto complete on.
37 // Must be one of the following: metrics, tagk or tagv.
38 // It is required.
39 // Only the one of the three query type can be used:
40 // TypeMetrics, TypeTagk, TypeTagv
41 Type string `json:"type"`
42
43 // An optional string value to match on for the given type
44 Q string `json:"q,omitempty"`
45
46 // An optional integer value presenting the maximum number of suggested
47 // results to return. If it is set, it must be greater than 0.
48 MaxResultNum int `json:"max,omitempty"`
49 }
50
51 func (sugParam *SuggestParam) String() string {
52 contents, _ := json.Marshal(sugParam)
53 return string(contents)
54 }
55
56 type SuggestResponse struct {
57 StatusCode int
58 ResultInfo []string `json:"ResultInfo"`
59 }
60
61 func (sugResp *SuggestResponse) SetStatus(code int) {
62 sugResp.StatusCode = code
63 }
64
65 func (sugResp *SuggestResponse) GetCustomParser() func(respCnt []byte) error {
66 return func(respCnt []byte) error {
67 return json.Unmarshal([]byte(fmt.Sprintf("{%s:%s}", `"ResultInfo"`, string(respCnt))), &sugResp)
68 }
69 }
70
71 func (sugResp *SuggestResponse) String() string {
72 buffer := bytes.NewBuffer(nil)
73 content, _ := json.Marshal(sugResp)
74 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
75 return buffer.String()
76 }
77
78 func (c *clientImpl) Suggest(sugParam SuggestParam) (*SuggestResponse, error) {
79 if !isValidSuggestParam(&sugParam) {
80 return nil, errors.New("The given suggest param is invalid.\n")
81 }
82 sugEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, SuggestPath)
83 reqBodyCnt, err := getSuggestBodyContents(&sugParam)
84 if err != nil {
85 return nil, err
86 }
87 fmt.Println(reqBodyCnt)
88 sugResp := SuggestResponse{}
89 if err := c.sendRequest(PostMethod, sugEndpoint, reqBodyCnt, &sugResp); err != nil {
90 return nil, err
91 }
92 return &sugResp, nil
93 }
94
95 func isValidSuggestParam(sugParam *SuggestParam) bool {
96 if sugParam.Type == "" {
97 return false
98 }
99 types := []string{TypeMetrics, TypeTagk, TypeTagv}
100 sugParam.Type = strings.TrimSpace(sugParam.Type)
101 for _, typeItem := range types {
102 if sugParam.Type == typeItem {
103 return true
104 }
105 }
106 return false
107 }
108
109 func getSuggestBodyContents(sugParam *SuggestParam) (string, error) {
110 result, err := json.Marshal(sugParam)
111 if err != nil {
112 return "", errors.New(fmt.Sprintf("Failed to marshal suggest param: %v\n", err))
113 }
114 return string(result), nil
115 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // Every metric, tag name and tag value is associated with a unique identifier (UID).
19 // Internally, the UID is a binary array assigned to a text value the first time it is
20 // encountered or via an explicit assignment request. This endpoint provides utilities
21 // for managing UIDs and their associated data. Please see the UID endpoint TOC below
22 // for information on what functions are implemented.
23 //
24 // UIDs exposed via the API are encoded as hexadecimal strings. The UID 42 would be expressed
25 // as 00002A given the default UID width of 3 bytes.
26 // You may also edit meta data associated with timeseries or individual UID objects via the UID endpoint.
27 //
28 // uid.go contains the structs and methods for the implementation of
29 // /api/uid/tsmeta, /api/uid/assign, /api/uid/uidmeta.
30 //
31 package client
32
33 import (
34 "bytes"
35 "encoding/json"
36 "errors"
37 "fmt"
38 "strings"
39 )
40
41 // UIDMetaData is the structure used to hold
42 // the parameters when calling (POST,PUT) /api/uid/uidmeta.
43 // Each attributes in UIDMetaData matches the definition in
44 // (http://opentsdb.net/docs/build/html/api_http/uid/uidmeta.html).
45 //
46 type UIDMetaData struct {
47 // A required hexadecimal representation of the UID
48 Uid string `json:"uid,omitempty"`
49
50 // A required type of UID, must be metric, tagk or tagv
51 Type string `json:"type,omitempty"`
52
53 // An optional brief description of what the UID represents
54 Description string `json:"description,omitempty"`
55
56 // An optional short name that can be displayed in GUIs instead of the default name
57 DisplayName string `json:"displayName,omitempty"`
58
59 // An optional detailed notes about what the UID represents
60 Notes string `json:"notes,omitempty"`
61
62 // An optional key/value map to store custom fields and values
63 Custom map[string]string `json:"custom,omitempty"`
64 }
65
66 // UIDMetaDataResponse acts as the implementation of Response in the /api/uid/uidmeta scene.
67 // It holds the status code and the response values defined in the
68 // (http://opentsdb.net/docs/build/html/api_http/uid/uidmeta.html).
69 //
70 type UIDMetaDataResponse struct {
71 UIDMetaData
72
73 StatusCode int
74
75 // The name of the UID as given when the data point was stored or the UID assigned
76 Name string `json:"name,omitempty"`
77
78 // A Unix epoch timestamp in seconds when the UID was first created.
79 // If the meta data was not stored when the UID was assigned, this value may be 0.
80 Created int64 `json:"created,omitempty"`
81
82 ErrorInfo map[string]interface{} `json:"error,omitempty"`
83 }
84
85 func (uidMetaDataResp *UIDMetaDataResponse) SetStatus(code int) {
86 uidMetaDataResp.StatusCode = code
87 }
88
89 func (uidMetaDataResp *UIDMetaDataResponse) GetCustomParser() func(respCnt []byte) error {
90 return func(respCnt []byte) error {
91 var resultBytes []byte
92 if uidMetaDataResp.StatusCode == 204 || // The OpenTSDB deletes a UIDMetaData successfully, or
93 uidMetaDataResp.StatusCode == 304 { // no changes were present, and with no body content.
94 return nil
95 } else {
96 resultBytes = respCnt
97 }
98 return json.Unmarshal(resultBytes, &uidMetaDataResp)
99 }
100 }
101
102 func (uidMetaDataResp *UIDMetaDataResponse) String() string {
103 buffer := bytes.NewBuffer(nil)
104 content, _ := json.Marshal(uidMetaDataResp)
105 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
106 return buffer.String()
107 }
108
109 func (c *clientImpl) QueryUIDMetaData(metaQueryParam map[string]string) (*UIDMetaDataResponse, error) {
110 if !isValidUIDMetaDataQueryParam(metaQueryParam) {
111 return nil, errors.New("The given query uid metadata is invalid.")
112 }
113 queryParam := fmt.Sprintf("%s=%v&%s=%v", "uid", metaQueryParam["uid"], "type", metaQueryParam["type"])
114 queryUIDMetaEndpoint := fmt.Sprintf("%s%s?%s", c.tsdbEndpoint, UIDMetaDataPath, queryParam)
115 uidMetaDataResp := UIDMetaDataResponse{}
116 if err := c.sendRequest(GetMethod, queryUIDMetaEndpoint, "", &uidMetaDataResp); err != nil {
117 return nil, err
118 }
119 return &uidMetaDataResp, nil
120 }
121
122 func (c *clientImpl) UpdateUIDMetaData(uidMetaData UIDMetaData) (*UIDMetaDataResponse, error) {
123 return c.operateUIDMetaData(PostMethod, &uidMetaData)
124 }
125
126 func (c *clientImpl) DeleteUIDMetaData(uidMetaData UIDMetaData) (*UIDMetaDataResponse, error) {
127 return c.operateUIDMetaData(DeleteMethod, &uidMetaData)
128 }
129
130 func (c *clientImpl) operateUIDMetaData(method string, uidMetaData *UIDMetaData) (*UIDMetaDataResponse, error) {
131 if !c.isValidOperateMethod(method) {
132 return nil, errors.New("The given method for operating a uid metadata is invalid.")
133 }
134 uidMetaEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, UIDMetaDataPath)
135 resultBytes, err := json.Marshal(uidMetaData)
136 if err != nil {
137 return nil, errors.New(fmt.Sprintf("Failed to marshal uidMetaData: %v", err))
138 }
139 uidMetaDataResp := UIDMetaDataResponse{}
140 if err = c.sendRequest(method, uidMetaEndpoint, string(resultBytes), &uidMetaDataResp); err != nil {
141 return nil, err
142 }
143 return &uidMetaDataResp, nil
144 }
145
146 func isValidUIDMetaDataQueryParam(metaQueryParam map[string]string) bool {
147 if metaQueryParam == nil || len(metaQueryParam) != 2 {
148 return false
149 }
150 checkKeys := []string{"uid", "type"}
151 for _, checkKey := range checkKeys {
152 _, exists := metaQueryParam[checkKey]
153 if !exists {
154 return false
155 }
156 }
157 typeValue := metaQueryParam["type"]
158 typeCheckItems := []string{TypeMetrics, TypeTagk, TypeTagv}
159 for _, checkItem := range typeCheckItems {
160 if typeValue == checkItem {
161 return true
162 }
163 }
164 return false
165 }
166
167 // UIDAssignParam is the structure used to hold
168 // the parameters when calling POST /api/uid/assign.
169 // Each attributes in UIDAssignParam matches the definition in
170 // (http://opentsdb.net/docs/build/html/api_http/uid/assign.html).
171 //
172 type UIDAssignParam struct {
173 // An optional list of metric names for assignment
174 Metric []string `json:"metric,omitempty"`
175
176 // An optional list of tag names for assignment
177 Tagk []string `json:"tagk,omitempty"`
178
179 // An optional list of tag values for assignment
180 Tagv []string `json:"tagv,omitempty"`
181 }
182
183 // UIDAssignResponse acts as the implementation of Response in the POST /api/uid/assign scene.
184 // It holds the status code and the response values defined in the
185 // (http://opentsdb.net/docs/build/html/api_http/uid/assign.html).
186 //
187 type UIDAssignResponse struct {
188 StatusCode int
189 Metric map[string]string `json:"metric"`
190 MetricErrors map[string]string `json:"metric_errors,omitempty"`
191 Tagk map[string]string `json:"tagk"`
192 TagkErrors map[string]string `json:"tagk_errors,omitempty"`
193 Tagv map[string]string `json:"tagv"`
194 TagvErrors map[string]string `json:"tagv_errors,omitempty"`
195 }
196
197 func (uidAssignResp *UIDAssignResponse) SetStatus(code int) {
198 uidAssignResp.StatusCode = code
199 }
200
201 func (uidAssignResp *UIDAssignResponse) GetCustomParser() func(respCnt []byte) error {
202 return nil
203 }
204
205 func (uidAssignResp *UIDAssignResponse) String() string {
206 buffer := bytes.NewBuffer(nil)
207 content, _ := json.Marshal(uidAssignResp)
208 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
209 return buffer.String()
210 }
211
212 func (c *clientImpl) AssignUID(assignParam UIDAssignParam) (*UIDAssignResponse, error) {
213 assignUIDEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, UIDAssignPath)
214 resultBytes, err := json.Marshal(assignParam)
215 if err != nil {
216 return nil, errors.New(fmt.Sprintf("Failed to marshal UIDAssignParam: %v", err))
217 }
218 uidAssignResp := UIDAssignResponse{}
219 if err = c.sendRequest(PostMethod, assignUIDEndpoint, string(resultBytes), &uidAssignResp); err != nil {
220 return nil, err
221 }
222 return &uidAssignResp, nil
223 }
224
225 // TSMetaData is the structure used to hold
226 // the parameters when calling (POST,PUT,DELETE) /api/uid/tsmeta.
227 // Each attributes in TSMetaData matches the definition in
228 // (http://opentsdb.net/docs/build/html/api_http/uid/tsmeta.html).
229 //
230 type TSMetaData struct {
231 // A required hexadecimal representation of the timeseries UID
232 Tsuid string `json:"tsuid,omitempty"`
233
234 // An optional brief description of what the UID represents
235 Description string `json:"description,omitempty"`
236
237 // An optional short name that can be displayed in GUIs instead of the default name
238 DisplayName string `json:"displayName,omitempty"`
239
240 // An optional detailed notes about what the UID represents
241 Notes string `json:"notes,omitempty"`
242
243 // An optional key/value map to store custom fields and values
244 Custom map[string]string `json:"custom,omitempty"`
245
246 // An optional value reflective of the data stored in the timeseries, may be used in GUIs or calculations
247 Units string `json:"units,omitempty"`
248
249 // The kind of data stored in the timeseries such as counter, gauge, absolute, etc.
250 // These may be defined later but they should be similar to Data Source Types in an RRD.
251 // Its value is optional
252 DataType string `json:"dataType,omitempty"`
253
254 // The number of days of data points to retain for the given timeseries. Not Implemented.
255 // When set to 0, the default, data is retained indefinitely.
256 // Its value is optional
257 Retention int64 `json:"retention,omitempty"`
258
259 // An optional maximum value for this timeseries that may be used in calculations such as
260 // percent of maximum. If the default of NaN is present, the value is ignored.
261 Max float64 `json:"max,omitempty"`
262
263 // An optional minimum value for this timeseries that may be used in calculations such as
264 // percent of minimum. If the default of NaN is present, the value is ignored.
265 Min float64 `json:"min,omitempty"`
266 }
267
268 type TSMetaDataResponse struct {
269 StatusCode int
270 TSMetaData
271 Metric UIDMetaData `json:"metric,omitempty"`
272 Tags []UIDMetaData `json:"tags,omitempty"`
273 Created int64 `json:"created,omitempty"`
274 LastReceived int64 `json:"lastReceived,omitempty"`
275 TotalDatapoints int64 `json:"totalDatapoints,omitempty"`
276 ErrorInfo map[string]interface{} `json:"error,omitempty"`
277 }
278
279 func (tsMetaDataResp *TSMetaDataResponse) SetStatus(code int) {
280 tsMetaDataResp.StatusCode = code
281 }
282
283 func (tsMetaDataResp *TSMetaDataResponse) GetCustomParser() func(respCnt []byte) error {
284 return func(respCnt []byte) error {
285 var resultBytes []byte
286 if tsMetaDataResp.StatusCode == 204 || // The OpenTSDB deletes a TSMetaData successfully, or
287 tsMetaDataResp.StatusCode == 304 { // no changes were present, and with no body content.
288 return nil
289 } else {
290 resultBytes = respCnt
291 }
292 return json.Unmarshal(resultBytes, &tsMetaDataResp)
293 }
294 }
295
296 func (tsMetaDataResp *TSMetaDataResponse) String() string {
297 buffer := bytes.NewBuffer(nil)
298 content, _ := json.Marshal(tsMetaDataResp)
299 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
300 return buffer.String()
301 }
302
303 func (c *clientImpl) QueryTSMetaData(tsuid string) (*TSMetaDataResponse, error) {
304 tsuid = strings.TrimSpace(tsuid)
305 if len(tsuid) == 0 {
306 return nil, errors.New("The given query tsuid is empty.")
307 }
308 queryTSMetaEndpoint := fmt.Sprintf("%s%s?tsuid=%s", c.tsdbEndpoint, TSMetaDataPath, tsuid)
309 tsMetaDataResp := TSMetaDataResponse{}
310 if err := c.sendRequest(GetMethod, queryTSMetaEndpoint, "", &tsMetaDataResp); err != nil {
311 return nil, err
312 }
313 return &tsMetaDataResp, nil
314 }
315
316 func (c *clientImpl) UpdateTSMetaData(tsMetaData TSMetaData) (*TSMetaDataResponse, error) {
317 return c.operateTSMetaData(PostMethod, &tsMetaData)
318 }
319
320 func (c *clientImpl) DeleteTSMetaData(tsMetaData TSMetaData) (*TSMetaDataResponse, error) {
321 return c.operateTSMetaData(DeleteMethod, &tsMetaData)
322 }
323
324 func (c *clientImpl) operateTSMetaData(method string, tsMetaData *TSMetaData) (*TSMetaDataResponse, error) {
325 if !c.isValidOperateMethod(method) {
326 return nil, errors.New("The given method for operating a uid metadata is invalid.")
327 }
328 tsMetaEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, TSMetaDataPath)
329 resultBytes, err := json.Marshal(tsMetaData)
330 if err != nil {
331 return nil, errors.New(fmt.Sprintf("Failed to marshal uidMetaData: %v", err))
332 }
333 tsMetaDataResp := TSMetaDataResponse{}
334 if err = c.sendRequest(method, tsMetaEndpoint, string(resultBytes), &tsMetaDataResp); err != nil {
335 return nil, err
336 }
337 return &tsMetaDataResp, nil
338 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package client defines the client and the corresponding
16 // rest api implementaion of OpenTSDB.
17 //
18 // version.go contains the structs and methods for the implementation of /api/version.
19 //
20 package client
21
22 import (
23 "bytes"
24 "encoding/json"
25 "fmt"
26 )
27
28 type VersionResponse struct {
29 StatusCode int
30 VersionInfo map[string]string `json:"VersionInfo"`
31 }
32
33 func (verResp *VersionResponse) SetStatus(code int) {
34 verResp.StatusCode = code
35 }
36
37 func (verResp *VersionResponse) GetCustomParser() func(respCnt []byte) error {
38 return func(respCnt []byte) error {
39 return json.Unmarshal([]byte(fmt.Sprintf("{%s:%s}", `"VersionInfo"`, string(respCnt))), &verResp)
40 }
41 }
42
43 func (verResp *VersionResponse) String() string {
44 buffer := bytes.NewBuffer(nil)
45 content, _ := json.Marshal(verResp)
46 buffer.WriteString(fmt.Sprintf("%s\n", string(content)))
47 return buffer.String()
48 }
49
50 func (c *clientImpl) Version() (*VersionResponse, error) {
51 verEndpoint := fmt.Sprintf("%s%s", c.tsdbEndpoint, VersionPath)
52 verResp := VersionResponse{}
53 if err := c.sendRequest(GetMethod, verEndpoint, "", &verResp); err != nil {
54 return nil, err
55 }
56 return &verResp, nil
57 }
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package config defines basic structure to hold the configure items used
16 // to initialize the opentsdb client.
17 //
18 package config
19
20 import (
21 "net/http"
22 )
23
24 type OpenTSDBConfig struct {
25
26 // The host of the target opentsdb, is a required non-empty string which is
27 // in the format of ip:port without http:// prefix or a domain.
28 OpentsdbHost string
29
30 // A pointer of http.Tranport is used by the opentsdb client.
31 // This value is optional, and if it is not set, client.DefaultTransport, which
32 // enables tcp keepalive mode, will be used in the opentsdb client.
33 Transport *http.Transport
34
35 // The maximal number of datapoints which will be inserted into the opentsdb
36 // via one calling of /api/put method.
37 // This value is optional, and if it is not set, client.DefaultMaxPutPointsNum
38 // will be used in the opentsdb client.
39 MaxPutPointsNum int
40
41 // The detect delta number of datapoints which will be used in client.Put()
42 // to split a large group of datapoints into small batches.
43 // This value is optional, and if it is not set, client.DefaultDetectDeltaNum
44 // will be used in the opentsdb client.
45 DetectDeltaNum int
46
47 // The maximal body content length per /api/put method to insert datapoints
48 // into opentsdb.
49 // This value is optional, and if it is not set, client.DefaultMaxPutPointsNum
50 // will be used in the opentsdb client.
51 MaxContentLength int
52 }
0 chmod 644 sample.go
1 chmod 644 client/*.go
0 // Copyright 2015 opentsdb-goclient authors. All Rights Reserved.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 //
15 // Package main shows the sample of how to use github.com/bluebreezecf/opentsdbclient/client
16 // to communicate with the OpenTSDB with the pre-define rest apis.
17 // (http://opentsdb.net/docs/build/html/api_http/index.html#api-endpoints)
18 //
19 package main
20
21 import (
22 "fmt"
23 "math/rand"
24 "time"
25
26 "github.com/bluebreezecf/opentsdb-goclient/client"
27 "github.com/bluebreezecf/opentsdb-goclient/config"
28 )
29
30 func main() {
31 opentsdbCfg := config.OpenTSDBConfig{
32 OpentsdbHost: "127.0.0.1:4242",
33 }
34 tsdbClient, err := client.NewClient(opentsdbCfg)
35 if err != nil {
36 fmt.Printf("%v\n", err)
37 return
38 }
39
40 //0. Ping
41 if err = tsdbClient.Ping(); err != nil {
42 fmt.Println(err.Error())
43 return
44 }
45 PutDataPointNum := 4
46 name := []string{"cpu", "disk", "net", "mem", "bytes"}
47 //1. POST /api/put
48 fmt.Println("Begin to test POST /api/put.")
49 cpuDatas := make([]client.DataPoint, 0)
50 st1 := time.Now().Unix()
51 time.Sleep(2 * time.Second)
52 tags := make(map[string]string)
53 tags["host"] = "bluebreezecf-host"
54 tags["try-name"] = "bluebreezecf-sample"
55 tags["demo-name"] = "opentsdb-test"
56 i := 0
57 for {
58 time.Sleep(500 * time.Millisecond)
59 data := client.DataPoint{
60 Metric: name[i],
61 Timestamp: time.Now().Unix(),
62 Value: rand.Float64(),
63 }
64 data.Tags = tags
65 cpuDatas = append(cpuDatas, data)
66 fmt.Printf(" %d.Prepare datapoint %s\n", i, data.String())
67 if i < PutDataPointNum {
68 i++
69 } else {
70 break
71 }
72 }
73
74 if resp, err := tsdbClient.Put(cpuDatas, "details"); err != nil {
75 fmt.Printf(" Error occurs when putting datapoints: %v", err)
76 } else {
77 fmt.Printf(" %s", resp.String())
78 }
79 fmt.Println("Finish testing POST /api/put.")
80
81 //2.1 POST /api/query to query
82 fmt.Println("Begin to test POST /api/query.")
83 time.Sleep(2 * time.Second)
84 st2 := time.Now().Unix()
85 queryParam := client.QueryParam{
86 Start: st1,
87 End: st2,
88 }
89 subqueries := make([]client.SubQuery, 0)
90 for _, metric := range name {
91 subQuery := client.SubQuery{
92 Aggregator: "sum",
93 Metric: metric,
94 Tags: tags,
95 }
96 subqueries = append(subqueries, subQuery)
97 }
98 queryParam.Queries = subqueries
99 if queryResp, err := tsdbClient.Query(queryParam); err != nil {
100 fmt.Printf("Error occurs when querying: %v", err)
101 } else {
102 fmt.Printf("%s", queryResp.String())
103 }
104 fmt.Println("Finish testing POST /api/query.")
105
106 //2.2 POST /api/query/last
107 fmt.Println("Begin to test POST /api/query/last.")
108 time.Sleep(1 * time.Second)
109 subqueriesLast := make([]client.SubQueryLast, 0)
110 for _, metric := range name {
111 subQueryLast := client.SubQueryLast{
112 Metric: metric,
113 Tags: tags,
114 }
115 subqueriesLast = append(subqueriesLast, subQueryLast)
116 }
117 queryLastParam := client.QueryLastParam{
118 Queries: subqueriesLast,
119 ResolveNames: true,
120 BackScan: 24,
121 }
122 if queryLastResp, err := tsdbClient.QueryLast(queryLastParam); err != nil {
123 fmt.Printf("Error occurs when querying last: %v", err)
124 } else {
125 fmt.Printf("%s", queryLastResp.String())
126 }
127 fmt.Println("Finish testing POST /api/query/last.")
128
129 //2.3 POST /api/query to delete
130 fmt.Println("Begin to test POST /api/query to delete.")
131 queryParam.Delete = true
132 if queryResp, err := tsdbClient.Query(queryParam); err != nil {
133 fmt.Printf("Error occurs when deleting: %v", err)
134 } else {
135 fmt.Printf("%s", queryResp.String())
136 }
137
138 time.Sleep(5 * time.Second)
139 fmt.Println("Query again which shoud return null.")
140 queryParam.Delete = false
141 if queryResp, err := tsdbClient.Query(queryParam); err != nil {
142 fmt.Printf("Error occurs when quering: %v", err)
143 } else {
144 fmt.Printf("%s", queryResp.String())
145 }
146 fmt.Println("Finish testing POST /api/query to delete.")
147
148 //3. GET /api/aggregators
149 fmt.Println("Begin to test GET /api/aggregators.")
150 aggreResp, err := tsdbClient.Aggregators()
151 if err != nil {
152 fmt.Printf("Error occurs when acquiring aggregators: %v", err)
153 } else {
154 fmt.Printf("%s", aggreResp.String())
155 }
156 fmt.Println("Finish testing GET /api/aggregators.")
157
158 //4. GET /api/config
159 fmt.Println("Begin to test GET /api/config.")
160 configResp, err := tsdbClient.Config()
161 if err != nil {
162 fmt.Printf("Error occurs when acquiring config info: %v", err)
163 } else {
164 fmt.Printf("%s", configResp.String())
165 }
166 fmt.Println("Finish testing GET /api/config.")
167
168 //5. Get /api/serializers
169 fmt.Println("Begin to test GET /api/serializers.")
170 serilResp, err := tsdbClient.Serializers()
171 if err != nil {
172 fmt.Printf("Error occurs when acquiring serializers info: %v", err)
173 } else {
174 fmt.Printf("%s", serilResp.String())
175 }
176 fmt.Println("Finish testing GET /api/serializers.")
177
178 //6. Get /api/stats
179 fmt.Println("Begin to test GET /api/stats.")
180 statsResp, err := tsdbClient.Stats()
181 if err != nil {
182 fmt.Printf("Error occurs when acquiring stats info: %v", err)
183 } else {
184 fmt.Printf("%s", statsResp.String())
185 }
186 fmt.Println("Finish testing GET /api/stats.")
187
188 //7. Get /api/suggest
189 fmt.Println("Begin to test GET /api/suggest.")
190 typeValues := []string{client.TypeMetrics, client.TypeTagk, client.TypeTagv}
191 for _, typeItem := range typeValues {
192 sugParam := client.SuggestParam{
193 Type: typeItem,
194 }
195 fmt.Printf(" Send suggest param: %s", sugParam.String())
196 sugResp, err := tsdbClient.Suggest(sugParam)
197 if err != nil {
198 fmt.Printf(" Error occurs when acquiring suggest info: %v\n", err)
199 } else {
200 fmt.Printf(" Recevie response: %s\n", sugResp.String())
201 }
202 }
203 fmt.Println("Finish testing GET /api/suggest.")
204
205 //8. Get /api/version
206 fmt.Println("Begin to test GET /api/version.")
207 versionResp, err := tsdbClient.Version()
208 if err != nil {
209 fmt.Printf("Error occurs when acquiring version info: %v", err)
210 } else {
211 fmt.Printf("%s", versionResp.String())
212 }
213 fmt.Println("Finish testing GET /api/version.")
214
215 //9. Get /api/dropcaches
216 fmt.Println("Begin to test GET /api/dropcaches.")
217 dropResp, err := tsdbClient.Dropcaches()
218 if err != nil {
219 fmt.Printf("Error occurs when acquiring dropcaches info: %v", err)
220 } else {
221 fmt.Printf("%s", dropResp.String())
222 }
223 fmt.Println("Finish testing GET /api/dropcaches.")
224
225 //10. POST /api/annotation
226 fmt.Println("Begin to test POST /api/annotation.")
227 custom := make(map[string]string, 0)
228 custom["owner"] = "bluebreezecf"
229 custom["host"] = "bluebreezecf-host"
230 addedST := time.Now().Unix()
231 addedTsuid := "000001000001000002"
232 anno := client.Annotation{
233 StartTime: addedST,
234 Tsuid: addedTsuid,
235 Description: "bluebreezecf test annotation",
236 Notes: "These would be details about the event, the description is just a summary",
237 Custom: custom,
238 }
239 if queryAnnoResp, err := tsdbClient.UpdateAnnotation(anno); err != nil {
240 fmt.Printf("Error occurs when posting annotation info: %v", err)
241 } else {
242 fmt.Printf("%s", queryAnnoResp.String())
243 }
244 fmt.Println("Finish testing POST /api/annotation.")
245
246 //11. GET /api/annotation
247 fmt.Println("Begin to test GET /api/annotation.")
248 queryAnnoMap := make(map[string]interface{}, 0)
249 queryAnnoMap[client.AnQueryStartTime] = addedST
250 queryAnnoMap[client.AnQueryTSUid] = addedTsuid
251 if queryAnnoResp, err := tsdbClient.QueryAnnotation(queryAnnoMap); err != nil {
252 fmt.Printf("Error occurs when acquiring annotation info: %v", err)
253 } else {
254 fmt.Printf("%s", queryAnnoResp.String())
255 }
256 fmt.Println("Finish testing GET /api/annotation.")
257
258 //12. GET /api/annotation
259 fmt.Println("Begin to test DELETE /api/annotation.")
260 if queryAnnoResp, err := tsdbClient.DeleteAnnotation(anno); err != nil {
261 fmt.Printf("Error occurs when deleting annotation info: %v", err)
262 } else {
263 fmt.Printf("%s", queryAnnoResp.String())
264 }
265 fmt.Println("Finish testing DELETE /api/annotation.")
266
267 //13. POST /api/annotation/bulk
268 fmt.Println("Begin to test POST /api/annotation/bulk.")
269 anns := make([]client.Annotation, 0)
270 bulkAnnNum := 4
271 i = 0
272 bulkAddBeginST := time.Now().Unix()
273 addedTsuids := make([]string, bulkAnnNum)
274 for {
275 if i < bulkAnnNum-1 {
276 addedST := time.Now().Unix()
277 addedTsuid := fmt.Sprintf("%s%d", "00000100000100000", i)
278 addedTsuids = append(addedTsuids, addedTsuid)
279 anno := client.Annotation{
280 StartTime: addedST,
281 Tsuid: addedTsuid,
282 Description: "bluebreezecf test annotation",
283 Notes: "These would be details about the event, the description is just a summary",
284 }
285 anns = append(anns, anno)
286 i++
287 } else {
288 break
289 }
290 }
291 if bulkAnnoResp, err := tsdbClient.BulkUpdateAnnotations(anns); err != nil {
292 fmt.Printf("Error occurs when posting bulk annotation info: %v", err)
293 } else {
294 fmt.Printf("%s", bulkAnnoResp.String())
295 }
296 fmt.Println("Finish testing POST /api/annotation/bulk.")
297
298 //14. DELETE /api/annotation/bulk
299 fmt.Println("Begin to test DELETE /api/annotation/bulk.")
300 bulkAnnoDelete := client.BulkAnnoDeleteInfo{
301 StartTime: bulkAddBeginST,
302 Tsuids: addedTsuids,
303 Global: false,
304 }
305 if bulkAnnoResp, err := tsdbClient.BulkDeleteAnnotations(bulkAnnoDelete); err != nil {
306 fmt.Printf("Error occurs when deleting bulk annotation info: %v", err)
307 } else {
308 fmt.Printf("%s", bulkAnnoResp.String())
309 }
310 fmt.Println("Finish testing DELETE /api/annotation/bulk.")
311
312 //15. GET /api/uid/uidmeta
313 fmt.Println("Begin to test GET /api/uid/uidmeta.")
314 metaQueryParam := make(map[string]string, 0)
315 metaQueryParam["type"] = client.TypeMetrics
316 metaQueryParam["uid"] = "00003A"
317 if resp, err := tsdbClient.QueryUIDMetaData(metaQueryParam); err != nil {
318 fmt.Printf("Error occurs when querying uidmetadata info: %v", err)
319 } else {
320 fmt.Printf("%s", resp.String())
321 }
322
323 fmt.Println("Finish testing GET /api/uid/uidmeta.")
324
325 //16. POST /api/uid/uidmeta
326 fmt.Println("Begin to test POST /api/uid/uidmeta.")
327 uidMetaData := client.UIDMetaData{
328 Uid: "00002A",
329 Type: "metric",
330 DisplayName: "System CPU Time",
331 }
332 if resp, err := tsdbClient.UpdateUIDMetaData(uidMetaData); err != nil {
333 fmt.Printf("Error occurs when posting uidmetadata info: %v", err)
334 } else {
335 fmt.Printf("%s", resp.String())
336 }
337 fmt.Println("Finish testing POST /api/uid/uidmeta.")
338
339 //17. DELETE /api/uid/uidmeta
340 fmt.Println("Begin to test DELETE /api/uid/uidmeta.")
341 uidMetaData = client.UIDMetaData{
342 Uid: "00003A",
343 Type: "metric",
344 }
345 if resp, err := tsdbClient.DeleteUIDMetaData(uidMetaData); err != nil {
346 fmt.Printf("Error occurs when deleting uidmetadata info: %v", err)
347 } else {
348 fmt.Printf("%s", resp.String())
349 }
350 fmt.Println("Finish testing DELETE /api/uid/uidmeta.")
351
352 //18. POST /api/uid/assign
353 fmt.Println("Begin to test POST /api/uid/assign.")
354 metrics := []string{"sys.cpu.0", "sys.cpu.1", "illegal!character"}
355 tagk := []string{"host"}
356 tagv := []string{"web01", "web02", "web03"}
357 assignParam := client.UIDAssignParam{
358 Metric: metrics,
359 Tagk: tagk,
360 Tagv: tagv,
361 }
362 if resp, err := tsdbClient.AssignUID(assignParam); err != nil {
363 fmt.Printf("Error occurs when assgining uid info: %v", err)
364 } else {
365 fmt.Printf("%s", resp.String())
366 }
367 fmt.Println("Finish testing POST /api/uid/assign.")
368
369 //19. GET /api/uid/tsmeta
370 fmt.Println("Begin to test GET /api/uid/tsmeta.")
371 if resp, err := tsdbClient.QueryTSMetaData("000001000001000001"); err != nil {
372 fmt.Printf("Error occurs when querying tsmetadata info: %v", err)
373 } else {
374 fmt.Printf("%s", resp.String())
375 }
376 fmt.Println("Finish testing GET /api/uid/tsmeta.")
377
378 //20. POST /api/uid/tsmeta
379 fmt.Println("Begin to test POST /api/uid/tsmeta.")
380 custom = make(map[string]string, 0)
381 custom["owner"] = "bluebreezecf"
382 custom["department"] = "paas dep"
383 tsMetaData := client.TSMetaData{
384 Tsuid: "000001000001000001",
385 DisplayName: "System CPU Time for Webserver 01",
386 Custom: custom,
387 }
388 if resp, err := tsdbClient.UpdateTSMetaData(tsMetaData); err != nil {
389 fmt.Printf("Error occurs when posting tsmetadata info: %v", err)
390 } else {
391 fmt.Printf("%s", resp.String())
392 }
393 fmt.Println("Finish testing POST /api/uid/tsmeta.")
394
395 //21. DELETE /api/uid/tsmeta
396 fmt.Println("Begin to test DELETE /api/uid/tsmeta.")
397 tsMetaData = client.TSMetaData{
398 Tsuid: "000001000001000001",
399 }
400 if resp, err := tsdbClient.DeleteTSMetaData(tsMetaData); err != nil {
401 fmt.Printf("Error occurs when deleting tsmetadata info: %v", err)
402 } else {
403 fmt.Printf("%s", resp.String())
404 }
405 fmt.Println("Finish testing DELETE /api/uid/tsmeta.")
406 }