github.com/franciscocpg/up@v0.1.10/platform/lambda/logs/log.go (about)

     1  package logs
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/apex/log"
     8  	"github.com/aws/aws-sdk-go/aws/awserr"
     9  	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
    10  )
    11  
    12  // Log implements log fetching and polling for CloudWatchLogs,
    13  // and represents a single group.
    14  type Log struct {
    15  	Config
    16  	GroupName string
    17  	Log       log.Interface
    18  	err       error
    19  }
    20  
    21  // Start consuming logs.
    22  func (l *Log) Start() <-chan *Event {
    23  	ch := make(chan *Event)
    24  	go l.start(ch)
    25  	return ch
    26  }
    27  
    28  // start consuming and exit after pagination if Follow is not enabled.
    29  func (l *Log) start(ch chan<- *Event) {
    30  	defer close(ch)
    31  
    32  	l.Log.Debug("enter")
    33  	defer l.Log.Debug("exit")
    34  
    35  	var start = l.StartTime.UnixNano() / int64(time.Millisecond)
    36  	var nextToken *string
    37  	var err error
    38  
    39  	for {
    40  		l.Log.WithField("start", start).Debug("request")
    41  		nextToken, start, err = l.fetch(nextToken, start, ch)
    42  
    43  		if err != nil {
    44  			l.err = fmt.Errorf("log %q: %s", l.GroupName, err)
    45  			break
    46  		}
    47  
    48  		if nextToken == nil && l.Follow {
    49  			time.Sleep(l.PollInterval)
    50  			l.Log.WithField("start", start).Debug("poll")
    51  			continue
    52  		}
    53  
    54  		if nextToken == nil {
    55  			break
    56  		}
    57  	}
    58  }
    59  
    60  // fetch logs relative to the given token and start time. We ignore when the log group is not found.
    61  func (l *Log) fetch(nextToken *string, start int64, ch chan<- *Event) (*string, int64, error) {
    62  	res, err := l.Service.FilterLogEvents(&cloudwatchlogs.FilterLogEventsInput{
    63  		LogGroupName:  &l.GroupName,
    64  		FilterPattern: &l.FilterPattern,
    65  		StartTime:     &start,
    66  		NextToken:     nextToken,
    67  	})
    68  
    69  	if e, ok := err.(awserr.Error); ok {
    70  		if e.Code() == "ResourceNotFoundException" {
    71  			l.Log.Debug("not found")
    72  			return nil, 0, nil
    73  		}
    74  	}
    75  
    76  	if err != nil {
    77  		return nil, 0, err
    78  	}
    79  
    80  	for _, event := range res.Events {
    81  		start = *event.Timestamp + 1
    82  		ch <- &Event{
    83  			GroupName: l.GroupName,
    84  			Message:   *event.Message,
    85  		}
    86  	}
    87  
    88  	return res.NextToken, start, nil
    89  }
    90  
    91  // Err returns the first error, if any, during processing.
    92  func (l *Log) Err() error {
    93  	return l.err
    94  }