Skip to content

Commit

Permalink
Add tailing functionality (#9)
Browse files Browse the repository at this point in the history
* add --follow flag
* allow printing logs in live mode
* update group flag usage
  • Loading branch information
jskiba authored Jul 10, 2024
1 parent af593d6 commit 6757cfa
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 19 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ Small standalone command line tool to retrieve and search recent app
server logs from [Solarwinds].

### This is v1 of the swo-cli and it supports ONLY logs search.
### This is v1 of the swo-cli and it DOES NOT support tailing.

Supports optional Boolean search queries. Example:
Supports optional Boolean search queries and polling for new events (like "tail -f"). Example:

$ swo logs "(www OR db) (nginx OR pgsql) -accepted"
$ swo logs -f "(www OR db) (nginx OR pgsql) -accepted"

## Quick Start

Expand Down Expand Up @@ -114,7 +113,7 @@ If you frequently pipe output to a certain command, create a function which
accepts optional arguments, invokes `swo` with any arguments, and pipes
output to that command. For example, this `swocolor` function will pipe to `lnav`:

$ function swocolor() { swo logs $* | lnav; }
$ function swocolor() { swo logs -f $* | lnav; }

Add the `function` line to your `~/.bashrc`. It can be invoked with search
parameters:
Expand Down Expand Up @@ -167,7 +166,7 @@ even though one is for 4 words (AND) while the other is for a phrase:

### Multiple API tokens

To use multiple API tokens (such as for separate home and work SolarWinds Observability
To use multiple API tokens (such as for separate home and work SolarWinds Observability
accounts), create a `.swo-cli.yml` configuration file in each project's
working directory and invoke the CLI in that directory. The CLI checks for
`.swo-cli.yml` in the current working directory prior to using
Expand Down
3 changes: 2 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
| Version | Supported |
|---------| ------------------ |
| 1.1.x | :white_check_mark: |
| 1.2.x | :white_check_mark: |

## Reporting a Vulnerability

To report a vulnerability, please email [email protected]. Details about our security and disclosure policies can be found at https://www.solarwinds.com/information-security.
To report a vulnerability, please email [email protected]. Details about our security and disclosure policies can be found at https://www.solarwinds.com/information-security.
7 changes: 4 additions & 3 deletions cmd/swo/main.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package main

import (
"github.com/solarwinds/swo-cli/logs"
"github.com/urfave/cli/v2"
"log"
"os"

"github.com/solarwinds/swo-cli/logs"
"github.com/urfave/cli/v2"
)

var version = "v1.1.2"
var version = "v1.2.0"

func main() {
app := &cli.App{
Expand Down
24 changes: 19 additions & 5 deletions logs/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ func (c *Client) prepareRequest(ctx context.Context, nextPage string) (*http.Req
params := url.Values{}
if nextPage == "" {
logsEndpoint, err = url.JoinPath(c.opts.ApiUrl, "v1/logs")
params.Add("direction", "forward")
if c.opts.follow {
params.Add("direction", "tail")
} else {
params.Add("direction", "forward")
}

params.Add("pageSize", "1000")

if c.opts.group != "" {
Expand Down Expand Up @@ -99,6 +104,10 @@ func (c *Client) prepareRequest(ctx context.Context, nextPage string) (*http.Req
if err != nil {
return nil, err
}

if c.opts.follow {
params.Del("endTime")
}
}

if err != nil {
Expand Down Expand Up @@ -187,15 +196,20 @@ func (c *Client) Run(ctx context.Context) error {
return err
}

if logs.NextPage == "" {
break
}

if c.opts.follow && len(logs.Logs) == 0 {
time.Sleep(2 * time.Second)
continue
}

err = c.printResult(logs.Logs)
if err != nil {
return fmt.Errorf("failed to print result: %w", err)
}

if logs.NextPage == "" {
break
}

nextPage = logs.NextPage
}

Expand Down
13 changes: 8 additions & 5 deletions logs/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ package logs

import (
"context"

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

var flags = []cli.Flag{
&cli.StringFlag{Name: "group", Aliases: []string{"g"}, Usage: "group ID to search"},
&cli.StringFlag{Name: "group", Aliases: []string{"g"}, Usage: "group name to search"},
&cli.StringFlag{Name: "min-time", Usage: "earliest time to search from", Value: "1 hour ago"},
&cli.StringFlag{Name: "max-time", Usage: "latest time to search from"},
&cli.StringFlag{Name: "system", Aliases: []string{"s"}, Usage: "system to search"},
&cli.BoolFlag{Name: "json", Aliases: []string{"j"}, Usage: "output raw JSON", Value: false},
&cli.BoolFlag{Name: "follow", Aliases: []string{"f"}, Usage: "enable live tailing", Value: false},
}

func run(cCtx *cli.Context) error {
Expand All @@ -22,6 +24,7 @@ func run(cCtx *cli.Context) error {
maxTime: cCtx.String("max-time"),
minTime: cCtx.String("min-time"),
json: cCtx.Bool("json"),
follow: cCtx.Bool("follow"),
ApiUrl: cCtx.String("api-url"),
Token: cCtx.String("api-token"),
}
Expand All @@ -46,14 +49,14 @@ func NewLogsCommand() *cli.Command {
Usage: "command-line search for SolarWinds Observability log management service",
Flags: flags,
ArgsUsage: `
EXAMPLES:
swo logs something
swo logs 1.2.3 Failure
swo logs -s ns1 "connection refused"
swo logs "(www OR db) (nginx OR pgsql) -accepted"
swo logs -g <SWO_GROUP_ID> "(nginx OR pgsql) -accepted"
swo logs --min-time 'yesterday at noon' --max-time 'today at 4am' -g <SWO_GROUP_ID>
swo logs -f "(www OR db) (nginx OR pgsql) -accepted"
swo logs -f -g <SWO_GROUP_NAME> "(nginx OR pgsql) -accepted"
swo logs --min-time 'yesterday at noon' --max-time 'today at 4am' -g <SWO_GROUP_NAME>
swo logs -- -redis
`,
Action: run,
Expand Down
10 changes: 10 additions & 0 deletions logs/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type Options struct {
maxTime string
minTime string
json bool
follow bool

ApiUrl string `yaml:"api-url"`
Token string `yaml:"token"`
Expand All @@ -68,6 +69,15 @@ func (opts *Options) Init(args []string) error {
opts.minTime = result
}

if opts.follow { // set maxTime to <now - 10s> when 'follow' flag is set, it is used only for the first request
result, err := parseTime(time.Now().Add(-10 * time.Second).Format(time.RFC3339))
if err != nil {
return errors.Join(errMaxTimeFlag, err)
}

opts.maxTime = result
}

if opts.maxTime != "" {
result, err := parseTime(opts.maxTime)
if err != nil {
Expand Down

0 comments on commit 6757cfa

Please sign in to comment.