github.com/astaxie/beego@v1.12.3/logs/alils/log_store.go (about) 1 package alils 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "net/http/httputil" 9 "strconv" 10 11 lz4 "github.com/cloudflare/golz4" 12 "github.com/gogo/protobuf/proto" 13 ) 14 15 // LogStore Store the logs 16 type LogStore struct { 17 Name string `json:"logstoreName"` 18 TTL int 19 ShardCount int 20 21 CreateTime uint32 22 LastModifyTime uint32 23 24 project *LogProject 25 } 26 27 // Shard define the Log Shard 28 type Shard struct { 29 ShardID int `json:"shardID"` 30 } 31 32 // ListShards returns shard id list of this logstore. 33 func (s *LogStore) ListShards() (shardIDs []int, err error) { 34 h := map[string]string{ 35 "x-sls-bodyrawsize": "0", 36 } 37 38 uri := fmt.Sprintf("/logstores/%v/shards", s.Name) 39 r, err := request(s.project, "GET", uri, h, nil) 40 if err != nil { 41 return 42 } 43 44 buf, err := ioutil.ReadAll(r.Body) 45 if err != nil { 46 return 47 } 48 49 if r.StatusCode != http.StatusOK { 50 errMsg := &errorMessage{} 51 err = json.Unmarshal(buf, errMsg) 52 if err != nil { 53 err = fmt.Errorf("failed to list logstore") 54 dump, _ := httputil.DumpResponse(r, true) 55 fmt.Println(dump) 56 return 57 } 58 err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) 59 return 60 } 61 62 var shards []*Shard 63 err = json.Unmarshal(buf, &shards) 64 if err != nil { 65 return 66 } 67 68 for _, v := range shards { 69 shardIDs = append(shardIDs, v.ShardID) 70 } 71 return 72 } 73 74 // PutLogs put logs into logstore. 75 // The callers should transform user logs into LogGroup. 76 func (s *LogStore) PutLogs(lg *LogGroup) (err error) { 77 body, err := proto.Marshal(lg) 78 if err != nil { 79 return 80 } 81 82 // Compresse body with lz4 83 out := make([]byte, lz4.CompressBound(body)) 84 n, err := lz4.Compress(body, out) 85 if err != nil { 86 return 87 } 88 89 h := map[string]string{ 90 "x-sls-compresstype": "lz4", 91 "x-sls-bodyrawsize": fmt.Sprintf("%v", len(body)), 92 "Content-Type": "application/x-protobuf", 93 } 94 95 uri := fmt.Sprintf("/logstores/%v", s.Name) 96 r, err := request(s.project, "POST", uri, h, out[:n]) 97 if err != nil { 98 return 99 } 100 101 buf, err := ioutil.ReadAll(r.Body) 102 if err != nil { 103 return 104 } 105 106 if r.StatusCode != http.StatusOK { 107 errMsg := &errorMessage{} 108 err = json.Unmarshal(buf, errMsg) 109 if err != nil { 110 err = fmt.Errorf("failed to put logs") 111 dump, _ := httputil.DumpResponse(r, true) 112 fmt.Println(dump) 113 return 114 } 115 err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) 116 return 117 } 118 return 119 } 120 121 // GetCursor gets log cursor of one shard specified by shardID. 122 // The from can be in three form: a) unix timestamp in seccond, b) "begin", c) "end". 123 // For more detail please read: http://gitlab.alibaba-inc.com/sls/doc/blob/master/api/shard.md#logstore 124 func (s *LogStore) GetCursor(shardID int, from string) (cursor string, err error) { 125 h := map[string]string{ 126 "x-sls-bodyrawsize": "0", 127 } 128 129 uri := fmt.Sprintf("/logstores/%v/shards/%v?type=cursor&from=%v", 130 s.Name, shardID, from) 131 132 r, err := request(s.project, "GET", uri, h, nil) 133 if err != nil { 134 return 135 } 136 137 buf, err := ioutil.ReadAll(r.Body) 138 if err != nil { 139 return 140 } 141 142 if r.StatusCode != http.StatusOK { 143 errMsg := &errorMessage{} 144 err = json.Unmarshal(buf, errMsg) 145 if err != nil { 146 err = fmt.Errorf("failed to get cursor") 147 dump, _ := httputil.DumpResponse(r, true) 148 fmt.Println(dump) 149 return 150 } 151 err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) 152 return 153 } 154 155 type Body struct { 156 Cursor string 157 } 158 body := &Body{} 159 160 err = json.Unmarshal(buf, body) 161 if err != nil { 162 return 163 } 164 cursor = body.Cursor 165 return 166 } 167 168 // GetLogsBytes gets logs binary data from shard specified by shardID according cursor. 169 // The logGroupMaxCount is the max number of logGroup could be returned. 170 // The nextCursor is the next curosr can be used to read logs at next time. 171 func (s *LogStore) GetLogsBytes(shardID int, cursor string, 172 logGroupMaxCount int) (out []byte, nextCursor string, err error) { 173 174 h := map[string]string{ 175 "x-sls-bodyrawsize": "0", 176 "Accept": "application/x-protobuf", 177 "Accept-Encoding": "lz4", 178 } 179 180 uri := fmt.Sprintf("/logstores/%v/shards/%v?type=logs&cursor=%v&count=%v", 181 s.Name, shardID, cursor, logGroupMaxCount) 182 183 r, err := request(s.project, "GET", uri, h, nil) 184 if err != nil { 185 return 186 } 187 188 buf, err := ioutil.ReadAll(r.Body) 189 if err != nil { 190 return 191 } 192 193 if r.StatusCode != http.StatusOK { 194 errMsg := &errorMessage{} 195 err = json.Unmarshal(buf, errMsg) 196 if err != nil { 197 err = fmt.Errorf("failed to get cursor") 198 dump, _ := httputil.DumpResponse(r, true) 199 fmt.Println(dump) 200 return 201 } 202 err = fmt.Errorf("%v:%v", errMsg.Code, errMsg.Message) 203 return 204 } 205 206 v, ok := r.Header["X-Sls-Compresstype"] 207 if !ok || len(v) == 0 { 208 err = fmt.Errorf("can't find 'x-sls-compresstype' header") 209 return 210 } 211 if v[0] != "lz4" { 212 err = fmt.Errorf("unexpected compress type:%v", v[0]) 213 return 214 } 215 216 v, ok = r.Header["X-Sls-Cursor"] 217 if !ok || len(v) == 0 { 218 err = fmt.Errorf("can't find 'x-sls-cursor' header") 219 return 220 } 221 nextCursor = v[0] 222 223 v, ok = r.Header["X-Sls-Bodyrawsize"] 224 if !ok || len(v) == 0 { 225 err = fmt.Errorf("can't find 'x-sls-bodyrawsize' header") 226 return 227 } 228 bodyRawSize, err := strconv.Atoi(v[0]) 229 if err != nil { 230 return 231 } 232 233 out = make([]byte, bodyRawSize) 234 err = lz4.Uncompress(buf, out) 235 if err != nil { 236 return 237 } 238 239 return 240 } 241 242 // LogsBytesDecode decodes logs binary data retruned by GetLogsBytes API 243 func LogsBytesDecode(data []byte) (gl *LogGroupList, err error) { 244 245 gl = &LogGroupList{} 246 err = proto.Unmarshal(data, gl) 247 if err != nil { 248 return 249 } 250 251 return 252 } 253 254 // GetLogs gets logs from shard specified by shardID according cursor. 255 // The logGroupMaxCount is the max number of logGroup could be returned. 256 // The nextCursor is the next curosr can be used to read logs at next time. 257 func (s *LogStore) GetLogs(shardID int, cursor string, 258 logGroupMaxCount int) (gl *LogGroupList, nextCursor string, err error) { 259 260 out, nextCursor, err := s.GetLogsBytes(shardID, cursor, logGroupMaxCount) 261 if err != nil { 262 return 263 } 264 265 gl, err = LogsBytesDecode(out) 266 if err != nil { 267 return 268 } 269 270 return 271 }