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