From 5dad115b06bace9fc077c29c353d112c02f2c1be Mon Sep 17 00:00:00 2001 From: Carson Long Date: Wed, 8 Nov 2023 08:29:09 -0800 Subject: [PATCH] Refactor the project structure Moves most of the plugin code from main.go to it's own internal/logcache package to increase clarity. This is a pure refactor that should not affect functionality. --- internal/logcache/plugin.go | 118 ++++++++++++++++++++++++++++++++ main.go | 133 ++---------------------------------- version.go | 37 ++++++++++ 3 files changed, 159 insertions(+), 129 deletions(-) create mode 100644 internal/logcache/plugin.go create mode 100644 version.go diff --git a/internal/logcache/plugin.go b/internal/logcache/plugin.go new file mode 100644 index 00000000..bc800d62 --- /dev/null +++ b/internal/logcache/plugin.go @@ -0,0 +1,118 @@ +package logcache + +import ( + "context" + "crypto/tls" + "log" + "net/http" + "os" + + "code.cloudfoundry.org/cli/plugin" + "code.cloudfoundry.org/log-cache-cli/v4/internal/command" + "golang.org/x/term" +) + +type LogCache struct { + version plugin.VersionType +} + +func New(version plugin.VersionType) *LogCache { + return &LogCache{version: version} +} + +func (lc *LogCache) Run(conn plugin.CliConnection, args []string) { + isTerminal := term.IsTerminal(int(os.Stdout.Fd())) + + skipSSL, err := conn.IsSSLDisabled() + if err != nil { + log.Fatal(err) + } + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{ + InsecureSkipVerify: skipSSL, //nolint:gosec + } + + l := log.New(os.Stderr, "", 0) + + switch args[0] { + case "query": + var opts []command.QueryOption + command.Query(conn, args[1:], http.DefaultClient, l, os.Stdout, opts...) + case "tail": + var opts []command.TailOption + if !isTerminal { + opts = append(opts, command.WithTailNoHeaders()) + } + command.Tail(context.Background(), conn, args[1:], http.DefaultClient, l, os.Stdout, opts...) + case "log-meta": + var opts []command.MetaOption + if !isTerminal { + opts = append(opts, command.WithMetaNoHeaders()) + } + command.Meta(conn, args[1:], http.DefaultClient, l, os.Stdout, opts...) + } +} + +func (lc *LogCache) GetMetadata() plugin.PluginMetadata { + return plugin.PluginMetadata{ + Name: "log-cache", + Version: lc.version, + Commands: []plugin.Command{ + { + Name: "tail", + HelpText: "Output logs for a source-id/app", + UsageDetails: plugin.Usage{ + Usage: `tail [options] + +ENVIRONMENT VARIABLES: + LOG_CACHE_ADDR Overrides the default location of log-cache. + LOG_CACHE_SKIP_AUTH Set to 'true' to disable CF authentication.`, + Options: map[string]string{ + "-start-time": "Start of query range in UNIX nanoseconds.", + "-end-time": "End of query range in UNIX nanoseconds.", + "-envelope-type, -t": "Envelope type filter. Available filters: 'log', 'counter', 'gauge', 'timer', 'event', and 'any'.", + "-envelope-class, -c": "Envelope class filter. Available filters: 'logs', 'metrics', and 'any'.", + "-follow, -f": "Output appended to stdout as logs are egressed.", + "-json": "Output envelopes in JSON format.", + "-lines, -n": "Number of envelopes to return. Default is 10.", + "-new-line": "Character used for new line substition, must be single unicode character. Default is '\\n'.", + "-name-filter": "Filters metrics by name.", + }, + }, + }, + { + Name: "log-meta", + HelpText: "Show all available meta information", + UsageDetails: plugin.Usage{ + Usage: `log-meta [options] + +ENVIRONMENT VARIABLES: + LOG_CACHE_ADDR Overrides the default location of log-cache. + LOG_CACHE_SKIP_AUTH Set to 'true' to disable CF authentication.`, + Options: map[string]string{ + "-source-type": "Source type of information to show. Available: 'all', 'application', 'service', 'platform', and 'unknown'. Excludes unknown sources unless 'all' or 'unknown' is selected, or `--guid` is used. To receive information on platform or unknown source id's, you must have the doppler.firehose, or logs.admin scope.", + "-sort-by": "Sort by specified column. Available: 'source-id', 'source', 'source-type', 'count', 'expired', 'cache-duration', and 'rate'.", + "-noise": "Fetch and display the rate of envelopes per minute for the last minute. WARNING: This is slow...", + "-guid": "Display raw source GUIDs with no source Names. Incompatible with 'source' and 'source-type' for --sort-by. Only allows 'platform' for --source-type", + }, + }, + }, + { + Name: "query", + HelpText: "Issues a PromQL query against Log Cache", + UsageDetails: plugin.Usage{ + Usage: `query [options] + +ENVIRONMENT VARIABLES: + LOG_CACHE_ADDR Overrides the default location of log-cache. + LOG_CACHE_SKIP_AUTH Set to 'true' to disable CF authentication.`, + Options: map[string]string{ + "-time": "Effective time for query execution of an instant query. Cannont be used with --start, --end, or --step. Can be a unix timestamp or RFC3339.", + "-start": "Start time for a range query. Cannont be used with --time. Can be a unix timestamp or RFC3339.", + "-end": "End time for a range query. Cannont be used with --time. Can be a unix timestamp or RFC3339.", + "-step": "Step interval for a range query. Cannot be used with --time.", + }, + }, + }, + }, + } +} diff --git a/main.go b/main.go index ab7394a1..69a657a9 100644 --- a/main.go +++ b/main.go @@ -1,139 +1,14 @@ package main import ( - "context" - "crypto/tls" - "log" - "net/http" - "os" - "strconv" - "strings" - "code.cloudfoundry.org/cli/plugin" - "code.cloudfoundry.org/log-cache-cli/v4/internal/command" - "golang.org/x/term" + "code.cloudfoundry.org/log-cache-cli/v4/internal/logcache" ) -// semver version is set via ldflags at compile time +// version is expected to be set via ldflags at compile time to a +// `MAJOR.MINOR.BUILD` version string, e.g. `"1.2.3"`, `"4.0.0`. var version string -type LogCacheCLI struct{} - -func (c *LogCacheCLI) Run(conn plugin.CliConnection, args []string) { - isTerminal := term.IsTerminal(int(os.Stdout.Fd())) - - skipSSL, err := conn.IsSSLDisabled() - if err != nil { - log.Fatal(err) - } - http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{ - InsecureSkipVerify: skipSSL, //nolint:gosec - } - - l := log.New(os.Stderr, "", 0) - - switch args[0] { - case "query": - var opts []command.QueryOption - command.Query(conn, args[1:], http.DefaultClient, l, os.Stdout, opts...) - case "tail": - var opts []command.TailOption - if !isTerminal { - opts = append(opts, command.WithTailNoHeaders()) - } - command.Tail(context.Background(), conn, args[1:], http.DefaultClient, l, os.Stdout, opts...) - case "log-meta": - var opts []command.MetaOption - if !isTerminal { - opts = append(opts, command.WithMetaNoHeaders()) - } - command.Meta(conn, args[1:], http.DefaultClient, l, os.Stdout, opts...) - } -} - -func (c *LogCacheCLI) GetMetadata() plugin.PluginMetadata { - // ignore any errors and use the default plugin.VersionType if version - // cannot be parsed - split := strings.Split(version, ".") - v := plugin.VersionType{} - if len(split) == 3 { - v.Major = readOrZero(split[0]) - v.Minor = readOrZero(split[1]) - v.Build = readOrZero(split[2]) - } - - return plugin.PluginMetadata{ - Name: "log-cache", - Version: v, - Commands: []plugin.Command{ - { - Name: "tail", - HelpText: "Output logs for a source-id/app", - UsageDetails: plugin.Usage{ - Usage: `tail [options] - -ENVIRONMENT VARIABLES: - LOG_CACHE_ADDR Overrides the default location of log-cache. - LOG_CACHE_SKIP_AUTH Set to 'true' to disable CF authentication.`, - Options: map[string]string{ - "-start-time": "Start of query range in UNIX nanoseconds.", - "-end-time": "End of query range in UNIX nanoseconds.", - "-envelope-type, -t": "Envelope type filter. Available filters: 'log', 'counter', 'gauge', 'timer', 'event', and 'any'.", - "-envelope-class, -c": "Envelope class filter. Available filters: 'logs', 'metrics', and 'any'.", - "-follow, -f": "Output appended to stdout as logs are egressed.", - "-json": "Output envelopes in JSON format.", - "-lines, -n": "Number of envelopes to return. Default is 10.", - "-new-line": "Character used for new line substition, must be single unicode character. Default is '\\n'.", - "-name-filter": "Filters metrics by name.", - }, - }, - }, - { - Name: "log-meta", - HelpText: "Show all available meta information", - UsageDetails: plugin.Usage{ - Usage: `log-meta [options] - -ENVIRONMENT VARIABLES: - LOG_CACHE_ADDR Overrides the default location of log-cache. - LOG_CACHE_SKIP_AUTH Set to 'true' to disable CF authentication.`, - Options: map[string]string{ - "-source-type": "Source type of information to show. Available: 'all', 'application', 'service', 'platform', and 'unknown'. Excludes unknown sources unless 'all' or 'unknown' is selected, or `--guid` is used. To receive information on platform or unknown source id's, you must have the doppler.firehose, or logs.admin scope.", - "-sort-by": "Sort by specified column. Available: 'source-id', 'source', 'source-type', 'count', 'expired', 'cache-duration', and 'rate'.", - "-noise": "Fetch and display the rate of envelopes per minute for the last minute. WARNING: This is slow...", - "-guid": "Display raw source GUIDs with no source Names. Incompatible with 'source' and 'source-type' for --sort-by. Only allows 'platform' for --source-type", - }, - }, - }, - { - Name: "query", - HelpText: "Issues a PromQL query against Log Cache", - UsageDetails: plugin.Usage{ - Usage: `query [options] - -ENVIRONMENT VARIABLES: - LOG_CACHE_ADDR Overrides the default location of log-cache. - LOG_CACHE_SKIP_AUTH Set to 'true' to disable CF authentication.`, - Options: map[string]string{ - "-time": "Effective time for query execution of an instant query. Cannont be used with --start, --end, or --step. Can be a unix timestamp or RFC3339.", - "-start": "Start time for a range query. Cannont be used with --time. Can be a unix timestamp or RFC3339.", - "-end": "End time for a range query. Cannont be used with --time. Can be a unix timestamp or RFC3339.", - "-step": "Step interval for a range query. Cannot be used with --time.", - }, - }, - }, - }, - } -} - -func readOrZero(s string) int { - n, err := strconv.Atoi(s) - if err != nil { - return 0 - } - return n -} - func main() { - plugin.Start(&LogCacheCLI{}) + plugin.Start(logcache.New(versionType())) } diff --git a/version.go b/version.go new file mode 100644 index 00000000..4a095b88 --- /dev/null +++ b/version.go @@ -0,0 +1,37 @@ +package main + +import ( + "strconv" + "strings" + + "code.cloudfoundry.org/cli/plugin" +) + +// versionType parses version into a plugin.VersionType. If version cannot be +// parsed correctly, then the default plugin.VersionType is returned, which +// results in the plugin being marked as "dev". +func versionType() plugin.VersionType { + s := strings.Split(version, ".") + if len(s) != 3 { + return plugin.VersionType{} + } + + var ( + err error + vt plugin.VersionType + ) + vt.Major, err = strconv.Atoi(s[0]) + if err != nil { + return plugin.VersionType{} + } + vt.Minor, err = strconv.Atoi(s[1]) + if err != nil { + return plugin.VersionType{} + } + vt.Build, err = strconv.Atoi(s[2]) + if err != nil { + return plugin.VersionType{} + } + + return vt +}