| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package monitor | 5 package monitor |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "math" | 8 "math" |
| 9 "time" | 9 "time" |
| 10 | 10 |
| 11 "github.com/golang/protobuf/proto" | |
| 12 "github.com/luci/luci-go/common/tsmon/distribution" | 11 "github.com/luci/luci-go/common/tsmon/distribution" |
| 13 "github.com/luci/luci-go/common/tsmon/field" | 12 "github.com/luci/luci-go/common/tsmon/field" |
| 14 "github.com/luci/luci-go/common/tsmon/types" | 13 "github.com/luci/luci-go/common/tsmon/types" |
| 15 | 14 |
| 16 pb "github.com/luci/luci-go/common/tsmon/ts_mon_proto" | 15 pb "github.com/luci/luci-go/common/tsmon/ts_mon_proto" |
| 17 ) | 16 ) |
| 18 | 17 |
| 19 const ( | 18 const ( |
| 20 metricNamePrefix = "/chrome/infra/" | 19 metricNamePrefix = "/chrome/infra/" |
| 21 ) | 20 ) |
| 22 | 21 |
| 23 // SerializeCells creates a MetricsCollection message from a slice of cells. | 22 // SerializeCells creates a MetricsCollection message from a slice of cells. |
| 24 func SerializeCells(cells []types.Cell) *pb.MetricsCollection { | 23 func SerializeCells(cells []types.Cell) *pb.MetricsCollection { |
| 25 collection := pb.MetricsCollection{ | 24 collection := pb.MetricsCollection{ |
| 26 Data: make([]*pb.MetricsData, len(cells)), | 25 Data: make([]*pb.MetricsData, len(cells)), |
| 27 } | 26 } |
| 28 | 27 |
| 29 for i, cell := range cells { | 28 for i, cell := range cells { |
| 30 collection.Data[i] = SerializeCell(cell) | 29 collection.Data[i] = SerializeCell(cell) |
| 31 } | 30 } |
| 32 | 31 |
| 33 return &collection | 32 return &collection |
| 34 } | 33 } |
| 35 | 34 |
| 36 // SerializeCell creates one MetricsData message from a cell. | 35 // SerializeCell creates one MetricsData message from a cell. |
| 37 func SerializeCell(c types.Cell) *pb.MetricsData { | 36 func SerializeCell(c types.Cell) *pb.MetricsData { |
| 38 d := pb.MetricsData{} | 37 d := pb.MetricsData{} |
| 39 » d.Name = proto.String(c.Name) | 38 » d.Name = c.Name |
| 40 » d.Description = proto.String(c.Description) | 39 » d.Description = c.Description |
| 41 » d.MetricNamePrefix = proto.String(metricNamePrefix) | 40 » d.MetricNamePrefix = metricNamePrefix |
| 42 d.Fields = field.Serialize(c.Fields, c.FieldVals) | 41 d.Fields = field.Serialize(c.Fields, c.FieldVals) |
| 43 » d.StartTimestampUs = proto.Uint64(uint64(c.ResetTime.UnixNano() / int64(
time.Microsecond))) | 42 » d.StartTimestampUs = uint64(c.ResetTime.UnixNano() / int64(time.Microsec
ond)) |
| 44 c.Target.PopulateProto(&d) | 43 c.Target.PopulateProto(&d) |
| 45 | 44 |
| 46 SerializeValue(c.ValueType, c.Value, &d) | 45 SerializeValue(c.ValueType, c.Value, &d) |
| 47 return &d | 46 return &d |
| 48 } | 47 } |
| 49 | 48 |
| 50 // SerializeValue writes one metric's value into the MetricsData message. | 49 // SerializeValue writes one metric's value into the MetricsData message. |
| 51 func SerializeValue(typ types.ValueType, value interface{}, d *pb.MetricsData) { | 50 func SerializeValue(typ types.ValueType, value interface{}, d *pb.MetricsData) { |
| 52 switch typ { | 51 switch typ { |
| 53 case types.NonCumulativeIntType: | 52 case types.NonCumulativeIntType: |
| 54 » » d.Gauge = proto.Int64(value.(int64)) | 53 » » d.Gauge = value.(int64) |
| 55 case types.CumulativeIntType: | 54 case types.CumulativeIntType: |
| 56 » » d.Counter = proto.Int64(value.(int64)) | 55 » » d.Counter = value.(int64) |
| 57 case types.NonCumulativeFloatType: | 56 case types.NonCumulativeFloatType: |
| 58 » » d.NoncumulativeDoubleValue = proto.Float64(value.(float64)) | 57 » » d.NoncumulativeDoubleValue = value.(float64) |
| 59 case types.CumulativeFloatType: | 58 case types.CumulativeFloatType: |
| 60 » » d.CumulativeDoubleValue = proto.Float64(value.(float64)) | 59 » » d.CumulativeDoubleValue = value.(float64) |
| 61 case types.StringType: | 60 case types.StringType: |
| 62 » » d.StringValue = proto.String(value.(string)) | 61 » » d.StringValue = value.(string) |
| 63 case types.BoolType: | 62 case types.BoolType: |
| 64 » » d.BooleanValue = proto.Bool(value.(bool)) | 63 » » d.BooleanValue = value.(bool) |
| 65 case types.CumulativeDistributionType: | 64 case types.CumulativeDistributionType: |
| 66 d.Distribution = serializeDistribution(value.(*distribution.Dist
ribution)) | 65 d.Distribution = serializeDistribution(value.(*distribution.Dist
ribution)) |
| 67 » » d.Distribution.IsCumulative = proto.Bool(true) | 66 » » d.Distribution.IsCumulative = true |
| 68 case types.NonCumulativeDistributionType: | 67 case types.NonCumulativeDistributionType: |
| 69 d.Distribution = serializeDistribution(value.(*distribution.Dist
ribution)) | 68 d.Distribution = serializeDistribution(value.(*distribution.Dist
ribution)) |
| 70 » » d.Distribution.IsCumulative = proto.Bool(false) | 69 » » d.Distribution.IsCumulative = false |
| 71 } | 70 } |
| 72 } | 71 } |
| 73 | 72 |
| 74 func runningZeroes(values []int64) []int64 { | 73 func runningZeroes(values []int64) []int64 { |
| 75 ret := []int64{} | 74 ret := []int64{} |
| 76 | 75 |
| 77 var count int64 | 76 var count int64 |
| 78 for _, v := range values { | 77 for _, v := range values { |
| 79 if v == 0 { | 78 if v == 0 { |
| 80 count++ | 79 count++ |
| 81 } else { | 80 } else { |
| 82 if count != 0 { | 81 if count != 0 { |
| 83 ret = append(ret, -count) | 82 ret = append(ret, -count) |
| 84 count = 0 | 83 count = 0 |
| 85 } | 84 } |
| 86 ret = append(ret, v) | 85 ret = append(ret, v) |
| 87 } | 86 } |
| 88 } | 87 } |
| 89 return ret | 88 return ret |
| 90 } | 89 } |
| 91 | 90 |
| 92 func serializeDistribution(d *distribution.Distribution) *pb.PrecomputedDistribu
tion { | 91 func serializeDistribution(d *distribution.Distribution) *pb.PrecomputedDistribu
tion { |
| 93 ret := pb.PrecomputedDistribution{} | 92 ret := pb.PrecomputedDistribution{} |
| 94 | 93 |
| 95 // Copy the bucketer params. | 94 // Copy the bucketer params. |
| 96 if d.Bucketer().Width() == 0 { | 95 if d.Bucketer().Width() == 0 { |
| 97 switch d.Bucketer().GrowthFactor() { | 96 switch d.Bucketer().GrowthFactor() { |
| 98 case 2: | 97 case 2: |
| 99 » » » ret.SpecType = pb.PrecomputedDistribution_CANONICAL_POWE
RS_OF_2.Enum() | 98 » » » ret.SpecType = pb.PrecomputedDistribution_CANONICAL_POWE
RS_OF_2 |
| 100 case math.Pow(10, 0.2): | 99 case math.Pow(10, 0.2): |
| 101 » » » ret.SpecType = pb.PrecomputedDistribution_CANONICAL_POWE
RS_OF_10_P_0_2.Enum() | 100 » » » ret.SpecType = pb.PrecomputedDistribution_CANONICAL_POWE
RS_OF_10_P_0_2 |
| 102 case 10: | 101 case 10: |
| 103 » » » ret.SpecType = pb.PrecomputedDistribution_CANONICAL_POWE
RS_OF_10.Enum() | 102 » » » ret.SpecType = pb.PrecomputedDistribution_CANONICAL_POWE
RS_OF_10 |
| 104 } | 103 } |
| 105 } | 104 } |
| 106 | 105 |
| 107 » if ret.SpecType == nil { | 106 » if ret.SpecType == pb.PrecomputedDistribution_UNKNOWN { |
| 108 » » ret.SpecType = pb.PrecomputedDistribution_CUSTOM_PARAMETERIZED.E
num() | 107 » » ret.SpecType = pb.PrecomputedDistribution_CUSTOM_PARAMETERIZED |
| 109 » » ret.Width = proto.Float64(d.Bucketer().Width()) | 108 » » ret.Width = d.Bucketer().Width() |
| 110 » » ret.GrowthFactor = proto.Float64(d.Bucketer().GrowthFactor()) | 109 » » ret.GrowthFactor = d.Bucketer().GrowthFactor() |
| 111 » » ret.NumBuckets = proto.Int32(int32(d.Bucketer().NumFiniteBuckets
())) | 110 » » ret.NumBuckets = int32(d.Bucketer().NumFiniteBuckets()) |
| 112 } | 111 } |
| 113 | 112 |
| 114 // Copy the distribution bucket values. Exclude the overflow buckets on
each | 113 // Copy the distribution bucket values. Exclude the overflow buckets on
each |
| 115 // end. | 114 // end. |
| 116 if len(d.Buckets()) >= 1 { | 115 if len(d.Buckets()) >= 1 { |
| 117 if len(d.Buckets()) == d.Bucketer().NumBuckets() { | 116 if len(d.Buckets()) == d.Bucketer().NumBuckets() { |
| 118 ret.Bucket = runningZeroes(d.Buckets()[1 : len(d.Buckets
())-1]) | 117 ret.Bucket = runningZeroes(d.Buckets()[1 : len(d.Buckets
())-1]) |
| 119 } else { | 118 } else { |
| 120 ret.Bucket = runningZeroes(d.Buckets()[1:]) | 119 ret.Bucket = runningZeroes(d.Buckets()[1:]) |
| 121 } | 120 } |
| 122 } | 121 } |
| 123 | 122 |
| 124 // Add overflow buckets if present. | 123 // Add overflow buckets if present. |
| 125 if len(d.Buckets()) >= 1 { | 124 if len(d.Buckets()) >= 1 { |
| 126 » » ret.Underflow = proto.Int64(d.Buckets()[0]) | 125 » » ret.Underflow = d.Buckets()[0] |
| 127 } | 126 } |
| 128 if len(d.Buckets()) == d.Bucketer().NumBuckets() { | 127 if len(d.Buckets()) == d.Bucketer().NumBuckets() { |
| 129 » » ret.Overflow = proto.Int64(d.Buckets()[d.Bucketer().NumBuckets()
-1]) | 128 » » ret.Overflow = d.Buckets()[d.Bucketer().NumBuckets()-1] |
| 130 } | 129 } |
| 131 | 130 |
| 132 if d.Count() > 0 { | 131 if d.Count() > 0 { |
| 133 » » ret.Mean = proto.Float64(d.Sum() / float64(d.Count())) | 132 » » ret.Mean = d.Sum() / float64(d.Count()) |
| 134 } | 133 } |
| 135 | 134 |
| 136 return &ret | 135 return &ret |
| 137 } | 136 } |
| OLD | NEW |