Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Modernize as a cf CLI plugin #66

Closed
wants to merge 12 commits into from
26 changes: 22 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
log-cache-cli
cf-lc-plugin
*.test
main
# Builds
bin

# IntelliJ
.idea/

# macOS
.DS_Store

# Vim files
[._]*.s[a-v][a-z]
!*.svg # comment out if you don't need vector files
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
Session.vim
Sessionx.vim
.netrwhist
*~
tags
[._]*.un~
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ NAME:
tail - Output logs for a source-id/app

USAGE:
tail [options] <source-id/app>
tail [options] SOURCE_ID

ENVIRONMENT VARIABLES:
LOG_CACHE_ADDR Overrides the default location of log-cache.
Expand Down Expand Up @@ -94,14 +94,14 @@ NAME:
query - Issues a PromQL query against Log Cache

USAGE:
query <promql-query> [options]
query PROMQL_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:
--end End time for a range query. Cannont be used with --time. Can be a unix timestamp or RFC3339.
--end End time for a range query. Cannot be used with --time. 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.
--step Step interval for a range query. Cannot be used with --time.
--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.
Expand Down
1 change: 0 additions & 1 deletion cmd/cf-lc-plugin/.gitignore

This file was deleted.

13 changes: 0 additions & 13 deletions cmd/cf-lc-plugin/cf_log_cache_plugin_suite_test.go

This file was deleted.

65 changes: 65 additions & 0 deletions internal/command/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package command

import (
"net/http"
"os"
"strings"

"code.cloudfoundry.org/cli/plugin"
logcache "code.cloudfoundry.org/go-log-cache"
)

// Logger is used for outputting log-cache results and errors
type Logger interface {
Fatalf(format string, args ...interface{})
Printf(format string, args ...interface{})
}

// HTTPClient is the client used for HTTP requests
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}

type tokenHTTPClient struct {
c HTTPClient
tokenFunc func() string
}

func (c *tokenHTTPClient) Do(req *http.Request) (*http.Response, error) {
accessToken := c.tokenFunc()
if len(accessToken) > 0 {
req.Header.Set("Authorization", accessToken)
}

return c.c.Do(req)

}

func newLogCacheClient(c HTTPClient, log Logger, cli plugin.CliConnection) *logcache.Client {
addr := os.Getenv("LOG_CACHE_ADDR")
if addr == "" {
addrAPI, err := cli.ApiEndpoint()
if err != nil {
log.Fatalf("Could not determine Log Cache endpoint: %s", err)
}
addr = strings.Replace(addrAPI, "api", "log-cache", 1)
}

if strings.ToLower(os.Getenv("LOG_CACHE_SKIP_AUTH")) != "true" {
c = &tokenHTTPClient{
c: c,
tokenFunc: func() string {
token, err := cli.AccessToken()
if err != nil {
log.Fatalf("Unable to get Access Token: %s", err)
}
return token
},
}
}

return logcache.NewClient(
addr,
logcache.WithHTTPClient(c),
)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cf_test
package command_test

import (
"errors"
Expand All @@ -9,7 +9,7 @@ import (
"sync"

"code.cloudfoundry.org/cli/plugin"
"code.cloudfoundry.org/cli/plugin/models"
plugin_models "code.cloudfoundry.org/cli/plugin/models"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

Expand Down Expand Up @@ -190,10 +190,3 @@ func (s *stubCliConnection) AccessToken() (string, error) {
s.accessTokenCount++
return s.accessToken, s.accessTokenErr
}

func (s *stubCliConnection) getAccessTokenCount() int {
s.Lock()
defer s.Unlock()

return s.accessTokenCount
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cf
package command

import (
"bytes"
Expand Down Expand Up @@ -122,7 +122,7 @@ func (f prettyFormatter) sourceHeader(sourceID, _, _, user string) (string, bool
}

func (f prettyFormatter) formatEnvelope(e *loggregator_v2.Envelope) (string, bool) {
return fmt.Sprintf("%s", envelopeWrapper{sourceID: f.sourceID, Envelope: e, newLine: f.newLine}), true
return envelopeWrapper{sourceID: f.sourceID, Envelope: e, newLine: f.newLine}.String(), true
}

type jsonFormatter struct {
Expand Down Expand Up @@ -251,7 +251,7 @@ func (e envelopeWrapper) String() string {
values = append(values, fmt.Sprintf("%s:%f %s", k, v.Value, v.Unit))
}

sort.Sort(sort.StringSlice(values))
sort.Strings(values)

return fmt.Sprintf("%sGAUGE %s",
e.header(ts),
Expand Down
85 changes: 10 additions & 75 deletions pkg/command/cf/meta.go → internal/command/meta.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
package cf
package command

import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"regexp"
"sort"
"strconv"
"strings"
"text/tabwriter"
"time"

"code.cloudfoundry.org/cli/plugin"
logcache "code.cloudfoundry.org/go-log-cache"
logcache_v1 "code.cloudfoundry.org/go-log-cache/rpc/logcache_v1"
flags "github.com/jessevdk/go-flags"
)
Expand Down Expand Up @@ -106,7 +103,6 @@ func WithMetaNoiseSleepDuration(d time.Duration) MetaOption {

// Meta returns the metadata from Log Cache
func Meta(
ctx context.Context,
cli plugin.CliConnection,
args []string,
c HTTPClient,
Expand All @@ -115,7 +111,7 @@ func Meta(
mopts ...MetaOption,
) {
opts := getOptions(args, log, mopts...)
client := createLogCacheClient(c, log, cli)
client := newLogCacheClient(c, log, cli)
tw := tabwriter.NewWriter(tableWriter, 0, 2, 2, ' ', 0)
username, err := cli.Username()
if err != nil {
Expand All @@ -125,7 +121,7 @@ func Meta(
var originalMeta map[string]*logcache_v1.MetaInfo
var currentMeta map[string]*logcache_v1.MetaInfo
writeRetrievingMetaHeader(opts, tw, username)
currentMeta, err = client.Meta(ctx)
currentMeta, err = client.Meta(context.Background())
if err != nil {
log.Fatalf("Failed to read Meta information: %s", err)
}
Expand All @@ -135,7 +131,7 @@ func Meta(
writeWaiting(opts, tw, username)
time.Sleep(opts.metaNoiseSleepDuration)
writeRetrievingMetaHeader(opts, tw, username)
currentMeta, err = client.Meta(ctx)
currentMeta, err = client.Meta(context.Background())
if err != nil {
log.Fatalf("Failed to read Meta information: %s", err)
}
Expand Down Expand Up @@ -227,31 +223,6 @@ type displayRow struct {
Delta int64
}

func createLogCacheClient(c HTTPClient, log Logger, cli plugin.CliConnection) *logcache.Client {
logCacheEndpoint, err := logCacheEndpoint(cli)
if err != nil {
log.Fatalf("Could not determine Log Cache endpoint: %s", err)
}

if strings.ToLower(os.Getenv("LOG_CACHE_SKIP_AUTH")) != "true" {
c = &tokenHTTPClient{
c: c,
tokenFunc: func() string {
token, err := cli.AccessToken()
if err != nil {
log.Fatalf("Unable to get Access Token: %s", err)
}
return token
},
}
}

return logcache.NewClient(
logCacheEndpoint,
logcache.WithHTTPClient(c),
)
}

func tableFormat(opts optionsFlags, row displayRow) (string, []interface{}) {
tableFormat := "%d\t%d\t%s\n"
items := []interface{}{interface{}(row.Count), interface{}(row.Expired), interface{}(row.CacheDuration)}
Expand All @@ -274,19 +245,21 @@ func tableFormat(opts optionsFlags, row displayRow) (string, []interface{}) {

func writeRetrievingMetaHeader(opts optionsFlags, tableWriter io.Writer, username string) {
if opts.withHeaders {
fmt.Fprintf(tableWriter, fmt.Sprintf(
fmt.Fprintf(
tableWriter,
"Retrieving log cache metadata as %s...\n\n",
username,
))
)
}
}

func writeAppsAndServicesHeader(opts optionsFlags, tableWriter io.Writer, username string) {
if opts.withHeaders {
fmt.Fprintf(tableWriter, fmt.Sprintf(
fmt.Fprintf(
tableWriter,
"Retrieving app and service names as %s...\n\n",
username,
))
)
}
}

Expand Down Expand Up @@ -375,18 +348,6 @@ func getOptions(args []string, log Logger, mopts ...MetaOption) optionsFlags {
return opts
}

func displayRate(rate int) string {
var output string

if rate >= MaximumBatchSize {
output = fmt.Sprintf(">%d", MaximumBatchSize-1)
} else {
output = strconv.Itoa(rate)
}

return output
}

func sortRows(opts optionsFlags, rows []displayRow) {
switch opts.SortBy {
case string(sortBySourceID):
Expand Down Expand Up @@ -530,32 +491,6 @@ func maxDuration(a, b time.Duration) time.Duration {
return a
}

func truncate(count int, entries map[string]*logcache_v1.MetaInfo) map[string]*logcache_v1.MetaInfo {
truncated := make(map[string]*logcache_v1.MetaInfo)
for k, v := range entries {
if len(truncated) >= count {
break
}
truncated[k] = v
}
return truncated
}

func logCacheEndpoint(cli plugin.CliConnection) (string, error) {
logCacheAddr := os.Getenv("LOG_CACHE_ADDR")

if logCacheAddr != "" {
return logCacheAddr, nil
}

apiEndpoint, err := cli.ApiEndpoint()
if err != nil {
return "", err
}

return strings.Replace(apiEndpoint, "api", "log-cache", 1), nil
}

func invalidSourceType(st string) bool {
validSourceTypes := []sourceType{
sourceTypePlatform,
Expand Down
Loading