Skip to content

Commit

Permalink
feat: support streaming of rule logs
Browse files Browse the repository at this point in the history
  • Loading branch information
danya committed Jan 14, 2025
1 parent 7ea959a commit f1228d5
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/enapter/enapter-cli
go 1.21

require (
github.com/gorilla/websocket v1.5.3
github.com/stretchr/testify v1.9.0
github.com/urfave/cli/v2 v2.27.4
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
Expand Down
33 changes: 33 additions & 0 deletions internal/app/enaptercli/cmd_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"net/url"
"strings"

"github.com/gorilla/websocket"
"github.com/urfave/cli/v2"
)

Expand Down Expand Up @@ -122,6 +123,38 @@ func (c *cmdBase) doHTTPRequest(ctx context.Context, p doHTTPRequestParams) erro
return p.RespProcessor(resp)
}

func (c *cmdBase) dialWebSocket(ctx context.Context, path string) (*websocket.Conn, error) {
url, err := url.Parse(c.apiHost + "/v3" + path)
if err != nil {
return nil, fmt.Errorf("parse url: %w", err)
}

switch url.Scheme {
case "https":
url.Scheme = "wss"
case "http":
url.Scheme = "ws"
}

headers := make(http.Header)
headers.Add("X-Enapter-Auth-Token", c.token)

if c.verbose {
fmt.Fprintf(c.writer, "== Dialing WebSocket at %s\n", url.String())
}

//nolint:bodyclose // body should be closed by callers
conn, resp, err := websocket.DefaultDialer.DialContext(ctx, url.String(), headers)
if err != nil {
return nil, fmt.Errorf("dial: %w", err)
}
if resp.StatusCode != http.StatusSwitchingProtocols {
return nil, cli.Exit(parseRespErrorMessage(resp), 1)
}

return conn, nil
}

func (c *cmdBase) defaultRespProcessor(resp *http.Response) error {
if resp.StatusCode != http.StatusOK {
return cli.Exit(parseRespErrorMessage(resp), 1)
Expand Down
1 change: 1 addition & 0 deletions internal/app/enaptercli/cmd_rule_engine_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func buildCmdRuleEngineRule() *cli.Command {
buildCmdRuleEngineRuleList(),
buildCmdRuleEngineRuleUpdate(),
buildCmdRuleEngineRuleUpdateScript(),
buildCmdRuleEngineRuleLogs(),
},
}
}
Expand Down
87 changes: 87 additions & 0 deletions internal/app/enaptercli/cmd_rule_engine_rule_logs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package enaptercli

import (
"encoding/json"
"fmt"
"time"

"github.com/urfave/cli/v2"
)

type cmdRuleEngineRuleLogs struct {
cmdRuleEngineRule
ruleID string
follow bool
}

func buildCmdRuleEngineRuleLogs() *cli.Command {
cmd := &cmdRuleEngineRuleLogs{}
return &cli.Command{
Name: "logs",
Usage: "Show rule logs",
CustomHelpTemplate: cmd.HelpTemplate(),
Flags: cmd.Flags(),
Before: cmd.Before,
Action: func(cliCtx *cli.Context) error {
return cmd.do(cliCtx)
},
}
}

func (c *cmdRuleEngineRuleLogs) Flags() []cli.Flag {
return append(c.cmdRuleEngineRule.Flags(),
&cli.StringFlag{
Name: "rule-id",
Usage: "rule ID",
Destination: &c.ruleID,
Required: true,
},
&cli.BoolFlag{
Name: "follow",
Aliases: []string{"f"},
Usage: "follow log output",
Destination: &c.follow,
},
)
}

func (c *cmdRuleEngineRuleLogs) do(cliCtx *cli.Context) error {
if !c.follow {
return cli.Exit("Currently, only follow mode (--follow) is supported.", 1)
}

path := fmt.Sprintf("/site/rule_engine/rules/%s/logs/ws", c.ruleID)
conn, err := c.dialWebSocket(cliCtx.Context, path)
if err != nil {
return fmt.Errorf("connect: %w", err)
}

go func() {
<-cliCtx.Done()
conn.Close()
}()

for {
_, r, err := conn.NextReader()
if err != nil {
select {
case <-cliCtx.Done():
return nil
default:
return fmt.Errorf("read: %w", err)
}
}

var msg struct {
Timestamp int64 `json:"timestamp"`
Severity string `json:"severity"`
Message string `json:"message"`
}
if err := json.NewDecoder(r).Decode(&msg); err != nil {
return fmt.Errorf("parse payload: %w", err)
}

ts := time.Unix(msg.Timestamp, 0).Format(time.RFC3339)
fmt.Fprintf(c.writer, "%s [%s] %s\n", ts, msg.Severity, msg.Message)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ COMMANDS:
list List rules
update Update a rule
update-script Update the script of a rule
logs Show rule logs
help, h Shows a list of commands or help for one command

OPTIONS:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
NAME:
enaptercli.test rule-engine rule logs - Show rule logs

USAGE:
enaptercli.test rule-engine rule logs [command options]

OPTIONS:
--verbose log extra details about operation (default: false)
--rule-id value rule ID
--follow, -f follow log output (default: false)
--help, -h show help

ENVIRONMENT VARIABLES:
ENAPTER3_API_TOKEN Enapter API access token
ENAPTER3_API_HOST Enapter API base URL (https://api.enapter.com by default)

0 comments on commit f1228d5

Please sign in to comment.