11package blade
22
33import (
4+ "context"
45 "encoding/json"
56 "errors"
67 "fmt"
@@ -9,10 +10,9 @@ import (
910
1011 "github.com/TylerBrock/colorjson"
1112 "github.com/TylerBrock/saw/config"
12- "github.com/aws/aws-sdk-go/aws"
13- "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
14- "github.com/aws/aws-sdk-go/aws/session"
15- "github.com/aws/aws-sdk-go/service/cloudwatchlogs"
13+ awsconfig "github.com/aws/aws-sdk-go-v2/config"
14+ "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs"
15+ "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types"
1616 "github.com/fatih/color"
1717)
1818
@@ -21,70 +21,62 @@ type Blade struct {
2121 config * config.Configuration
2222 aws * config.AWSConfiguration
2323 output * config.OutputConfiguration
24- cwl * cloudwatchlogs.CloudWatchLogs
24+ cwl * cloudwatchlogs.Client
2525}
2626
2727// NewBlade creates a new Blade with CloudWatchLogs instance from provided config
2828func NewBlade (
29+ ctx context.Context ,
2930 config * config.Configuration ,
3031 awsConfig * config.AWSConfiguration ,
3132 outputConfig * config.OutputConfiguration ,
32- ) * Blade {
33+ ) ( * Blade , error ) {
3334 blade := Blade {}
34- awsCfg := aws.Config {}
35-
36- if awsConfig .Region != "" {
37- awsCfg .Region = & awsConfig .Region
38- }
39-
40- awsSessionOpts := session.Options {
41- Config : awsCfg ,
42- AssumeRoleTokenProvider : stscreds .StdinTokenProvider ,
43- SharedConfigState : session .SharedConfigEnable ,
44- }
4535
36+ var opts []func (* awsconfig.LoadOptions ) error
4637 if awsConfig .Profile != "" {
47- awsSessionOpts . Profile = awsConfig .Profile
38+ opts = append ( opts , awsconfig . WithSharedConfigProfile ( awsConfig .Profile ))
4839 }
40+ if awsConfig .Region != "" {
41+ opts = append (opts , awsconfig .WithRegion (awsConfig .Region ))
42+ }
43+ awsCfg , err := awsconfig .LoadDefaultConfig (ctx , opts ... )
4944
50- sess := session .Must (session .NewSessionWithOptions (awsSessionOpts ))
51-
52- blade .cwl = cloudwatchlogs .New (sess )
45+ blade .cwl = cloudwatchlogs .NewFromConfig (awsCfg )
5346 blade .config = config
5447 blade .output = outputConfig
5548
56- return & blade
49+ return & blade , err
5750}
5851
5952// GetLogGroups gets the log groups from AWS given the blade configuration
60- func (b * Blade ) GetLogGroups () [] * cloudwatchlogs .LogGroup {
53+ func (b * Blade ) GetLogGroups (ctx context. Context ) ( groups []types .LogGroup , err error ) {
6154 input := b .config .DescribeLogGroupsInput ()
62- groups := make ([]* cloudwatchlogs.LogGroup , 0 )
63- b .cwl .DescribeLogGroupsPages (input , func (
64- out * cloudwatchlogs.DescribeLogGroupsOutput ,
65- lastPage bool ,
66- ) bool {
67- for _ , group := range out .LogGroups {
68- if b .config .Fuzzy && ! groupNameMatches (* group .LogGroupName , b .config .Group ) {
69- continue
70- }
71- groups = append (groups , group )
55+ logGroupsPaginator := cloudwatchlogs .NewDescribeLogGroupsPaginator (b .cwl , input )
56+ var page * cloudwatchlogs.DescribeLogGroupsOutput
57+ for logGroupsPaginator .HasMorePages () {
58+ page , err = logGroupsPaginator .NextPage (ctx )
59+ if err != nil {
60+ return
7261 }
73- return ! lastPage
74- })
75- return groups
62+ groups = append ( groups , page . LogGroups ... )
63+ }
64+ return
7665}
7766
7867func groupNameMatches (s , substr string ) bool {
7968 return strings .Contains (s , substr )
8069}
8170
82- func (b * Blade ) ResolveFuzzyGroupName () (err error ) {
71+ func (b * Blade ) ResolveFuzzyGroupName (ctx context. Context ) (err error ) {
8372 if ! b .config .Fuzzy {
8473 return
8574 }
8675 b .config .Fuzzy = false
87- groups := b .GetLogGroups ()
76+ groups , err := b .GetLogGroups (ctx )
77+ if err != nil {
78+ return
79+ }
8880 if len (groups ) == 0 {
8981 return errors .New ("no log groups found" )
9082 }
@@ -99,15 +91,15 @@ func (b *Blade) ResolveFuzzyGroupName() (err error) {
9991 return
10092}
10193
102- func getGroupNames (groups []* cloudwatchlogs .LogGroup ) (op []string ) {
94+ func getGroupNames (groups []types .LogGroup ) (op []string ) {
10395 op = make ([]string , len (groups ))
10496 for i := 0 ; i < len (groups ); i ++ {
10597 op [i ] = * groups [i ].LogGroupName
10698 }
10799 return
108100}
109101
110- func filterGroupNames (groups []* cloudwatchlogs .LogGroup , group string ) (op []string ) {
102+ func filterGroupNames (groups []types .LogGroup , group string ) (op []string ) {
111103 for i := 0 ; i < len (groups ); i ++ {
112104 if groupNameMatches (* groups [i ].LogGroupName , group ) {
113105 op = append (op , * groups [i ].LogGroupName )
@@ -117,46 +109,50 @@ func filterGroupNames(groups []*cloudwatchlogs.LogGroup, group string) (op []str
117109}
118110
119111// GetLogStreams gets the log streams from AWS given the blade configuration
120- func (b * Blade ) GetLogStreams () (streams []* cloudwatchlogs .LogStream , err error ) {
121- if err := b .ResolveFuzzyGroupName (); err != nil {
112+ func (b * Blade ) GetLogStreams (ctx context. Context ) (streams []types .LogStream , err error ) {
113+ if err := b .ResolveFuzzyGroupName (ctx ); err != nil {
122114 return nil , err
123115 }
124116 input := b .config .DescribeLogStreamsInput ()
125- b .cwl . DescribeLogStreamsPages ( input , func (
126- out * cloudwatchlogs.DescribeLogStreamsOutput ,
127- lastPage bool ,
128- ) bool {
129- for _ , stream := range out . LogStreams {
130- streams = append ( streams , stream )
117+ logStreamsPaginator := cloudwatchlogs . NewDescribeLogStreamsPaginator ( b .cwl , input )
118+ var page * cloudwatchlogs.DescribeLogStreamsOutput
119+ for logStreamsPaginator . HasMorePages () {
120+ page , err = logStreamsPaginator . NextPage ( ctx )
121+ if err != nil {
122+ return
131123 }
132- return ! lastPage
133- })
134- return streams , err
124+ streams = append ( streams , page . LogStreams ... )
125+ }
126+ return
135127}
136128
137129// GetEvents gets events from AWS given the blade configuration
138- func (b * Blade ) GetEvents () (err error ) {
139- if err := b .ResolveFuzzyGroupName (); err != nil {
130+ func (b * Blade ) GetEvents (ctx context. Context ) (err error ) {
131+ if err := b .ResolveFuzzyGroupName (ctx ); err != nil {
140132 return err
141133 }
142134 formatter := b .output .Formatter ()
143135 input := b .config .FilterLogEventsInput ()
144-
145- handlePage := func (page * cloudwatchlogs.FilterLogEventsOutput , lastPage bool ) bool {
136+ logEventsPaginator := cloudwatchlogs .NewFilterLogEventsPaginator (b .cwl , input )
137+ var page * cloudwatchlogs.FilterLogEventsOutput
138+ for logEventsPaginator .HasMorePages () {
139+ page , err = logEventsPaginator .NextPage (ctx )
140+ if err != nil {
141+ return
142+ }
146143 for _ , event := range page .Events {
147144 if b .output .Pretty {
148145 fmt .Println (strings .TrimRight (formatEvent (formatter , event ), "\n " ))
149146 } else {
150147 fmt .Println (strings .TrimRight (* event .Message , "\n " ))
151148 }
152149 }
153- return ! lastPage
154150 }
155- return b . cwl . FilterLogEventsPages ( input , handlePage )
151+ return
156152}
157153
158154// StreamEvents continuously prints log events to the console
159- func (b * Blade ) StreamEvents () (err error ) {
155+ func (b * Blade ) StreamEvents (ctx context. Context ) (err error ) {
160156 var lastSeenTime * int64
161157 var seenEventIDs map [string ]bool
162158 formatter := b .output .Formatter ()
@@ -177,46 +173,45 @@ func (b *Blade) StreamEvents() (err error) {
177173 }
178174 }
179175
180- handlePage := func (page * cloudwatchlogs.FilterLogEventsOutput , lastPage bool ) bool {
181- for _ , event := range page .Events {
182- updateLastSeenTime (event .Timestamp )
183- if _ , seen := seenEventIDs [* event .EventId ]; ! seen {
184- var message string
185- if b .output .Raw {
186- message = * event .Message
187- } else {
188- message = formatEvent (formatter , event )
176+ for {
177+ logEventsPaginator := cloudwatchlogs .NewFilterLogEventsPaginator (b .cwl , input )
178+ var page * cloudwatchlogs.FilterLogEventsOutput
179+ for logEventsPaginator .HasMorePages () {
180+ page , err = logEventsPaginator .NextPage (ctx )
181+ if err != nil {
182+ return
183+ }
184+ for _ , event := range page .Events {
185+ updateLastSeenTime (event .Timestamp )
186+ if _ , seen := seenEventIDs [* event .EventId ]; ! seen {
187+ var message string
188+ if b .output .Raw {
189+ message = * event .Message
190+ } else {
191+ message = formatEvent (formatter , event )
192+ }
193+ message = strings .TrimRight (message , "\n " )
194+ fmt .Println (message )
195+ addSeenEventIDs (event .EventId )
189196 }
190- message = strings .TrimRight (message , "\n " )
191- fmt .Println (message )
192- addSeenEventIDs (event .EventId )
193197 }
194198 }
195- return ! lastPage
196- }
197-
198- for {
199- err = b .cwl .FilterLogEventsPages (input , handlePage )
200- if err != nil {
201- return
202- }
203199 if lastSeenTime != nil {
204- input .SetStartTime ( * lastSeenTime )
200+ input .StartTime = lastSeenTime
205201 }
206202 time .Sleep (1 * time .Second )
207203 }
208204}
209205
210206// formatEvent returns a CloudWatch log event as a formatted string using the provided formatter
211- func formatEvent (formatter * colorjson.Formatter , event * cloudwatchlogs .FilteredLogEvent ) string {
207+ func formatEvent (formatter * colorjson.Formatter , event types .FilteredLogEvent ) string {
212208 red := color .New (color .FgRed ).SprintFunc ()
213209 white := color .New (color .FgWhite ).SprintFunc ()
214210
215- str := aws .StringValue (event .Message )
216- bytes := []byte (str )
217- date := aws .MillisecondsTimeValue (event .Timestamp )
218- dateStr := date .Format (time .RFC3339 )
219- streamStr := aws .StringValue (event .LogStreamName )
211+ str := * event .Message
212+ bytes := []byte (* event .Message )
213+ dateStr := time .UnixMilli (* event .Timestamp ).Format (time .RFC3339 )
214+ streamStr := * event .LogStreamName
220215 jl := map [string ]interface {}{}
221216
222217 if err := json .Unmarshal (bytes , & jl ); err != nil {
0 commit comments