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  }