// Interpolate takes a counter value sampled at variable intervals and aligns each value with a <duration> ms boundary. // The initial value is not output unless it appears exactly on a ms boundary. // Runs of two or more missing values will be filled by NaN func Interpolate(duration uint64, input *oproto.ValueStream) *oproto.ValueStream { output := &oproto.ValueStream{} var previousValue *oproto.Value var timestamp uint64 for _, v := range input.Value { if previousValue == nil { if v.Timestamp%duration == 0 { // Value is exactly on a timestamp output.Value = append(output.Value, v) previousValue = v timestamp = v.Timestamp + duration } else { previousValue = v previousValue.Timestamp = v.Timestamp / duration * duration timestamp = previousValue.Timestamp + duration } continue } if v.Timestamp >= timestamp { // Fill in any missing values before this one rate := float64((v.DoubleValue - previousValue.DoubleValue)) for ; timestamp <= v.Timestamp; timestamp += duration { pct := float64(timestamp-previousValue.Timestamp) / float64(v.Timestamp-previousValue.Timestamp) newValue := previousValue.DoubleValue + (rate * pct) output.Value = append(output.Value, &oproto.Value{ Timestamp: timestamp, DoubleValue: newValue, }) } if previousValue.Timestamp < v.Timestamp { if v.Timestamp%duration == 0 { // Value is exactly on a timestamp output.Value = append(output.Value, v) previousValue = v timestamp += duration } else { previousValue = v } } } } return output }
func Encode(input *oproto.ValueStream) *oproto.ValueStream { output := &oproto.ValueStream{Variable: input.Variable} var last *oproto.Value for _, value := range input.Value { if last == nil { last = value continue } if last.StringValue != "" && value.StringValue != "" { if last.StringValue == value.StringValue { if value.EndTimestamp > value.Timestamp { last.EndTimestamp = value.EndTimestamp } else { last.EndTimestamp = value.Timestamp } continue } } else { if last.DoubleValue == value.DoubleValue { if value.EndTimestamp > value.Timestamp { last.EndTimestamp = value.EndTimestamp } else { last.EndTimestamp = value.Timestamp } continue } } if last.EndTimestamp == 0 && last.Timestamp != 0 { last.EndTimestamp = last.Timestamp } output.Value = append(output.Value, last) last = value } if last != nil { if last.EndTimestamp == 0 && last.Timestamp != 0 { last.EndTimestamp = last.Timestamp } output.Value = append(output.Value, last) } return output }
func findFirstMatchingPolicy(value *oproto.Value, policies []*oproto.RetentionPolicyItem) *oproto.RetentionPolicyItem { now := openinstrument.NowMs() valueStartAge := now - value.Timestamp if value.EndTimestamp == 0 && value.Timestamp != 0 { value.EndTimestamp = value.Timestamp } valueEndAge := now - value.EndTimestamp for _, item := range policies { if len(item.Variable) == 0 { // No variables supplied, this matches everything return item } for _, i := range item.Variable { // Look for policies that match the variable age v := variable.NewFromProto(i) if v.TimestampInsideRange(valueStartAge) || v.TimestampInsideRange(valueEndAge) { return item } } } return nil }