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 }