github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/metricsender/metricsender.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // Package metricsender contains functions for sending 5 // metrics from a state server to a remote metric collector. 6 package metricsender 7 8 import ( 9 "time" 10 11 "github.com/juju/errors" 12 "github.com/juju/loggo" 13 14 "github.com/juju/juju/apiserver/metricsender/wireformat" 15 "github.com/juju/juju/state" 16 ) 17 18 var logger = loggo.GetLogger("juju.apiserver.metricsender") 19 20 // MetricSender defines the interface used to send metrics 21 // to a collection service. 22 type MetricSender interface { 23 Send([]*wireformat.MetricBatch) (*wireformat.Response, error) 24 } 25 26 var ( 27 defaultMaxBatchesPerSend = 10 28 defaultSender MetricSender = &NopSender{} 29 ) 30 31 func handleResponse(mm *state.MetricsManager, st *state.State, response wireformat.Response) { 32 for _, envResp := range response.EnvResponses { 33 err := st.SetMetricBatchesSent(envResp.AcknowledgedBatches) 34 if err != nil { 35 logger.Errorf("failed to set sent on metrics %v", err) 36 } 37 for unitName, status := range envResp.UnitStatuses { 38 unit, err := st.Unit(unitName) 39 if err != nil { 40 logger.Errorf("failed to retrieve unit %q: %v", unitName, err) 41 continue 42 } 43 err = unit.SetMeterStatus(status.Status, status.Info) 44 if err != nil { 45 logger.Errorf("failed to set unit %q meter status to %v: %v", unitName, status, err) 46 } 47 } 48 } 49 if response.NewGracePeriod > 0 { 50 err := mm.SetGracePeriod(response.NewGracePeriod) 51 if err != nil { 52 logger.Errorf("failed to set new grace period %v", err) 53 } 54 } 55 } 56 57 // SendMetrics will send any unsent metrics 58 // over the MetricSender interface in batches 59 // no larger than batchSize. 60 func SendMetrics(st *state.State, sender MetricSender, batchSize int) error { 61 metricsManager, err := st.MetricsManager() 62 if err != nil { 63 return errors.Trace(err) 64 } 65 for { 66 metrics, err := st.MetricsToSend(batchSize) 67 if err != nil { 68 return errors.Trace(err) 69 } 70 if len(metrics) == 0 { 71 logger.Infof("nothing to send") 72 break 73 } 74 wireData := make([]*wireformat.MetricBatch, len(metrics)) 75 for i, m := range metrics { 76 wireData[i] = wireformat.ToWire(m) 77 } 78 response, err := sender.Send(wireData) 79 if err != nil { 80 logger.Errorf("%+v", err) 81 if incErr := metricsManager.IncrementConsecutiveErrors(); incErr != nil { 82 logger.Errorf("failed to increment error count %v", incErr) 83 return errors.Trace(errors.Wrap(err, incErr)) 84 } 85 return errors.Trace(err) 86 } 87 if response != nil { 88 // TODO (mattyw) We are currently ignoring errors during response handling. 89 handleResponse(metricsManager, st, *response) 90 if err := metricsManager.SetLastSuccessfulSend(time.Now()); err != nil { 91 err = errors.Annotate(err, "failed to set successful send time") 92 logger.Warningf("%v", err) 93 return errors.Trace(err) 94 } 95 } 96 } 97 98 unsent, err := st.CountOfUnsentMetrics() 99 if err != nil { 100 return errors.Trace(err) 101 } 102 sent, err := st.CountOfSentMetrics() 103 if err != nil { 104 return errors.Trace(err) 105 } 106 logger.Infof("metrics collection summary: sent:%d unsent:%d", sent, unsent) 107 108 return nil 109 } 110 111 // DefaultMaxBatchesPerSend returns the default number of batches per send. 112 func DefaultMaxBatchesPerSend() int { 113 return defaultMaxBatchesPerSend 114 } 115 116 // DefaultMetricSender returns the default metric sender. 117 func DefaultMetricSender() MetricSender { 118 return defaultSender 119 }