diff --git a/.gitignore b/.gitignore index 13af037bf..25e84215a 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,4 @@ experimental/_integration/_integration app/static.go prog/static.go vendor/github.com/2opremio/go-1/codec/codecgen/codecgen -report/report.codecgen.go \ No newline at end of file +*.codecgen.go diff --git a/Makefile b/Makefile index 973448a18..7bbf2c1c8 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ DOCKER_DISTRIB_URL=https://get.docker.com/builds/Linux/x86_64/docker-$(DOCKER_VE RUNSVINIT=vendor/runsvinit/runsvinit CODECGEN_DIR=vendor/github.com/2opremio/go-1/codec/codecgen CODECGEN_EXE=$(CODECGEN_DIR)/codecgen +CODECGEN_TARGETS=report/report.codecgen.go render/render.codecgen.go render/detailed/detailed.codecgen.go RM=--rm RUN_FLAGS=-ti BUILD_IN_CONTAINER=true @@ -60,7 +61,7 @@ $(SCOPE_EXE) $(RUNSVINIT) lint tests shell: $(SCOPE_BACKEND_BUILD_UPTODATE) else -$(SCOPE_EXE): $(SCOPE_BACKEND_BUILD_UPTODATE) +$(SCOPE_EXE): $(SCOPE_BACKEND_BUILD_UPTODATE) $(CODECGEN_TARGETS) time $(GO) build $(GO_BUILD_FLAGS) -o $@ ./$(@D) @strings $@ | grep cgo_stub\\\.go >/dev/null || { \ rm $@; \ @@ -71,11 +72,10 @@ $(SCOPE_EXE): $(SCOPE_BACKEND_BUILD_UPTODATE) false; \ } -$(SCOPE_EXE): report/report.codecgen.go - -CODECGEN_REPORT_SOURCES=$(shell find report/ -type f -name '*.go' -not -name '*_test.go' -not -name '*.codecgen.go' -not -name '*.generated.go') -report/report.codecgen.go: $(CODECGEN_EXE) $(CODECGEN_REPORT_SOURCES) - cd report && $(GO_HOST_ENV) ../$(CODECGEN_EXE) -u -o $(@F) $(notdir $(CODECGEN_REPORT_SOURCES)) +# Enable second expansion to automatically generate the dependencies of codecgen +.SECONDEXPANSION: +%.codecgen.go: $(CODECGEN_EXE) $$(shell find $$(@D) -maxdepth 1 -type f -name '*.go' -not -name '*_test.go' -not -name '*.codecgen.go' -not -name '*.generated.go') + cd $(@D) && $(GO_HOST_ENV) $(shell pwd)/$(CODECGEN_EXE) -u -o $(@F) $(notdir $(filter-out $<,$^)) $(CODECGEN_EXE): $(CODECGEN_DIR)/*.go $(GO_HOST_ENV) $(GO) build $(GO_BUILD_TAGS) -o $@ ./$(@D) @@ -137,7 +137,8 @@ clean: $(GO) clean ./... $(SUDO) docker rmi $(SCOPE_UI_BUILD_IMAGE) $(SCOPE_BACKEND_BUILD_IMAGE) >/dev/null 2>&1 || true rm -rf $(SCOPE_EXPORT) $(SCOPE_UI_BUILD_UPTODATE) $(SCOPE_BACKEND_BUILD_UPTODATE) \ - $(SCOPE_EXE) $(RUNSVINIT) prog/static.go client/build/app.js docker/weave .pkg + $(SCOPE_EXE) $(RUNSVINIT) prog/static.go client/build/app.js docker/weave .pkg \ + $(CODECGEN_TARGETS) $(CODECGEN_EXE) deps: $(GO) get -u -f $(GO_BUILD_TAGS) \ diff --git a/render/detailed/metadata.go b/render/detailed/metadata.go index 124823eae..2cebac534 100644 --- a/render/detailed/metadata.go +++ b/render/detailed/metadata.go @@ -1,7 +1,6 @@ package detailed import ( - "bytes" "strconv" "strings" @@ -105,6 +104,7 @@ func (c Counter) MetadataRows(n report.Node) []MetadataRow { } // MetadataRow is a row for the metadata table. +// codecgen: skip type MetadataRow struct { ID string Value string @@ -119,23 +119,44 @@ func (m MetadataRow) Copy() MetadataRow { } } -// MarshalJSON marshals this MetadataRow to json. It adds a label before +// MarshalJSON shouldn't be used, use CodecEncodeSelf instead +func (MetadataRow) MarshalJSON() ([]byte, error) { + panic("MarshalJSON shouldn't be used, use CodecEncodeSelf instead") +} + +// UnmarshalJSON shouldn't be used, use CodecDecodeSelf instead +func (*MetadataRow) UnmarshalJSON(b []byte) error { + panic("UnmarshalJSON shouldn't be used, use CodecDecodeSelf instead") +} + +type labelledMetadataRow struct { + ID string `json:"id"` + Label string `json:"label"` + Value string `json:"value"` + Prime bool `json:"prime,omitempty"` +} + +// CodecEncodeSelf marshals this MetadataRow. It adds a label before // rendering. -func (m MetadataRow) MarshalJSON() ([]byte, error) { - buf := bytes.Buffer{} - encoder := codec.NewEncoder(&buf, &codec.JsonHandle{}) - err := encoder.Encode(struct { - ID string `json:"id"` - Label string `json:"label"` - Value string `json:"value"` - Prime bool `json:"prime,omitempty"` - }{ +func (m *MetadataRow) CodecEncodeSelf(encoder *codec.Encoder) { + in := labelledMetadataRow{ ID: m.ID, Label: Label(m.ID), Value: m.Value, Prime: m.Prime, - }) - return buf.Bytes(), err + } + encoder.Encode(in) +} + +// CodecDecodeSelf implements codec.Selfer +func (m *MetadataRow) CodecDecodeSelf(decoder *codec.Decoder) { + var in labelledMetadataRow + decoder.Decode(&in) + *m = MetadataRow{ + ID: in.ID, + Value: in.Value, + Prime: in.Prime, + } } // NodeMetadata produces a table (to be consumed directly by the UI) based on diff --git a/render/detailed/metrics.go b/render/detailed/metrics.go index 182c47ffc..18751a249 100644 --- a/render/detailed/metrics.go +++ b/render/detailed/metrics.go @@ -1,7 +1,6 @@ package detailed import ( - "bytes" "math" "github.com/ugorji/go/codec" @@ -37,6 +36,7 @@ var ( // MetricRow is a tuple of data used to render a metric as a sparkline and // accoutrements. +// codecgen: skip type MetricRow struct { ID string Format string @@ -60,19 +60,29 @@ func (m MetricRow) Copy() MetricRow { return row } -// MarshalJSON marshals this MetricRow to json. It takes the basic Metric +// MarshalJSON shouldn't be used, use CodecEncodeSelf instead +func (MetricRow) MarshalJSON() ([]byte, error) { + panic("MarshalJSON shouldn't be used, use CodecEncodeSelf instead") +} + +// UnmarshalJSON shouldn't be used, use CodecDecodeSelf instead +func (*MetricRow) UnmarshalJSON(b []byte) error { + panic("UnmarshalJSON shouldn't be used, use CodecDecodeSelf instead") +} + +type wiredMetricRow struct { + ID string `json:"id"` + Label string `json:"label"` + Format string `json:"format,omitempty"` + Group string `json:"group,omitempty"` + Value float64 `json:"value"` + report.WireMetrics +} + +// CodecEncodeSelf marshals this MetricRow. It takes the basic Metric // rendering, then adds some row-specific fields. -func (m MetricRow) MarshalJSON() ([]byte, error) { - buf := bytes.Buffer{} - encoder := codec.NewEncoder(&buf, &codec.JsonHandle{}) - err := encoder.Encode(struct { - ID string `json:"id"` - Label string `json:"label"` - Format string `json:"format,omitempty"` - Group string `json:"group,omitempty"` - Value float64 `json:"value"` - report.WireMetrics - }{ +func (m *MetricRow) CodecEncodeSelf(encoder *codec.Encoder) { + encoder.Encode(wiredMetricRow{ ID: m.ID, Label: Label(m.ID), Format: m.Format, @@ -80,7 +90,21 @@ func (m MetricRow) MarshalJSON() ([]byte, error) { Value: m.Value, WireMetrics: m.Metric.ToIntermediate(), }) - return buf.Bytes(), err +} + +// CodecDecodeSelf implements codec.Selfer +func (m *MetricRow) CodecDecodeSelf(decoder *codec.Decoder) { + var in wiredMetricRow + decoder.Decode(&in) + + metric := in.WireMetrics.FromIntermediate() + *m = MetricRow{ + ID: in.ID, + Format: in.Format, + Group: in.Group, + Value: in.Value, + Metric: &metric, + } } // NodeMetrics produces a table (to be consumed directly by the UI) based on diff --git a/render/detailed/summary.go b/render/detailed/summary.go index 8cc65c054..14e252c08 100644 --- a/render/detailed/summary.go +++ b/render/detailed/summary.go @@ -36,6 +36,7 @@ func (g NodeSummaryGroup) Copy() NodeSummaryGroup { // Column provides special json serialization for column ids, so they include // their label for the frontend. +// codecgen: skip type Column string // CodecEncodeSelf implements codec.Selfer diff --git a/report/controls.go b/report/controls.go index d6cb702a7..90aa4363e 100644 --- a/report/controls.go +++ b/report/controls.go @@ -4,6 +4,7 @@ import ( "time" "github.com/ugorji/go/codec" + "github.com/weaveworks/scope/common/mtime" ) diff --git a/report/metrics.go b/report/metrics.go index bd355e89c..182ef0337 100644 --- a/report/metrics.go +++ b/report/metrics.go @@ -254,7 +254,9 @@ func (m Metric) ToIntermediate() WireMetrics { } } -func (m WireMetrics) fromIntermediate() Metric { +// FromIntermediate obtains the metric from a representation suitable +// for serialization. +func (m WireMetrics) FromIntermediate() Metric { samples := ps.NewList() for _, s := range m.Samples { samples = samples.Cons(s) @@ -280,7 +282,7 @@ func (m *Metric) CodecDecodeSelf(decoder *codec.Decoder) { if err := decoder.Decode(&in); err != nil { return } - *m = in.fromIntermediate() + *m = in.FromIntermediate() } // MarshalJSON shouldn't be used, use CodecEncodeSelf instead @@ -306,6 +308,6 @@ func (m *Metric) GobDecode(input []byte) error { if err := gob.NewDecoder(bytes.NewBuffer(input)).Decode(&in); err != nil { return err } - *m = in.fromIntermediate() + *m = in.FromIntermediate() return nil }