github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/worker/uniter/operation/metrics.go (about) 1 // Copyright 2014-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package operation 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/juju/apiserver/params" 11 "github.com/juju/juju/worker/uniter/metrics" 12 ) 13 14 // apiMetricSender is used to send metrics to the state server. Its default implementation is 15 // *uniter.Unit. 16 type apiMetricSender interface { 17 AddMetricBatches(batches []params.MetricBatch) (map[string]error, error) 18 } 19 20 // metricsReader is used to read metrics batches stored by the metrics recorder 21 // and remove metrics batches that have been marked as succesfully sent. 22 type metricsReader interface { 23 Read() ([]metrics.MetricBatch, error) 24 Remove(uuid string) error 25 Close() error 26 } 27 28 type sendMetrics struct { 29 DoesNotRequireMachineLock 30 spoolDir string 31 sender apiMetricSender 32 } 33 34 // String implements the Operation interface. 35 func (op *sendMetrics) String() string { 36 return fmt.Sprintf("sending metrics") 37 } 38 39 // Prepare implements the Operation interface. 40 func (op *sendMetrics) Prepare(state State) (*State, error) { 41 return &state, nil 42 } 43 44 // Execute implements the Operation interface. 45 // Execute will try to read any metric batches stored in the spool directory 46 // and send them to the state server. 47 func (op *sendMetrics) Execute(state State) (*State, error) { 48 reader, err := metrics.NewJSONMetricReader(op.spoolDir) 49 if err != nil { 50 logger.Warningf("failed to create a metric reader: %v", err) 51 return &state, nil 52 } 53 54 batches, err := reader.Read() 55 if err != nil { 56 logger.Warningf("failed to open the metric reader: %v", err) 57 return &state, nil 58 } 59 defer reader.Close() 60 var sendBatches []params.MetricBatch 61 for _, batch := range batches { 62 sendBatches = append(sendBatches, metrics.APIMetricBatch(batch)) 63 } 64 results, err := op.sender.AddMetricBatches(sendBatches) 65 if err != nil { 66 logger.Warningf("could not send metrics: %v", err) 67 return &state, nil 68 } 69 for batchUUID, resultErr := range results { 70 // if we fail to send any metric batch we log a warning with the assumption that 71 // the unsent metric batches remain in the spool directory and will be sent to the 72 // state server when the network partition is restored. 73 if _, ok := resultErr.(*params.Error); ok || params.IsCodeAlreadyExists(resultErr) { 74 err = reader.Remove(batchUUID) 75 if err != nil { 76 logger.Warningf("could not remove batch %q from spool: %v", batchUUID, err) 77 } 78 } else { 79 logger.Warningf("failed to send batch %q: %v", batchUUID, resultErr) 80 } 81 } 82 return &state, nil 83 } 84 85 // Commit implements the Operation interface. 86 func (op *sendMetrics) Commit(state State) (*State, error) { 87 state.SendMetricsTime = time.Now().Unix() 88 return &state, nil 89 }