github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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 sent := 0 66 for { 67 metrics, err := st.MetricsToSend(batchSize) 68 if err != nil { 69 return errors.Trace(err) 70 } 71 lenM := len(metrics) 72 if lenM == 0 { 73 if sent == 0 { 74 logger.Infof("nothing to send") 75 } else { 76 logger.Infof("done sending") 77 } 78 break 79 } 80 wireData := make([]*wireformat.MetricBatch, lenM) 81 for i, m := range metrics { 82 wireData[i] = wireformat.ToWire(m) 83 } 84 response, err := sender.Send(wireData) 85 if err != nil { 86 logger.Errorf("%+v", err) 87 if incErr := metricsManager.IncrementConsecutiveErrors(); incErr != nil { 88 logger.Errorf("failed to increment error count %v", incErr) 89 return errors.Trace(errors.Wrap(err, incErr)) 90 } 91 return errors.Trace(err) 92 } 93 if response != nil { 94 // TODO (mattyw) We are currently ignoring errors during response handling. 95 handleResponse(metricsManager, st, *response) 96 if err := metricsManager.SetLastSuccessfulSend(time.Now()); err != nil { 97 err = errors.Annotate(err, "failed to set successful send time") 98 logger.Warningf("%v", err) 99 return errors.Trace(err) 100 } 101 } 102 sent += lenM 103 } 104 105 unsent, err := st.CountOfUnsentMetrics() 106 if err != nil { 107 return errors.Trace(err) 108 } 109 sentStored, err := st.CountOfSentMetrics() 110 if err != nil { 111 return errors.Trace(err) 112 } 113 logger.Infof("metrics collection summary: sent:%d unsent:%d (%d sent metrics stored)", sent, unsent, sentStored) 114 115 return nil 116 } 117 118 // DefaultMaxBatchesPerSend returns the default number of batches per send. 119 func DefaultMaxBatchesPerSend() int { 120 return defaultMaxBatchesPerSend 121 } 122 123 // DefaultMetricSender returns the default metric sender. 124 func DefaultMetricSender() MetricSender { 125 return defaultSender 126 }