Skip to content

Commit

Permalink
refactor(logs): Use native TailLogs SDK method
Browse files Browse the repository at this point in the history
This commit reworks the tailing of kraftcloud vm instances logs to
use the now native KraftCloud Go SDK method for tailing logs, aptly
`TailLogs`.

Signed-off-by: Alexander Jung <[email protected]>
  • Loading branch information
nderjung committed Apr 10, 2024
1 parent 1f3487e commit b0a4997
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 133 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ require (
k8s.io/apimachinery v0.29.3
k8s.io/apiserver v0.29.3
oras.land/oras-go/v2 v2.5.0
sdk.kraft.cloud v0.5.5-0.20240408130935-44faa2c974b3
sdk.kraft.cloud v0.5.5-0.20240410102038-8d0f0333b17a
sigs.k8s.io/kustomize/kyaml v0.14.3
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1677,8 +1677,8 @@ oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZH
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sdk.kraft.cloud v0.5.5-0.20240408130935-44faa2c974b3 h1:WNGjGRijO9vHa2DOVqOAJXqL+RBhsdkQAG/Jb9JmQnk=
sdk.kraft.cloud v0.5.5-0.20240408130935-44faa2c974b3/go.mod h1:u88mmv6PoEASnMLNkyYgrMCzJ4tkMGurV8ZMvXA9a2I=
sdk.kraft.cloud v0.5.5-0.20240410102038-8d0f0333b17a h1:23i4O5zQRjwqpFslVVdgcR3Kj42Qw7XGfGHPbufoqFs=
sdk.kraft.cloud v0.5.5-0.20240410102038-8d0f0333b17a/go.mod h1:u88mmv6PoEASnMLNkyYgrMCzJ4tkMGurV8ZMvXA9a2I=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I=
Expand Down
143 changes: 13 additions & 130 deletions internal/cli/kraft/cloud/instance/logs/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,18 @@ package logs

import (
"context"
"encoding/base64"
"errors"
"fmt"
"strings"
"time"

"github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"

kraftcloud "sdk.kraft.cloud"
kcinstances "sdk.kraft.cloud/instances"

"kraftkit.sh/cmdfactory"
"kraftkit.sh/config"
"kraftkit.sh/internal/cli/kraft/cloud/utils"
"kraftkit.sh/iostreams"
"kraftkit.sh/log"
)

const (
defaultPageSize = 4096
maxPageSize = defaultPageSize*4 - 1
maxPossibleBytes = 1024 * 1024 * 1024
)

type LogOptions struct {
Expand Down Expand Up @@ -91,37 +80,13 @@ func (opts *LogOptions) Pre(cmd *cobra.Command, _ []string) error {
}

if opts.Tail < -1 {
return fmt.Errorf("invalid value for --tail: %d, should be -1, or positive", opts.Tail)
}

if opts.Follow && opts.Tail == -1 {
opts.Tail = 100
return fmt.Errorf("invalid value for --tail: %d, should be -1 for all logs, or positive for length of truncated logs", opts.Tail)
}

return nil
}

func (opts *LogOptions) logsFetchDecode(ctx context.Context, client kcinstances.InstancesService, image string, offset, limit int) ([]byte, *kcinstances.LogResponseItem, error) {
logResp, err := client.WithMetro(opts.metro).Log(ctx, image, offset, limit)
if err != nil {
return nil, nil, fmt.Errorf("could not retrieve logs: %w", err)
}
log, err := logResp.FirstOrErr()
if err != nil {
return nil, nil, fmt.Errorf("could not retrieve logs: %w", err)
}

outputPart, err := base64.StdEncoding.DecodeString(log.Output)
if err != nil {
return nil, nil, fmt.Errorf("decoding base64 console output: %w", err)
}

return outputPart, log, nil
}

func (opts *LogOptions) Run(ctx context.Context, args []string) error {
var offset, limit int

auth, err := config.GetKraftCloudAuthConfig(ctx, opts.token)
if err != nil {
return fmt.Errorf("could not retrieve credentials: %w", err)
Expand All @@ -131,103 +96,21 @@ func (opts *LogOptions) Run(ctx context.Context, args []string) error {
kraftcloud.WithToken(config.GetKraftCloudTokenAuthConfig(*auth)),
)

if opts.Follow {
offset = -defaultPageSize
limit = maxPageSize

for {
output, resp, err := opts.logsFetchDecode(ctx, client, args[0], offset, limit)
if err != nil {
if errors.Is(err, context.Canceled) {
return nil
}
return err
}

// Split the output by line and print each line separately to
// be able to limit the output to the last N lines.
// Truncate the last line if it's not a full line.
if len(output) > 0 {
split := strings.Split(string(output), "\n")
linesToSkip := len(split) - opts.Tail
for i, line := range split {
if i < linesToSkip {
continue
}

if i == len(split)-1 && output[len(output)-1] != '\n' {
offset = resp.Range.End - len(line)
} else {
if i == len(split)-1 {
offset = resp.Range.End
}
fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", line)
}
}
}

time.Sleep(500 * time.Millisecond)
}
logChan, errChan, err := client.TailLogs(ctx, args[0], opts.Follow, opts.Tail, 500*time.Millisecond)
if err != nil {
return fmt.Errorf("initializing log tailing: %w", err)
}

var output []byte
if opts.Tail >= 0 {
lines := 0
for i := 1; lines < opts.Tail; i++ {
offset = i * -defaultPageSize
limit = defaultPageSize

outputPart, resp, err := opts.logsFetchDecode(ctx, client, args[0], offset, limit)
if err != nil {
return err
}

outputPart = append(outputPart, output...)
output = outputPart

if resp.Range.Start == resp.Available.Start {
break
for {
select {
case <-ctx.Done():
return nil
case err := <-errChan:
return err
case line, ok := <-logChan:
if ok {
fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", line)
}

lines += strings.Count(string(outputPart), "\n")
}

split := strings.Split(string(output), "\n")
start := len(split) - opts.Tail
if start < 0 {
start = 0
}
for i := start; i < len(split); i++ {
fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", split[i])
}
} else {
// The same as above, but fetch the max possible amount of logs.
// Stop only when there are no more logs to fetch.
for i := 4; ; i = i + 4 {
offset = i * -defaultPageSize
limit = maxPageSize

outputPart, resp, err := opts.logsFetchDecode(ctx, client, args[0], offset, limit)
if err != nil {
return err
}

outputPart = append(outputPart, output...)
output = outputPart

if resp.Range.Start == resp.Available.Start {
break
}

if len(output) > maxPossibleBytes {
log.G(ctx).Warnf("The maximum amount of logs has been reached. Stopping.")
fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", output)
break
}
}

fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", output)
}

return nil
}

0 comments on commit b0a4997

Please sign in to comment.