Skip to content

Commit

Permalink
z1651 (#96)
Browse files Browse the repository at this point in the history
* add --follow param to service log command
  • Loading branch information
kawaiiyoshiyuki authored Sep 27, 2022
1 parent afdb2f6 commit 5b1ba94
Show file tree
Hide file tree
Showing 15 changed files with 270 additions and 109 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v0.12.9] - 2022-09-27

### Added
- `--follow` flag for `zcli service logs` command to receive continuous stream of logs

## [v0.12.8] - 2022-09-26

### Added
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/briandowns/spinner v1.18.1
github.com/ghodss/yaml v1.0.0
github.com/golang/protobuf v1.5.2
github.com/gorilla/websocket v1.5.0
github.com/judwhite/go-svc v1.2.1
github.com/lxc/lxd v0.0.0-20220922224603-c76bc42c6393
github.com/miekg/dns v1.1.50
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
Expand Down
3 changes: 2 additions & 1 deletion src/cliAction/serviceLogs/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const JSON = "JSON"
const JSONSTREAM = "JSONSTREAM"
const AT = "@"
const UPLOADING = "UPLOADING"
const HTTP = "http://"
const HTTPS = "https://"
const WSS = "wss://"
const RFC5424 = "5424"
const RFC3164 = "3164"
1 change: 1 addition & 0 deletions src/cliAction/serviceLogs/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Handler struct {
httpClient *httpClient.Handler
apiGrpcClient zBusinessZeropsApiProtocol.ZBusinessZeropsApiProtocolClient
sdkConfig sdkConfig.Config
LastMsgId string
}

func New(config Config, httpClient *httpClient.Handler, apiGrpcClient zBusinessZeropsApiProtocol.ZBusinessZeropsApiProtocolClient, sdkConfig sdkConfig.Config) *Handler {
Expand Down
9 changes: 9 additions & 0 deletions src/cliAction/serviceLogs/handler_checkInputValues.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type InputValues struct {
facility int
format string
formatTemplate string
mode string
}

func (h *Handler) checkInputValues(config RunConfig) (inputValues InputValues, err error) {
Expand All @@ -35,12 +36,20 @@ func (h *Handler) checkInputValues(config RunConfig) (inputValues InputValues, e
return inputValues, err
}

mode := RESPONSE
if config.Follow {
mode = STREAM
if format == JSON {
return inputValues, fmt.Errorf("%s", i18n.LogFormatStreamMismatch)
}
}
return InputValues{
limit: int(limit),
minSeverity: severity,
facility: facility,
format: format,
formatTemplate: formatTemplate,
mode: mode,
}, nil
}

Expand Down
56 changes: 56 additions & 0 deletions src/cliAction/serviceLogs/handler_formatLogs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package serviceLogs

import (
"encoding/json"
"fmt"
)

func parseResponseByFormat(jsonData Response, format, formatTemplate, mode string) error {
var err error

logs := jsonData.Items
if mode == RESPONSE {
logs = reverseLogs(logs)
}

if format == FULL {
if formatTemplate != "" {
if err = getFullWithTemplate(logs, formatTemplate); err != nil {
return err
}
return nil
} else {
// TODO get rfc from config when implemented as flag
getFullByRfc(logs, RFC5424)
return nil
}
} else if format == SHORT {
for _, o := range logs {
fmt.Printf("%v %s \n", o.Timestamp, o.Content)
}
} else if format == JSONSTREAM {
for _, o := range logs {
val, err := json.Marshal(o)
if err != nil {
return err
}
fmt.Println(string(val))
}
} else {
val, err := json.Marshal(logs)
if err != nil {
return err
}
fmt.Println(string(val))
}

return nil
}

// reverseLogs makes log order ASC to get the last logs of given limit
func reverseLogs(data []Data) []Data {
for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
data[i], data[j] = data[j], data[i]
}
return data
}
1 change: 1 addition & 0 deletions src/cliAction/serviceLogs/handler_getContainerId.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func (h *Handler) getContainerId(ctx context.Context, sdkConfig sdkConfig.Config
Operator: "eq",
Value: types.String(serviceId),
})

var sortData []body.EsSortItem
sortData = append(sortData, body.EsSortItem{
Name: "number",
Expand Down
91 changes: 9 additions & 82 deletions src/cliAction/serviceLogs/handler_getLogs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@ package serviceLogs
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"

"github.com/zeropsio/zerops-go/dto/output"
"github.com/zeropsio/zerops-go/types"
)

type Response struct {
Expand Down Expand Up @@ -38,7 +33,7 @@ type Data struct {
Message string `json:"message"`
}

func getLogs(ctx context.Context, method, url, format, formatTemplate string) error {
func getLogs(ctx context.Context, method, url, format, formatTemplate, mode string) error {
c := http.Client{Timeout: time.Duration(1) * time.Minute}

req, err := http.NewRequest(method, url, nil)
Expand All @@ -61,90 +56,22 @@ func getLogs(ctx context.Context, method, url, format, formatTemplate string) er
return err
}

err = parseResponseByFormat(body, format, formatTemplate)
jsonData, err := parseResponse(body)
if err != nil {
return err
}
return nil
}

func parseResponseByFormat(body []byte, format, formatTemplate string) error {
var err error

var jsonData Response
err = json.Unmarshal(body, &jsonData)
err = parseResponseByFormat(jsonData, format, formatTemplate, mode)
if err != nil {
return err
}

logs := jsonData.Items
ascLogs := reverseLogs(logs)

if format == FULL {
if formatTemplate != "" {
if err = getFullWithTemplate(ascLogs, formatTemplate); err != nil {
return err
}
return nil
} else {
// TODO get rfc from config when implemented as flag
getFullByRfc(ascLogs, RFC5424)
return nil
}
} else if format == SHORT {
for _, o := range ascLogs {
fmt.Printf("%v %s \n", o.Timestamp, o.Content)
}
} else if format == JSONSTREAM {
for _, o := range ascLogs {
val, err := json.Marshal(o)
if err != nil {
return err
}
fmt.Println(string(val))
}
} else {
val, err := json.Marshal(ascLogs)
if err != nil {
return err
}
fmt.Println(string(val))
}

return nil
}

// reverseLogs makes log order ASC to get the last logs of given limit
func reverseLogs(data []Data) []Data {
for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
data[i], data[j] = data[j], data[i]
}
return data
}

func getLogRequestData(resOutput output.ProjectLog) (string, string, types.DateTime) {
outputUrl := string(resOutput.Url)
urlData := strings.Split(outputUrl, " ")
method, url := urlData[0], urlData[1]

// TODO enable token when websocket is used and return it
// accessToken := resOutput.AccessToken
expiration := resOutput.Expiration

return method, HTTP + url, expiration
}

func makeQueryParams(limit, facility, minSeverity int, logServiceId, containerId string) string {
query := fmt.Sprintf("&limit=%d&desc=1&facility=%d&serviceStackId=%s",
limit, facility, logServiceId)

if minSeverity != -1 {
query += fmt.Sprintf("&minimumSeverity=%d", minSeverity)
}

if containerId != "" {
query += fmt.Sprintf("&containerId=%s", containerId)
func parseResponse(body []byte) (Response, error) {
var jsonData Response
err := json.Unmarshal(body, &jsonData)
if err != nil || len(jsonData.Items) == 0 {
return Response{}, err
}

return query
return jsonData, nil
}
23 changes: 16 additions & 7 deletions src/cliAction/serviceLogs/handler_getServiceLogUrl.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ package serviceLogs
import (
"context"
"fmt"
"github.com/zeropsio/zerops-go/dto/output"
"net/http"
"strings"
"time"

"github.com/zerops-io/zcli/src/i18n"
"github.com/zerops-io/zcli/src/utils/sdkConfig"
"github.com/zeropsio/zerops-go/dto/input/path"
"github.com/zeropsio/zerops-go/sdk"
"github.com/zeropsio/zerops-go/sdkBase"
"github.com/zeropsio/zerops-go/types"
"github.com/zeropsio/zerops-go/types/uuid"
)

func (h *Handler) getServiceLogResData(ctx context.Context, sdkConfig sdkConfig.Config, projectId string) (string, string, types.DateTime, error) {
func (h *Handler) getServiceLogResData(ctx context.Context, sdkConfig sdkConfig.Config, projectId string) (string, string, error) {
zdk := sdk.New(
sdkBase.DefaultConfig(sdkBase.WithCustomEndpoint(sdkConfig.RegionUrl)),
&http.Client{Timeout: 1 * time.Minute},
Expand All @@ -25,13 +26,21 @@ func (h *Handler) getServiceLogResData(ctx context.Context, sdkConfig sdkConfig.

response, err := authorizedSdk.GetProjectLog(ctx, path.ProjectId{Id: uuid.ProjectId(projectId)})
if err != nil {
return "", "", types.DateTime{}, err
return "", "", err
}

resOutput, err := response.Output()
if err != nil { // TODO parse meta data
return "", "", types.DateTime{}, fmt.Errorf("%s %v", i18n.LogAccessFailed, err)
if err != nil {
return "", "", fmt.Errorf("%s %v", i18n.LogAccessFailed, err)
}
method, url, expiration := getLogRequestData(resOutput)
return method, url, expiration, nil
method, url := getLogRequestData(resOutput)
return method, url, nil
}

func getLogRequestData(resOutput output.ProjectLog) (string, string) {
outputUrl := string(resOutput.Url)
urlData := strings.Split(outputUrl, " ")
method, url := urlData[0], urlData[1]

return method, url
}
59 changes: 59 additions & 0 deletions src/cliAction/serviceLogs/handler_printLogs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package serviceLogs

import (
"context"
"fmt"
"strings"
)

func (h *Handler) printLogs(ctx context.Context, config RunConfig, inputs InputValues, containerId, logServiceId, projectId string) error {
method, url, err := h.getServiceLogResData(ctx, h.sdkConfig, projectId)
if err != nil {
return err
}

query := makeQueryParams(inputs, logServiceId, containerId)

if inputs.mode == RESPONSE {
err = getLogs(ctx, method, HTTPS+url+query, inputs.format, inputs.formatTemplate, inputs.mode)
if err != nil {
return err
}
}
if inputs.mode == STREAM {
wsUrl := getWsUrl(url)
err := h.getLogStream(ctx, config, inputs, wsUrl, query, containerId, logServiceId, projectId)
if err != nil {
return err
}
}
return nil
}

func makeQueryParams(inputs InputValues, logServiceId, containerId string) string {
query := fmt.Sprintf("&limit=%d&desc=%d&facility=%d&serviceStackId=%s",
inputs.limit, getDesc(inputs.mode), inputs.facility, logServiceId)

if inputs.minSeverity != -1 {
query += fmt.Sprintf("&minimumSeverity=%d", inputs.minSeverity)
}

if containerId != "" {
query += fmt.Sprintf("&containerId=%s", containerId)
}

return query
}

func getDesc(mode string) int {
if mode == RESPONSE {
return 1
}
return 0
}

func getWsUrl(apiUrl string) string {
urlSplit := strings.Split(apiUrl, "?")
url, token := urlSplit[0], urlSplit[1]
return url + "/stream?" + token
}
11 changes: 1 addition & 10 deletions src/cliAction/serviceLogs/handler_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package serviceLogs
import (
"context"
"fmt"

"github.com/zerops-io/zcli/src/i18n"
"github.com/zerops-io/zcli/src/utils/projectService"
)
Expand Down Expand Up @@ -52,15 +51,7 @@ func (h *Handler) Run(ctx context.Context, config RunConfig) error {
}
}

// TODO when websocket is implemented, replace _ with expiration
method, url, _, err := h.getServiceLogResData(ctx, h.sdkConfig, projectId)
if err != nil {
return err
}

query := makeQueryParams(inputs.limit, inputs.facility, inputs.minSeverity, logServiceId, containerId)
err = getLogs(ctx, method, url+query, inputs.format, inputs.formatTemplate)
if err != nil {
if err = h.printLogs(ctx, config, inputs, containerId, logServiceId, projectId); err != nil {
return err
}

Expand Down
Loading

0 comments on commit 5b1ba94

Please sign in to comment.