From 84ed251fa9d855ed7ef5951df315a6b5e558187d Mon Sep 17 00:00:00 2001 From: Josh Harshman Date: Fri, 19 Jan 2024 10:01:25 -0700 Subject: [PATCH] Remove tscli from project. This PR removes the tscli utility from the project. --- Makefile | 14 ---- tscli/Makefile | 13 ---- tscli/README.md | 42 ------------ tscli/main.go | 167 --------------------------------------------- tscli/main_test.go | 57 ---------------- 5 files changed, 293 deletions(-) delete mode 100644 tscli/Makefile delete mode 100644 tscli/README.md delete mode 100644 tscli/main.go delete mode 100644 tscli/main_test.go diff --git a/Makefile b/Makefile index 327f2ea..a1ed9e4 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,3 @@ -BINDIR ?= ./bin -SCRIPTDIR := ./scripts SHELL := /bin/bash GOBIN := $(shell which go 2> /dev/null) ifeq ($(GOBIN),) @@ -10,15 +8,3 @@ endif test: $(GOBIN) test -v ./... -.PHONY: build -build: - make -C tscli - -.PHONY: install -install: build - cp $(BINDIR)/tscli /usr/local/bin/ - -.PHONY: clean -clean: - rm -rf $(BINDIR) - diff --git a/tscli/Makefile b/tscli/Makefile deleted file mode 100644 index a70ff11..0000000 --- a/tscli/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -BINDIR ?= ../bin -SHELL := /bin/bash -GOBIN := $(shell which go 2> /dev/null) -ifeq ($(GOBIN),) -GOBIN := /usr/local/go/bin/go -endif - -default: build - -.PHONY: build -build: - @mkdir -p $(BINDIR) - $(GOBIN) build -o $(BINDIR)/tscli diff --git a/tscli/README.md b/tscli/README.md deleted file mode 100644 index 289c1a0..0000000 --- a/tscli/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# TSCLI -A CLI front-end to the libbitly/tsplot package. - -``` -$ tscli -h - -_____________________________ .____ .___ -\__ ___/ _____/\_ ___ \| | | | - | | \_____ \ / \ \/| | | | - | | / \\ \___| |___| | - |____| /_______ / \______ /_______ \___| - \/ \/ \/ -A CLI front-end to the tsplot package which provides a method of plotting time series data taken -from Google Cloud Monitoring (formerly StackDriver). - -Usage: - tscli [flags] - -Flags: - -a, --app string The (Bitly) application. Usually top level directory - --end string End of the time window for which the query returns time series data for. Hours or minutes accepted, i.e: -5h or -5m or now. (default "now") - -h, --help help for tscli - -m, --metric string The metric. - -o, --output string Specify output directory for resulting plot. Defaults to current working directory. - --print-raw Only print time series data and exit. - -p, --project string GCP Project. - --query-override string Override the default query. Must be a full valid query. Metric flag is not used. - --reduce Use a time series reducer to return a single averaged result. - -s, --service string The (Bitly) service. Service directory found under application directory. - --start string Start time of window for which the query returns time series data for. Hours or minutes accepted, i.e: -5h or -5m. - -``` - -## Authentication -Authentication is done via `GOOGLE_APPLICATION_CREDENTIALS`. Ensure this variable is exported -in your environment and that it points to a valid GCP Service Account JSON file. - -Otherwise, you will encounter this error: -``` -err creating metric client google: could not find default credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information. -exit status 1 -``` diff --git a/tscli/main.go b/tscli/main.go deleted file mode 100644 index 3a8a7cf..0000000 --- a/tscli/main.go +++ /dev/null @@ -1,167 +0,0 @@ -package main - -import ( - "context" - "errors" - "fmt" - "log" - "os" - "regexp" - "strconv" - "strings" - "time" - - monitoring "cloud.google.com/go/monitoring/apiv3/v2" - "github.com/bitly/tsplot/tsplot" - "github.com/spf13/cobra" - "gonum.org/v1/plot/vg" - "google.golang.org/api/option" - monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" - "google.golang.org/protobuf/types/known/durationpb" - "google.golang.org/protobuf/types/known/timestamppb" -) - -const GAP = "GOOGLE_APPLICATION_CREDENTIALS" - -var GoogleCloudMonitoringClient *monitoring.MetricClient - -func main() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintf(os.Stderr, "err %v\n", err) - os.Exit(1) - } -} - -var ( - rootCmd = &cobra.Command{ - Use: "tscli", - Short: "Plots time series data from GCM.", - Long: ` -_____________________________ .____ .___ -\__ ___/ _____/\_ ___ \| | | | - | | \_____ \ / \ \/| | | | - | | / \\ \___| |___| | - |____| /_______ / \______ /_______ \___| - \/ \/ \/ -A CLI front-end to the tsplot package which provides a method of plotting time series data taken -from Google Cloud Monitoring (formerly StackDriver). -`, - PreRunE: auth, - RunE: executeQuery, - } - - project string - query string - startTime string - endTime string - outDir string - title string - groupBy string -) - -func init() { - rootCmd.Flags().StringVarP(&project, "project", "p", "", "GCP Project.") - rootCmd.Flags().StringVarP(&query, "query", "m", "", "The query filter.") - rootCmd.Flags().StringVar(&startTime, "start", "", "Start time of window for which the query returns time series data for. Hours or minutes accepted, i.e: -5h or -5m.") - rootCmd.Flags().StringVar(&endTime, "end", "now", "End of the time window for which the query returns time series data for. Hours or minutes accepted, i.e: -5h or -5m or now.") - rootCmd.Flags().StringVarP(&outDir, "output", "o", "", "Specify output directory for resulting plot. Defaults to current working directory.") - rootCmd.Flags().StringVarP(&title, "title", "t", "", "Specify title of graph.") - rootCmd.Flags().StringVar(&groupBy, "group-by", "", "Key to group metric by when dealing with multiple time series.") - rootCmd.MarkFlagRequired("project") - rootCmd.MarkFlagRequired("query") - rootCmd.MarkFlagRequired("start") - rootCmd.MarkFlagRequired("title") - rootCmd.MarkFlagRequired("output") -} - -func auth(cmd *cobra.Command, args []string) error { - var opts []option.ClientOption - serviceAccountJsonPath := os.Getenv(GAP) - if serviceAccountJsonPath != "" { - opts = append(opts, option.WithCredentialsFile(serviceAccountJsonPath)) - } - - mc, err := monitoring.NewMetricClient(context.Background(), opts...) - if err != nil { - return err - } - GoogleCloudMonitoringClient = mc - return nil -} - -func executeQuery(cmd *cobra.Command, args []string) error { - - if !timeFormatOK(startTime) { - return errors.New("err validating start time format") - } - - if endTime != "" && !timeFormatOK(endTime) { - return errors.New("err validating end time format") - } - - if startTime == endTime { - return errors.New("err invalid time frame") - } - - st := parseTime(startTime) - et := parseTime(endTime) - - request := &monitoringpb.ListTimeSeriesRequest{ - Name: fmt.Sprintf("projects/%s", project), - //`resource.type = "global" AND metric.type = "custom.googleapis.com/opencensus/fishnet/queuereader_fishnet/messages_total"` - Filter: query, - Interval: &monitoringpb.TimeInterval{ - EndTime: timestamppb.New(et), - StartTime: timestamppb.New(st), - }, - Aggregation: &monitoringpb.Aggregation{ - AlignmentPeriod: durationpb.New(time.Minute * 1), - // todo: these need to be settable as they are not uniformly useful across all metric types. - PerSeriesAligner: monitoringpb.Aggregation_ALIGN_RATE, - CrossSeriesReducer: monitoringpb.Aggregation_REDUCE_MEAN, - GroupByFields: []string{fmt.Sprintf("metric.labels.%s", groupBy)}, - }, - View: monitoringpb.ListTimeSeriesRequest_FULL, - } - - tsi := GoogleCloudMonitoringClient.ListTimeSeries(context.Background(), request) - plot, err := tsplot.NewPlotFromTimeSeriesIterator(tsi, groupBy, tsplot.WithXTimeTicks(time.Kitchen), tsplot.WithTitle(title), tsplot.WithXAxisName("UTC")) - if err != nil { - log.Fatal(err) - } - - saveFile := fmt.Sprintf("%s/%s.png", outDir, title) - return plot.Save(8*vg.Inch, 4*vg.Inch, saveFile) -} - -func timeFormatOK(s string) bool { - if s == "" { - return false - } - if s == "now" { - return true - } - b, _ := regexp.MatchString(`^-\d+[m,h]$`, s) - if !b { - return false - } - return true -} - -func parseTime(s string) time.Time { - if s == "now" { - return time.Now() - } - parts := strings.Split(s, "") - num, _ := strconv.Atoi(parts[1 : len(parts)-1][0]) - unit := parts[len(parts)-1] - now := time.Now() - var t time.Time - switch unit { - case "m": - t = now.Add(-time.Minute * time.Duration(num)) - case "h": - t = now.Add(-time.Hour * time.Duration(num)) - } - return t -} diff --git a/tscli/main_test.go b/tscli/main_test.go deleted file mode 100644 index 24ec6d9..0000000 --- a/tscli/main_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "testing" -) - -func Test_timeFormatOK(t *testing.T) { - tests := []struct { - desc string - input string - expect bool - }{ - { - desc: "correctly formatted current time", - input: "now", - expect: true, - }, - { - desc: "correctly formed hour", - input: "-1h", - expect: true, - }, - { - desc: "correctly formed minute", - input: "-1m", - expect: true, - }, - { - desc: "incorrectly formed, no unit", - input: "-1", - expect: false, - }, - { - desc: "incorrectly formed, no value", - input: "-m", - expect: false, - }, - { - desc: "incorrectly formed, no negative sign", - input: "1h", - expect: false, - }, - { - desc: "empty string", - input: "", - expect: false, - }, - } - - for _, test := range tests { - t.Run(test.desc, func(tt *testing.T) { - if got := timeFormatOK(test.input); got != test.expect { - tt.Errorf("expected: %t, but got %t\n", test.expect, got) - } - }) - } -}