diff --git a/cmd/mock_server.go b/cmd/mock_server.go
index fbfe1c0..7977c99 100644
--- a/cmd/mock_server.go
+++ b/cmd/mock_server.go
@@ -48,6 +48,7 @@ var (
type summaryTable struct {
Spans []*cloudtrace.Span
MetricDescriptors []*validation.DescriptorStatus
+ TimeSeries []*validation.TimeSeriesStatus
}
func main() {
@@ -87,7 +88,8 @@ func startStandaloneServer() {
<-sig
grpcServer.GracefulStop()
if *summary {
- summaryTable := createSummaryTable(mockTraceServer.SpansSummary(), mockMetricServer.MetricDescriptorSummary())
+ summaryTable := createSummaryTable(mockTraceServer.SpansSummary(),
+ mockMetricServer.MetricDescriptorSummary(), mockMetricServer.TimeSeriesSummary())
writeSummaryPage(summaryTable)
}
finish <- true
@@ -99,10 +101,12 @@ func startStandaloneServer() {
<-finish
}
-func createSummaryTable(spans []*cloudtrace.Span, descriptors []*validation.DescriptorStatus) summaryTable {
+func createSummaryTable(spans []*cloudtrace.Span, descriptors []*validation.DescriptorStatus,
+ timeSeries []*validation.TimeSeriesStatus) summaryTable {
return summaryTable{
Spans: spans,
MetricDescriptors: descriptors,
+ TimeSeries: timeSeries,
}
}
diff --git a/internal/validation/mock_metric_validation.go b/internal/validation/mock_metric_validation.go
index 904d9cc..61c65d6 100644
--- a/internal/validation/mock_metric_validation.go
+++ b/internal/validation/mock_metric_validation.go
@@ -70,6 +70,21 @@ type PreviousPoint struct {
Time time.Time
}
+// TimeSeriesStruct wraps a TimeSeries with the status of its creation.
+// Used in the TimeSeries summary table.
+type TimeSeriesStatus struct {
+ TimeSeries *monitoring.TimeSeries
+ Status string
+}
+
+// TimeSeriesData is a wrapper struct for all the data that the server
+// keeps with respect to time series.
+type TimeSeriesData struct {
+ UploadedPoints map[string]*PreviousPoint
+ TimeSeriesSummary []*TimeSeriesStatus
+ TimeSeriesLock sync.Mutex
+}
+
// ValidateRequiredFields verifies that the given request contains the required fields.
func ValidateRequiredFields(req interface{}) error {
reqReflect := reflect.ValueOf(req)
@@ -261,45 +276,71 @@ func ValidateRateLimit(timeSeries []*monitoring.TimeSeries, uploadedPoints map[s
}
// ValidateCreateTimeSeries checks that the given TimeSeries conform to the API requirements.
-func ValidateCreateTimeSeries(timeSeries []*monitoring.TimeSeries, descriptors map[string]*metric.MetricDescriptor,
- uploadedPoints map[string]*PreviousPoint) error {
+func ValidateCreateTimeSeries(timeSeries []*monitoring.TimeSeries, timeSeriesData *TimeSeriesData, descriptors map[string]*metric.MetricDescriptor) error {
if len(timeSeries) > maxTimeSeriesPerRequest {
return statusTooManyTimeSeries
}
+ var overallErr error
for _, ts := range timeSeries {
+ var currentErr error
+
// Check that required fields for time series are present.
if ts.Metric == nil || len(ts.Points) != 1 || ts.Resource == nil {
- return statusInvalidTimeSeries
+ addTimeSeriesToSummary(&timeSeriesData.TimeSeriesSummary, ts, statusInvalidTimeSeries.Error())
+ currentErr = statusInvalidTimeSeries
}
// Check that the metric labels follow the constraints.
for k, v := range ts.Metric.Labels {
if len(k) > maxTimeSeriesLabelKeyBytes {
- return statusInvalidTimeSeriesLabelKey
+ addTimeSeriesToSummary(&timeSeriesData.TimeSeriesSummary, ts, statusInvalidTimeSeriesLabelKey.Error())
+ currentErr = statusInvalidTimeSeriesLabelKey
}
if len(v) > maxTimeSeriesLabelValueBytes {
- return statusInvalidTimeSeriesLabelValue
+ addTimeSeriesToSummary(&timeSeriesData.TimeSeriesSummary, ts, statusInvalidTimeSeriesLabelValue.Error())
+ currentErr = statusInvalidTimeSeriesLabelValue
}
}
if err := validateMetricKind(ts, descriptors); err != nil {
- return err
+ addTimeSeriesToSummary(&timeSeriesData.TimeSeriesSummary, ts, err.Error())
+ currentErr = err
}
- if err := validateValueType(ts.ValueType, ts.Points[0]); err != nil {
- return err
+ if len(ts.Points) == 1 {
+ if err := validateValueType(ts.ValueType, ts.Points[0]); err != nil {
+ addTimeSeriesToSummary(&timeSeriesData.TimeSeriesSummary, ts, err.Error())
+ currentErr = err
+ }
+
+ if err := validatePoint(ts, timeSeriesData.UploadedPoints); err != nil {
+ addTimeSeriesToSummary(&timeSeriesData.TimeSeriesSummary, ts, err.Error())
+ currentErr = err
+ }
}
- if err := validatePoint(ts, uploadedPoints); err != nil {
- return err
+ if currentErr == nil {
+ addTimeSeriesToSummary(&timeSeriesData.TimeSeriesSummary, ts, "OK")
+ } else {
+ overallErr = currentErr
}
}
+ if overallErr != nil {
+ return overallErr
+ }
return nil
}
+func addTimeSeriesToSummary(summary *[]*TimeSeriesStatus, ts *monitoring.TimeSeries, err string) {
+ *summary = append(*summary, &TimeSeriesStatus{
+ TimeSeries: ts,
+ Status: err,
+ })
+}
+
// validateMetricKind check that if metric_kind is present,
// it is the same as the metricKind of the associated metric.
func validateMetricKind(timeSeries *monitoring.TimeSeries, descriptors map[string]*metric.MetricDescriptor) error {
diff --git a/server/metric/mock_metric.go b/server/metric/mock_metric.go
index 7d4d33a..5d9f271 100644
--- a/server/metric/mock_metric.go
+++ b/server/metric/mock_metric.go
@@ -15,8 +15,6 @@
package metric
import (
- "sync"
-
"github.com/golang/protobuf/ptypes/empty"
"github.com/googleinterns/cloud-operations-api-mock/internal/validation"
"golang.org/x/net/context"
@@ -32,8 +30,7 @@ import (
type MockMetricServer struct {
monitoring.UnimplementedMetricServiceServer
metricDescriptorData *validation.MetricDescriptorData
- uploadedPoints map[string]*validation.PreviousPoint
- uploadedPointsLock sync.Mutex
+ timeSeriesData *validation.TimeSeriesData
}
// NewMockMetricServer creates a new MockMetricServer and returns a pointer to it.
@@ -43,9 +40,12 @@ func NewMockMetricServer() *MockMetricServer {
UploadedMetricDescriptors: uploadedMetricDescriptors,
}
uploadedPoints := make(map[string]*validation.PreviousPoint)
+ timeSeriesData := &validation.TimeSeriesData{
+ UploadedPoints: uploadedPoints,
+ }
return &MockMetricServer{
metricDescriptorData: metricDescriptorData,
- uploadedPoints: uploadedPoints,
+ timeSeriesData: timeSeriesData,
}
}
@@ -152,24 +152,21 @@ func (s *MockMetricServer) ListMetricDescriptors(ctx context.Context, req *monit
// If it already exists, an error is returned.
func (s *MockMetricServer) CreateTimeSeries(ctx context.Context, req *monitoring.CreateTimeSeriesRequest,
) (*empty.Empty, error) {
- s.uploadedPointsLock.Lock()
- if err := validation.ValidateRateLimit(req.TimeSeries, s.uploadedPoints); err != nil {
- s.uploadedPointsLock.Unlock()
+ s.timeSeriesData.TimeSeriesLock.Lock()
+ defer s.timeSeriesData.TimeSeriesLock.Unlock()
+ if err := validation.ValidateRateLimit(req.TimeSeries, s.timeSeriesData.UploadedPoints); err != nil {
return nil, err
}
- s.uploadedPointsLock.Unlock()
if err := validation.ValidateRequiredFields(req); err != nil {
return nil, err
}
if err := validation.ValidateProjectName(req.Name); err != nil {
return nil, err
}
- if err := validation.ValidateCreateTimeSeries(req.TimeSeries, s.metricDescriptorData.UploadedMetricDescriptors, s.uploadedPoints); err != nil {
+ if err := validation.ValidateCreateTimeSeries(req.TimeSeries, s.timeSeriesData, s.metricDescriptorData.UploadedMetricDescriptors); err != nil {
return nil, err
}
- s.uploadedPointsLock.Lock()
- defer s.uploadedPointsLock.Unlock()
- validation.AddPoint(req.TimeSeries, s.uploadedPoints)
+ validation.AddPoint(req.TimeSeries, s.timeSeriesData.UploadedPoints)
return &empty.Empty{}, nil
}
@@ -199,3 +196,8 @@ func addMetricDescriptorToSummary(summary *[]*validation.DescriptorStatus, metri
func (s *MockMetricServer) MetricDescriptorSummary() []*validation.DescriptorStatus {
return s.metricDescriptorData.MetricDescriptorSummary
}
+
+// TimeSeriesSummary returns the time series data to display in the summary page.
+func (s *MockMetricServer) TimeSeriesSummary() []*validation.TimeSeriesStatus {
+ return s.timeSeriesData.TimeSeriesSummary
+}
diff --git a/static/css/main.css b/static/css/main.css
index 20347df..3b9f3c7 100755
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -22,7 +22,7 @@ body, html {
align-items: center;
justify-content: center;
flex-wrap: wrap;
- padding: 33px 30px;
+ padding: 0 60px 60px;
}
.summary {
@@ -92,3 +92,10 @@ th, td {
color: #808080;
line-height: 1.4;
}
+
+.title {
+ color: #6c7ae0;
+ text-decoration: underline;
+ padding-top: 50px;
+ padding-bottom: 50px;
+}
diff --git a/static/summary_template.html b/static/summary_template.html
index b1f5d7b..75bc4c1 100755
--- a/static/summary_template.html
+++ b/static/summary_template.html
@@ -10,7 +10,7 @@
-
Trace Summary
+
Trace
@@ -43,7 +43,7 @@ Trace Summary
- Metric Descriptors Summary
+ Metric Descriptors
@@ -56,7 +56,6 @@ Metric Descriptors Summa
-
@@ -75,6 +74,49 @@ Metric Descriptors Summa
+
+
+ Time Series
+
+
+
+
+
+ Metric Type |
+ Metric Labels |
+ Monitored Resource Type |
+ Monitored Resource Labels |
+ Point Interval |
+ Status |
+
+
+
+
+
+
+
+ {{ range $index, $ts := .TimeSeries }}
+ {{ if eq $ts.Status "OK" }}
+
+ {{ else }}
+
+ {{ end }}
+ {{ $ts.TimeSeries.Metric.Type }} |
+ {{ $ts.TimeSeries.Metric.Labels }} |
+ {{ $ts.TimeSeries.Resource.Type }} |
+ {{ $ts.TimeSeries.Resource.Labels }} |
+ {{ if $ts.TimeSeries.Points }}
+ {{ (index $ts.TimeSeries.Points 0).Interval }} |
+ {{ else }}
+ Missing Point |
+ {{ end }}
+ {{ $ts.Status }} |
+
+ {{ end }}
+
+
+
+