package cloudwatch import ( "fmt" "os" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/cloudwatchlogs" "github.com/aws/eks-anywhere-test-tool/pkg/awsprofiles" "github.com/aws/eks-anywhere-test-tool/pkg/constants" "github.com/aws/eks-anywhere/pkg/logger" ) type Cloudwatch struct { session *session.Session svc *cloudwatchlogs.CloudWatchLogs } func New(account awsprofiles.EksAccount) (*Cloudwatch, error) { logger.V(2).Info("creating Cloudwatch client") sess, err := session.NewSessionWithOptions(session.Options{ Profile: account.ProfileName(), Config: aws.Config{Region: aws.String(constants.AwsAccountRegion)}, }) if err != nil { fmt.Printf("Got error when setting up session: %v", err) os.Exit(1) } svc := cloudwatchlogs.New(sess) logger.V(2).Info("created Cloudwatch client") return &Cloudwatch{ session: sess, svc: svc, }, nil } func (c *Cloudwatch) GetLogs(logGroupName string, logStreamName string) ([]*cloudwatchlogs.OutputLogEvent, error) { return c.getLogs(logGroupName, logStreamName, nil, nil) } func (c *Cloudwatch) GetLogsInTimeframe(logGroupName string, logStreamName string, startTime int64, endTime int64) ([]*cloudwatchlogs.OutputLogEvent, error) { return c.getLogs(logGroupName, logStreamName, &startTime, &endTime) } func (c *Cloudwatch) getLogs(logGroupName string, logStreamName string, startTime *int64, endTime *int64) ([]*cloudwatchlogs.OutputLogEvent, error) { var nextToken *string var output []*cloudwatchlogs.OutputLogEvent for { l, err := c.getLogSegment(logGroupName, logStreamName, startTime, endTime, nextToken) if err != nil { if isInvalidParameterError(err) { logger.Info("log stream does not exist. Proceeding to fetch next log events", "logStream", logStreamName) } else { logger.Info("error fetching cloudwatch logs", "group", logGroupName, "stream", logStreamName, "err", err) return nil, err } } if l.NextForwardToken == nil || nextToken != nil && *nextToken == *l.NextForwardToken { logger.Info("finished fetching logs", "logGroup", logGroupName, "logStream", logStreamName) logger.V(3).Info("token comparison", "nextToken", nextToken, "nextForwardToken", l.NextForwardToken) break } nextToken = l.NextForwardToken logger.Info("fetched logs", "logGroup", logGroupName, "logStream", logStreamName, "events", len(l.Events)) logger.V(3).Info("token comparison", "nextToken", nextToken, "nextForwardToken", l.NextForwardToken) output = append(output, l.Events...) } return output, nil } func (c Cloudwatch) getLogSegment(logGroupName string, logStreamName string, startTime *int64, endTime *int64, nextToken *string) (*cloudwatchlogs.GetLogEventsOutput, error) { input := &cloudwatchlogs.GetLogEventsInput{ LogGroupName: aws.String(logGroupName), LogStreamName: aws.String(logStreamName), NextToken: nextToken, StartFromHead: aws.Bool(true), } if startTime != nil { input.StartTime = startTime } if endTime != nil { input.EndTime = endTime } return c.svc.GetLogEvents(input) } func isInvalidParameterError(err error) bool { if awsErr, ok := err.(awserr.Error); ok { return awsErr.Code() == cloudwatchlogs.ErrCodeInvalidParameterException } return false }