forked from lucagrulla/cw
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
157 lines (136 loc) · 5.59 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package main
import (
"fmt"
"net/http"
"os"
"os/signal"
"regexp"
"strconv"
"strings"
"time"
"github.com/fatih/color"
"github.com/lucagrulla/cw/cloudwatch"
"github.com/lucagrulla/cw/timeutil"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
lsCommand = kingpin.Command("ls", "Show an entity")
lsGroups = lsCommand.Command("groups", "Show all groups.")
lsStreams = lsCommand.Command("streams", "Show all streams in a given log group.")
lsLogGroupName = lsStreams.Arg("group", "the group name").HintAction(groupsCompletion).Required().String()
tailCommand = kingpin.Command("tail", "Tail a log group.")
follow = tailCommand.Flag("follow", "Don't stop when the end of stream is reached, but rather wait for additional data to be appended.").Short('f').Default("false").Bool()
printTimestamp = tailCommand.Flag("timestamp", "Print the event timestamp.").Short('t').Default("false").Bool()
printEventID = tailCommand.Flag("event Id", "Print the event Id").Short('i').Default("false").Bool()
printStreamName = tailCommand.Flag("stream name", "Print the log stream name this event belongs to.").Short('s').Default("false").Bool()
grep = tailCommand.Flag("grep", "Pattern to filter logs by. See http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html for syntax.").Short('g').Default("").String()
logGroupName = tailCommand.Arg("group", "The log group name.").Required().HintAction(groupsCompletion).String()
logStreamName = tailCommand.Arg("stream", "The log stream name. Use \\* for tail all the group streams.").Default("*").HintAction(streamsCompletion).String()
startTime = tailCommand.Arg("start", "The tailing start time in UTC. If a timestamp is passed(format: hh[:mm]) it's expanded to today at the given time. Full format: 2017-02-27[T09:00[:00]].").
Default(time.Now().UTC().Add(-30 * time.Second).Format(timeutil.TimeFormat)).String()
endTime = tailCommand.Arg("end", "The tailing end time in UTC. If a timestamp is passed(format: hh[:mm]) it's expanded to today at the given time. Full format: 2017-02-27[T09:00[:00]].").String()
)
func groupsCompletion() []string {
var groups []string
for msg := range cloudwatch.LsGroups() {
groups = append(groups, *msg)
}
return groups
}
func streamsCompletion() []string {
var streams []string
for msg := range cloudwatch.LsStreams(logGroupName, nil, 0, 0) {
streams = append(streams, *msg)
}
return streams
}
func timestampToUTC(timeStamp *string) time.Time {
if regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`).MatchString(*timeStamp) {
t, _ := time.ParseInLocation("2006-01-02", *timeStamp, time.UTC)
return t
} else if regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}$`).MatchString(*timeStamp) {
t, _ := time.ParseInLocation("2006-01-02T15", *timeStamp, time.UTC)
return t
} else if regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$`).MatchString(*timeStamp) {
t, _ := time.ParseInLocation("2006-01-02T15:04", *timeStamp, time.UTC)
return t
} else if regexp.MustCompile(`^\d{1,2}$`).MatchString(*timeStamp) {
y, m, d := time.Now().Date()
t, _ := strconv.Atoi(*timeStamp)
return time.Date(y, m, d, t, 0, 0, 0, time.UTC)
} else if res := regexp.MustCompile(`^(?P<Hour>\d{1,2}):(?P<Minute>\d{2})$`).FindStringSubmatch(*timeStamp); res != nil {
y, m, d := time.Now().Date()
t, _ := strconv.Atoi(res[1])
mm, _ := strconv.Atoi(res[2])
return time.Date(y, m, d, t, mm, 0, 0, time.UTC)
}
//TODO check even last scenario and if it's not a recognized pattern throw an error
t, _ := time.ParseInLocation("2006-01-02T15:04:05", *timeStamp, time.UTC)
return t
}
func fetchLatestVersion() chan string {
latestVersionChannel := make(chan string, 1)
go func() {
r, _ := http.Get("https://github.com/lucagrulla/cw/releases/latest")
finalURL := r.Request.URL.String()
tokens := strings.Split(finalURL, "/")
latestVersionChannel <- tokens[len(tokens)-1]
}()
return latestVersionChannel
}
func newVersionMsg(currentVersion string, latestVersionChannel chan string) {
latestVersion := <-latestVersionChannel
if latestVersion != currentVersion {
fmt.Println("")
fmt.Println("")
msg := fmt.Sprintf("%s - %s -> %s", color.GreenString("A new version of cw is available!"), color.YellowString(currentVersion), color.GreenString(latestVersion))
fmt.Println(msg)
}
}
func versionCheckOnSigterm(version string, latestVersionChannel chan string) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
newVersionMsg(version, latestVersionChannel)
os.Exit(0)
}()
}
func main() {
version := "1.5.0"
kingpin.Version(version).Author("Luca Grulla")
command := kingpin.Parse()
latestVersionChannel := fetchLatestVersion()
versionCheckOnSigterm(version, latestVersionChannel)
switch command {
case "ls groups":
for msg := range cloudwatch.LsGroups() {
fmt.Println(*msg)
}
case "ls streams":
for msg := range cloudwatch.LsStreams(lsLogGroupName, nil, 0, 0) {
fmt.Println(*msg)
}
case "tail":
st := timestampToUTC(startTime)
var et time.Time
if *endTime != "" {
et = timestampToUTC(endTime)
}
for event := range cloudwatch.Tail(logGroupName, logStreamName, follow, &st, &et, grep) {
msg := *event.Message
eventTimestamp := *event.Timestamp / 1000
if *printEventID {
msg = fmt.Sprintf("%s - %s", color.YellowString(*event.EventId), msg)
}
if *printStreamName {
msg = fmt.Sprintf("%s - %s", color.BlueString(*event.LogStreamName), msg)
}
if *printTimestamp {
msg = fmt.Sprintf("%s - %s", color.GreenString(timeutil.FormatTimestamp(eventTimestamp)), msg)
}
fmt.Println(msg)
}
}
newVersionMsg(version, latestVersionChannel)
}