github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/logforwarder/tracker.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package logforwarder
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"gopkg.in/juju/names.v2"
     9  
    10  	"github.com/juju/juju/api/base"
    11  	logfwdapi "github.com/juju/juju/api/logfwd"
    12  	"github.com/juju/juju/logfwd"
    13  	"github.com/juju/juju/logfwd/syslog"
    14  )
    15  
    16  // TrackingSinkArgs holds the args to OpenTrackingSender.
    17  type TrackingSinkArgs struct {
    18  	// Config is the logging config that will be used.
    19  	Config *syslog.RawConfig
    20  
    21  	// Caller is the API caller that will be used.
    22  	Caller base.APICaller
    23  
    24  	// Name is the name given to the log sink.
    25  	Name string
    26  
    27  	// OpenSink is the function that opens the underlying log sink that
    28  	// will be wrapped.
    29  	OpenSink LogSinkFn
    30  }
    31  
    32  // OpenTrackingSink opens a log record sender to use with a worker.
    33  // The sender also tracks records that were successfully sent.
    34  func OpenTrackingSink(args TrackingSinkArgs) (*LogSink, error) {
    35  	sink, err := args.OpenSink(args.Config)
    36  	if err != nil {
    37  		return nil, errors.Trace(err)
    38  	}
    39  
    40  	return &LogSink{
    41  		&trackingSender{
    42  			SendCloser: sink,
    43  			tracker:    newLastSentTracker(args.Name, args.Caller),
    44  		},
    45  	}, nil
    46  }
    47  
    48  type trackingSender struct {
    49  	SendCloser
    50  	tracker *lastSentTracker
    51  }
    52  
    53  // Send implements Sender.
    54  func (s *trackingSender) Send(records []logfwd.Record) error {
    55  	if err := s.SendCloser.Send(records); err != nil {
    56  		return errors.Trace(err)
    57  	}
    58  	if err := s.tracker.setLastSent(records); err != nil {
    59  		return errors.Trace(err)
    60  	}
    61  	return nil
    62  }
    63  
    64  type lastSentTracker struct {
    65  	sink   string
    66  	client *logfwdapi.LastSentClient
    67  }
    68  
    69  func newLastSentTracker(sink string, caller base.APICaller) *lastSentTracker {
    70  	client := logfwdapi.NewLastSentClient(func(name string) logfwdapi.FacadeCaller {
    71  		return base.NewFacadeCaller(caller, name)
    72  	})
    73  	return &lastSentTracker{
    74  		sink:   sink,
    75  		client: client,
    76  	}
    77  }
    78  
    79  func (lst lastSentTracker) setLastSent(records []logfwd.Record) error {
    80  	// The records are received and sent in order, so we only need to
    81  	// call SetLastSent for the last record.
    82  	if len(records) == 0 {
    83  		return nil
    84  	}
    85  	rec := records[len(records)-1]
    86  	model := rec.Origin.ModelUUID
    87  	if !names.IsValidModel(model) {
    88  		return errors.Errorf("bad model UUID %q", model)
    89  	}
    90  	modelTag := names.NewModelTag(model)
    91  	results, err := lst.client.SetLastSent([]logfwdapi.LastSentInfo{{
    92  		LastSentID: logfwdapi.LastSentID{
    93  			Model: modelTag,
    94  			Sink:  lst.sink,
    95  		},
    96  		RecordID:        rec.ID,
    97  		RecordTimestamp: rec.Timestamp,
    98  	}})
    99  	if err != nil {
   100  		return errors.Trace(err)
   101  	}
   102  	if err := results[0].Error; err != nil {
   103  		return errors.Trace(err)
   104  	}
   105  	return nil
   106  }