func BuildJobResultRequest(input JobResultArgs) (*monitoringpb.CreateTimeSeriesRequest, error) {
	var endTimestamp int64
	if input.EndTimestamp == nil {
		endTimestamp = time.Now().UnixNano() / 1000000
	} else {
		endTimestamp = *input.EndTimestamp
	}
	if e := validateJobResultRequestInput(&input); e != nil {
		return nil, e
	}
	return &monitoringpb.CreateTimeSeriesRequest{
		Name: "projects/" + input.ProjectID,
		TimeSeries: []*monitoringpb.TimeSeries{{
			Metric: &metricpb.Metric{
				Type: "custom.googleapis.com/" + input.MetricPath,
				Labels: map[string]string{
					"result_state": input.ResultState,
				},
			},
			Resource: &monitoredres.MonitoredResource{
				Type: "generic_task",
				Labels: map[string]string{
					"project_id": input.ProjectID,
					"location":   input.Zone,
					"namespace":  input.Pipeline,
					"job":        input.Job,
					"task_id":    input.Task,
				},
			},
			Points: []*monitoringpb.Point{{
				Interval: &monitoringpb.TimeInterval{
					EndTime: &timestamp.Timestamp{
						Seconds: endTimestamp / 1000,
					},
				},
				Value: &monitoringpb.TypedValue{
					Value: &monitoringpb.TypedValue_Int64Value{
						Int64Value: endTimestamp - input.StartTimestamp,
					},
				},
			}},
		}},
	}, nil
}
BuildJobResultRequest builds a new job result request object to submit to gcp cloud monitoring.
package requests
import (
	"fmt"
	"strings"
	"time"
	"github.com/golang/protobuf/ptypes/timestamp"
	metricpb "google.golang.org/genproto/googleapis/api/metric"
	"google.golang.org/genproto/googleapis/api/monitoredres"
	monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
)
type JobResultArgs struct {
	EndTimestamp   *int64  
	Job            string
	MetricPath     string
	Pipeline       string
	ProjectID      string
	ResultState    string
	StartTimestamp int64  
	Task           string
	Zone           string
}
func validateJobResultRequestInput(input *JobResultArgs) error {
	if strings.TrimSpace(input.ProjectID) == "" {
		return fmt.Errorf("empty project-id value")
	}
	if strings.TrimSpace(input.Zone) == "" {
		return fmt.Errorf("empty zone value")
	}
	if strings.TrimSpace(input.Pipeline) == "" {
		return fmt.Errorf("empty pipeline value")
	}
	if strings.TrimSpace(input.Job) == "" {
		return fmt.Errorf("empty job value")
	}
	if strings.TrimSpace(input.Task) == "" {
		return fmt.Errorf("empty task value")
	}
	if strings.TrimSpace(input.MetricPath) == "" {
		return fmt.Errorf("empty metric-path value")
	}
	state := strings.TrimSpace(input.ResultState)
	if state != "success" && state != "failure" {
		return fmt.Errorf("invalid state value")
	}
	if input.EndTimestamp != nil && *input.EndTimestamp < input.StartTimestamp {
		return fmt.Errorf("end-timestamp cannot occur before start-timestamp")
	}
	return nil
}