package metrics import ( "fmt" "strings" "time" "cloud.google.com/go/monitoring/apiv3/v2/monitoringpb" "google.golang.org/genproto/googleapis/api/distribution" "google.golang.org/genproto/googleapis/api/metric" "google.golang.org/genproto/googleapis/api/monitoredres" "google.golang.org/protobuf/types/known/timestamppb" "edge-infra.dev/pkg/lib/gcp/monitoring/monutil" ) const ( location = "us-east1-b" ) // creates a timeSeries entry with the specified label slice func (c *Client) AddTimeSeriesLabels(d *Descriptor, l []string) bool { var err error var tsReq monitoringpb.CreateTimeSeriesRequest var tsVal monitoringpb.TimeSeries tsReq.Name = fmt.Sprintf("projects/%s", c.ProjectID) rLabels := monutil.SliceToMap([]string{"project_id", "location", "cluster", "namespace", "job", "instance"}) rLabels["project_id"] = c.ProjectID rLabels["location"] = location tsVal.Resource = &monitoredres.MonitoredResource{ Labels: rLabels, Type: "prometheus_target", } switch strings.ToUpper(d.ValueType) { case "DOUBLE": tsVal.ValueType = *metric.MetricDescriptor_DOUBLE.Enum() case "DISTRIBUTION": tsVal.ValueType = *metric.MetricDescriptor_DISTRIBUTION.Enum() default: fmt.Printf("%s ValueType not supported yet\n", d.ValueType) return false } tsVal.Metric = &metric.Metric{ Type: d.Type, Labels: monutil.SliceToMap(l), } tsVal.Points, err = d.tsPoint() if err != nil { return false } tsReq.TimeSeries = append(tsReq.TimeSeries, &tsVal) // create timeseries err = c.client.CreateTimeSeries(c.ctx, &tsReq) if err != nil { fmt.Printf("CreateTimeSeries Error: %s", err.Error()) } return err == nil } // creates a timeSeries point object for a given descriptor func (d *Descriptor) tsPoint() ([]*monitoringpb.Point, error) { var tsP monitoringpb.Point sT, err := getTime(true) if err != nil { return nil, err } var eT time.Time if d.MetricKind == "GAUGE" { eT = sT } else { eT, err = getTime(false) if err != nil { return nil, err } } tsP.Interval = &monitoringpb.TimeInterval{ StartTime: setTimeInterval(&sT), EndTime: setTimeInterval(&eT), } if strings.ToUpper(d.ValueType) == "DOUBLE" { tsP.Value = &monitoringpb.TypedValue{ Value: &monitoringpb.TypedValue_DoubleValue{ DoubleValue: 0, }, } return []*monitoringpb.Point{&tsP}, nil } else if d.ValueType == "DISTRIBUTION" { tsP.Value = &monitoringpb.TypedValue{ Value: &monitoringpb.TypedValue_DistributionValue{ DistributionValue: &distribution.Distribution{ BucketOptions: &distribution.Distribution_BucketOptions{ Options: &distribution.Distribution_BucketOptions_ExplicitBuckets{ ExplicitBuckets: &distribution.Distribution_BucketOptions_Explicit{ Bounds: []float64{0}, }, }, }, }, }, } return []*monitoringpb.Point{&tsP}, nil } return nil, fmt.Errorf("%s ValueType or %s MetricKind not currently supported by metermaid", d.ValueType, d.MetricKind) } // returns a timestamp object for a specified time value func setTimeInterval(t *time.Time) *timestamppb.Timestamp { return ×tamppb.Timestamp{Seconds: t.Unix(), Nanos: 0} } // returns the formatted date/time string, true for startTime, false for endTime func getTime(t bool) (time.Time, error) { currTime := time.Now().UTC().Format("2006-01-02") if t { return time.Parse("2006-01-02T15:04:05.000000Z", currTime+"T00:00:00.000000Z") } return time.Parse("2006-01-02T15:04:05.000000Z", currTime+"T00:00:01.000000Z") }