This repository has been archived by the owner on Mar 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 098aca9
Showing
15 changed files
with
805 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pkg/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
SHELL := /bin/bash | ||
PROGRAM := cwli | ||
VERSION := v0.1.0 | ||
GOOS := $(shell go env GOOS) | ||
GOARCH := $(shell go env GOARCH) | ||
ENTRYPOINT := cmd/cwli/main.go | ||
SRC := $(wildcard *.go) $(wildcard */*.go) | ||
|
||
.PHONY: all | ||
all: $(PROGRAM) | ||
|
||
$(PROGRAM): $(SRC) lint vet | ||
go build \ | ||
-ldflags "-X github.com/winebarrel/cwli/cli.version=$(VERSION)" \ | ||
-o pkg/$(PROGRAM) $(ENTRYPOINT) | ||
|
||
.PHONY: package | ||
package: clean $(PROGRAM) | ||
gzip -c pkg/$(PROGRAM) > pkg/$(PROGRAM)-$(VERSION)-$(GOOS)-$(GOARCH).gz | ||
rm pkg/$(PROGRAM) | ||
|
||
.PHONY: lint | ||
lint: | ||
golint -set_exit_status | ||
|
||
.PHONY: vet | ||
vet: | ||
go vet | ||
|
||
.PHONY: clean | ||
clean: | ||
rm -f pkg/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# cwli | ||
|
||
## Usage | ||
|
||
``` | ||
$ cwli -h | ||
Usage of cwli: | ||
-query string | ||
Query string | ||
-showptr | ||
Show @ptr in query result | ||
-version | ||
Print version and exit | ||
``` | ||
|
||
``` | ||
$ cwli | ||
ap-northeast-1> show groups; | ||
/aws/kinesisfirehose/my-kinesis | ||
/aws/lambda/my-lambda | ||
/aws/rds/cluster/my-rds/slow-query | ||
ap-northeast-1> head /aws/lambda/my-lambda limit 1; | ||
*************************** 1. row *************************** | ||
Timestamp: 1516438129835 | ||
Message: START RequestId: bbd0dbdd-fdbe-11e7-a41f-398ced7d9303 Version: $LATEST | ||
ap-northeast-1> source /aws/lambda/my-lambda start=2018/11/19 end=2019/11/21 | field @timestamp, @message | limit 2; | ||
{"@timestamp":"2019-04-09 09:38:19.455","@message":"END RequestId: ab83228c-6af1-4c0b-a304-e043aecbe84a\n"} | ||
{"@timestamp":"2019-04-09 09:38:19.455","@message":"2019-04-09T09:38:19.455Z\tab83228c-6af1-4c0b-a304-e043aecbe84a\tLogEC2InstanceStateChange\n"} | ||
// Status: Complete | ||
// Statistics: BytesScanned=859801 RecordsMatched=2065 RecordsScanned=2065 | ||
``` | ||
|
||
### Passing to external command | ||
|
||
``` | ||
ap-northeast-1> source /aws/lambda/my-lambda start=2018/11/19 end=2019/11/21 | field @timestamp, @message ! head -n 1 | tee output.jsonl; | ||
{"@timestamp":"2019-04-09 09:38:19.455","@message":"2019-04-09T09:38:19.455Z\tab83228c-6af1-4c0b-a304-e043aecbe84a\tLogEC2InstanceStateChange\n"} | ||
``` | ||
|
||
``` | ||
$ cat output.jsonl | ||
{"@timestamp":"2019-04-09 09:38:19.455","@message":"2019-04-09T09:38:19.455Z\tab83228c-6af1-4c0b-a304-e043aecbe84a\tLogEC2InstanceStateChange\n"} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package cli | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
) | ||
|
||
var version string | ||
|
||
type Flags struct { | ||
Query string | ||
Showptr bool | ||
} | ||
|
||
func ParseFlags() (flags *Flags) { | ||
flags = &Flags{} | ||
var printVersion bool | ||
|
||
flag.StringVar(&flags.Query, "query", "", "Query string") | ||
flag.BoolVar(&flags.Showptr, "showptr", false, "Show @ptr in query result") | ||
flag.BoolVar(&printVersion, "version", false, "Print version and exit") | ||
flag.Parse() | ||
|
||
if printVersion { | ||
fmt.Println(version) | ||
os.Exit(0) | ||
} | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/winebarrel/cwli" | ||
"github.com/winebarrel/cwli/cli" | ||
) | ||
|
||
func init() { | ||
log.SetFlags(log.LstdFlags) | ||
} | ||
|
||
func main() { | ||
flags := cli.ParseFlags() | ||
runner := cwli.NewRunner(flags) | ||
runner.Run() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package cwli | ||
|
||
import ( | ||
"io" | ||
"log" | ||
"os" | ||
"os/exec" | ||
) | ||
|
||
func executeCommand(str string, input string) (err error) { | ||
cmd := exec.Command("sh", "-c", str) | ||
cmd.Stdout = os.Stdout | ||
cmd.Stderr = os.Stderr | ||
|
||
stdin, err := cmd.StdinPipe() | ||
|
||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
go func() { | ||
defer stdin.Close() | ||
io.WriteString(stdin, input) | ||
}() | ||
|
||
err = cmd.Run() | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package exec | ||
|
||
import ( | ||
"io" | ||
|
||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs" | ||
"github.com/winebarrel/cwli/cli" | ||
) | ||
|
||
type Executable interface { | ||
Start(svc *cloudwatchlogs.CloudWatchLogs, flags *cli.Flags, out io.Writer) error | ||
} | ||
|
||
var Commands = []func(string) (Executable, error){ | ||
parseHelp, | ||
parseShowGroups, | ||
parseHead, | ||
parseQuery, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package exec | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"regexp" | ||
"strconv" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs" | ||
"github.com/winebarrel/cwli/cli" | ||
) | ||
|
||
var regexpHead = regexp.MustCompile(`(?i)^head\s+(\S+)(?:\s+limit\s+([0-9]+))?\s*$`) | ||
|
||
type headCommand struct { | ||
group string | ||
limit int64 | ||
} | ||
|
||
func parseHead(str string) (cmd Executable, err error) { | ||
submatch := regexpHead.FindStringSubmatch(str) | ||
|
||
if len(submatch) == 0 { | ||
return | ||
} | ||
|
||
group := submatch[1] | ||
limit := int64(3) | ||
|
||
if submatch[2] != "" { | ||
limit, err = strconv.ParseInt(submatch[2], 10, 64) | ||
|
||
if err != nil { | ||
return | ||
} | ||
} | ||
|
||
if limit <= 0 { | ||
err = fmt.Errorf("Invalid limit: %d", limit) | ||
return | ||
} | ||
|
||
cmd = &headCommand{ | ||
group: group, | ||
limit: limit, | ||
} | ||
|
||
return | ||
} | ||
|
||
func describeLogGroup(svc *cloudwatchlogs.CloudWatchLogs, group string) (logGroup *cloudwatchlogs.LogGroup, err error) { | ||
params := &cloudwatchlogs.DescribeLogGroupsInput{ | ||
LogGroupNamePrefix: aws.String(group), | ||
Limit: aws.Int64(1), | ||
} | ||
|
||
resp, err := svc.DescribeLogGroups(params) | ||
|
||
if err != nil { | ||
return | ||
} | ||
|
||
if len(resp.LogGroups) == 0 || *resp.LogGroups[0].LogGroupName != group { | ||
err = fmt.Errorf("LogGroup was not found: %s", group) | ||
return | ||
} | ||
|
||
logGroup = resp.LogGroups[0] | ||
|
||
return | ||
} | ||
|
||
func describeLogStream(svc *cloudwatchlogs.CloudWatchLogs, logGroup *cloudwatchlogs.LogGroup) (logStream *cloudwatchlogs.LogStream, err error) { | ||
params := &cloudwatchlogs.DescribeLogStreamsInput{ | ||
LogGroupName: logGroup.LogGroupName, | ||
Descending: aws.Bool(true), | ||
OrderBy: aws.String("LastEventTime"), | ||
Limit: aws.Int64(1), | ||
} | ||
|
||
resp, err := svc.DescribeLogStreams(params) | ||
|
||
if err != nil { | ||
return | ||
} | ||
|
||
if len(resp.LogStreams) == 0 { | ||
err = fmt.Errorf("LogStream was not found in %s", *logGroup.LogGroupName) | ||
return | ||
} | ||
|
||
logStream = resp.LogStreams[0] | ||
|
||
return | ||
} | ||
|
||
func getLogEvent(svc *cloudwatchlogs.CloudWatchLogs, logGroup *cloudwatchlogs.LogGroup, logStream *cloudwatchlogs.LogStream, limit int64) (events []*cloudwatchlogs.OutputLogEvent, err error) { | ||
params := &cloudwatchlogs.GetLogEventsInput{ | ||
LogGroupName: logGroup.LogGroupName, | ||
LogStreamName: logStream.LogStreamName, | ||
StartTime: logStream.LastEventTimestamp, | ||
Limit: aws.Int64(limit), | ||
} | ||
|
||
resp, err := svc.GetLogEvents(params) | ||
|
||
if err != nil { | ||
return | ||
} | ||
|
||
if len(resp.Events) == 0 { | ||
err = fmt.Errorf("Events was not found in %s", *logGroup.LogGroupName) | ||
return | ||
} | ||
|
||
events = resp.Events | ||
|
||
return | ||
} | ||
|
||
func (cmd *headCommand) Start(svc *cloudwatchlogs.CloudWatchLogs, flags *cli.Flags, out io.Writer) (err error) { | ||
logGroup, err := describeLogGroup(svc, cmd.group) | ||
|
||
if err != nil { | ||
return | ||
} | ||
|
||
logStream, err := describeLogStream(svc, logGroup) | ||
|
||
if err != nil { | ||
return | ||
} | ||
|
||
events, err := getLogEvent(svc, logGroup, logStream, cmd.limit) | ||
|
||
if err != nil { | ||
return | ||
} | ||
|
||
for i, event := range events { | ||
fmt.Fprintf(out, "*************************** %d. row ***************************\n", i+1) | ||
fmt.Fprintf(out, "Timestamp: %d\n", *event.Timestamp) | ||
fmt.Fprintf(out, "Message: %s\n", *event.Message) | ||
} | ||
|
||
return | ||
} | ||
|
||
func usageHead() string { | ||
return "head LOG-GROUP [limit N]\n\tPrint first lines of a Log Group" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package exec | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"regexp" | ||
|
||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs" | ||
"github.com/winebarrel/cwli/cli" | ||
) | ||
|
||
var usages = []func() string{ | ||
usageHelp, | ||
usageShowGroups, | ||
usageHead, | ||
usageQuery, | ||
} | ||
|
||
var regexpHelp = regexp.MustCompile(`(?i)^help\s*$`) | ||
|
||
type helpCommand struct { | ||
} | ||
|
||
func parseHelp(str string) (cmd Executable, err error) { | ||
if !regexpHelp.MatchString(str) { | ||
return | ||
} | ||
|
||
cmd = &helpCommand{} | ||
|
||
return | ||
} | ||
|
||
func (cmd *helpCommand) Start(svc *cloudwatchlogs.CloudWatchLogs, flags *cli.Flags, out io.Writer) (err error) { | ||
|
||
for _, usage := range usages { | ||
fmt.Fprintln(out, usage()) | ||
} | ||
|
||
return | ||
} | ||
|
||
func usageHelp() string { | ||
return "help\n\tPrint a help message" | ||
} |
Oops, something went wrong.