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: retrieve multiple service logs stream at once via cli #2426

Merged
merged 4 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func NewHistoricalServiceIdentifierArgWithValidationDisabled(
return &args.ArgConfig{
Key: serviceIdentifierArgKey,
IsOptional: isOptional,
DefaultValue: "",
DefaultValue: []string{},
IsGreedy: isGreedy,
ArgCompletionProvider: args.NewManualCompletionsProvider(getCompletionsForExistingAndHistoricalServices(enclaveIdentifierArgKey)),
ValidationFunc: noValidationFunc,
Expand Down
1 change: 1 addition & 0 deletions cli/cli/command_framework/lowlevel/args/consts_for_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var validArgsConfig = []*ArgConfig{
IsGreedy: true,
},
}

var validTokens = []string{
arg1Value,
arg2Value,
Expand Down
84 changes: 68 additions & 16 deletions cli/cli/commands/service/logs/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package logs
import (
"context"
"fmt"
"github.com/fatih/color"
"github.com/kurtosis-tech/kurtosis/api/golang/core/lib/services"
"github.com/kurtosis-tech/kurtosis/api/golang/engine/kurtosis_engine_rpc_api_bindings"
"github.com/kurtosis-tech/kurtosis/api/golang/engine/lib/kurtosis_context"
Expand All @@ -34,10 +35,12 @@ const (
isEnclaveIdArgGreedy = false

serviceIdentifierArgKey = "service"
isServiceIdentifierArgOptional = false
isServiceIdentifierArgGreedy = false
isServiceIdentifierArgOptional = true // don't need to pass this in if they use the return all services flag
isServiceIdentifierArgGreedy = true

shouldFollowLogsFlagKey = "follow"
returnAllServiceLogs = "all-services"
allServicesWildcard = "*"
tedim52 marked this conversation as resolved.
Show resolved Hide resolved
returnNumLogsFlagKey = "num"
returnAllLogsFlagKey = "all"
matchTextFilterFlagKey = "match"
Expand All @@ -55,12 +58,25 @@ const (
commonInstructionInMatchFlags = "Important: " + matchTextFilterFlagKey + " and " + matchRegexFilterFlagKey + " flags cannot be used at the same time. You should either use one or the other."
)

type ColorPrinter func(a ...interface{}) string

var colorList = []ColorPrinter{
color.New(color.FgBlue).SprintFunc(),
color.New(color.FgCyan).SprintFunc(),
color.New(color.FgGreen).SprintFunc(),
color.New(color.FgMagenta).SprintFunc(),
color.New(color.FgYellow).SprintFunc(),
color.New(color.FgHiRed).SprintFunc(),
color.New(color.FgHiBlue).SprintFunc(),
color.New(color.FgHiWhite).SprintFunc(),
}

var doNotFilterLogLines *kurtosis_context.LogLineFilter = nil

var defaultShouldFollowLogs = strconv.FormatBool(false)
var defaultInvertMatchFilterFlagValue = strconv.FormatBool(false)

var defaultShouldReturnAllLogs = strconv.FormatBool(false)
var defaultShouldReturnAllServiceLog = strconv.FormatBool(false)
var defaultNumLogLinesFlagValue = strconv.Itoa(defaultNumLogLines)

var ServiceLogsCmd = &engine_consuming_kurtosis_command.EngineConsumingKurtosisCommand{
Expand Down Expand Up @@ -121,6 +137,13 @@ var ServiceLogsCmd = &engine_consuming_kurtosis_command.EngineConsumingKurtosisC
Type: flags.FlagType_Bool,
Default: defaultInvertMatchFilterFlagValue,
},
{
Key: returnAllServiceLogs,
Usage: "Returns service log streams for all logs in an enclave",
Shorthand: "x",
Type: flags.FlagType_Bool,
Default: defaultShouldReturnAllServiceLog,
},
},
Args: []*args.ArgConfig{
enclave_id_arg.NewHistoricalEnclaveIdentifiersArgWithValidationDisabled(
Expand All @@ -131,8 +154,8 @@ var ServiceLogsCmd = &engine_consuming_kurtosis_command.EngineConsumingKurtosisC
service_identifier_arg.NewHistoricalServiceIdentifierArgWithValidationDisabled(
serviceIdentifierArgKey,
enclaveIdentifierArgKey,
isServiceIdentifierArgGreedy,
isServiceIdentifierArgOptional,
isServiceIdentifierArgGreedy,
),
},
RunFunc: run,
Expand All @@ -151,10 +174,20 @@ func run(
return stacktrace.Propagate(err, "An error occurred getting the enclave identifier using arg key '%v'", enclaveIdentifierArgKey)
}

serviceIdentifier, err := args.GetNonGreedyArg(serviceIdentifierArgKey)
shouldReturnAllServiceLogs, err := flags.GetBool(returnAllServiceLogs)
if err != nil {
return stacktrace.Propagate(err, "An error occurred getting the 'all-services' flag using key '%v'", returnAllServiceLogs)
}

var serviceIdentifiers []string
serviceIdentifiers, err = args.GetGreedyArg(serviceIdentifierArgKey)
if err != nil {
return stacktrace.Propagate(err, "An error occurred getting the service identifier using arg key '%v'", serviceIdentifierArgKey)
}
// if no service identifiers were passed or just the wildcard was passed, default to returning all
if len(serviceIdentifiers) == 0 || (len(serviceIdentifiers) == 1 && serviceIdentifiers[0] == allServicesWildcard) { //
shouldReturnAllServiceLogs = true
}

shouldFollowLogs, err := flags.GetBool(shouldFollowLogsFlagKey)
if err != nil {
Expand Down Expand Up @@ -191,10 +224,27 @@ func run(
return stacktrace.Propagate(err, "An error occurred connecting to the local Kurtosis engine")
}

serviceUuid := getEnclaveAndServiceUuidForIdentifiers(kurtosisCtx, ctx, enclaveIdentifier, serviceIdentifier)
if shouldReturnAllServiceLogs {
enclaveCtx, err := kurtosisCtx.GetEnclaveContext(ctx, enclaveIdentifier)
if err != nil {
return stacktrace.Propagate(err, "An error occurred retrieving enclave context for '%v'", enclaveIdentifier)
}

userServiceUuids := map[services.ServiceUUID]bool{
serviceUuid: true,
allServiceIdentifiers, err := enclaveCtx.GetExistingAndHistoricalServiceIdentifiers(ctx)
if err != nil {
return stacktrace.Propagate(err, "An error occurred retrieving service identifiers for enclave '%v'", enclaveIdentifier)
}
serviceIdentifiers = allServiceIdentifiers.GetOrderedListOfNames()
}

userServiceUuids := map[services.ServiceUUID]bool{}
serviceUuids := map[services.ServiceUUID]string{}
serviceColorPrinterMap := map[string]ColorPrinter{}
for idx, serviceIdentifier := range serviceIdentifiers {
serviceUuid := getEnclaveAndServiceUuidForIdentifiers(kurtosisCtx, ctx, enclaveIdentifier, serviceIdentifier)
serviceUuids[serviceUuid] = serviceIdentifier
serviceColorPrinterMap[serviceIdentifier] = colorList[idx%len(colorList)]
userServiceUuids[serviceUuid] = true
}

logLineFilter, err := getLogLineFilterFromFilterFlagValues(matchTextStr, matchRegexStr, invertMatch)
Expand Down Expand Up @@ -226,14 +276,16 @@ func run(
}

userServiceLogsByUuid := serviceLogsStreamContent.GetServiceLogsByServiceUuids()

userServiceLogs, found := userServiceLogsByUuid[serviceUuid]
if !found {
return stacktrace.NewError("Expected to find logs for user service with UUID '%v' on user service logs map '%+v' but was not found; this should never happen, and is a bug in Kurtosis", serviceUuid, userServiceLogsByUuid)
}

for _, serviceLog := range userServiceLogs {
out.PrintOutLn(serviceLog.GetContent())
for serviceUuid, serviceIdentifier := range serviceUuids {
userServiceLogs, found := userServiceLogsByUuid[serviceUuid]
if !found {
return stacktrace.NewError("Expected to find logs for user service with UUID '%v' on user service logs map '%+v' but was not found; this should never happen, and is a bug in Kurtosis", serviceUuid, userServiceLogsByUuid)
}

for _, serviceLog := range userServiceLogs {
colorPrinter := serviceColorPrinterMap[serviceIdentifier]
out.PrintOutLn(fmt.Sprintf("%v %v", colorPrinter("[%v]", serviceIdentifier), serviceLog.GetContent()))
}
}
case <-interruptChan:
logrus.Debugf("Received signal interruption in service logs Kurtosis CLI command")
Expand Down
9 changes: 5 additions & 4 deletions docs/docs/cli-reference/service-logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ sidebar_label: service logs
slug: /service-logs
---

To print the logs for a service, run:
To print the logs for services in an enclave, run:


```bash
kurtosis service logs $THE_ENCLAVE_IDENTIFIER $THE_SERVICE_IDENTIFIER
kurtosis service logs $THE_ENCLAVE_IDENTIFIER $THE_SERVICE_IDENTIFIER1 $THE_SERVICE_IDENTIFIER2 $THE_SERVICE_IDENTIFIER3
```
where `$THE_ENCLAVE_IDENTIFIER` and the `$THE_SERVICE_IDENTIFIER` are [resource identifiers](../advanced-concepts/resource-identifier.md) for the enclave and service, respectively. The service identifier (name or UUID) is printed upon inspecting an enclave.
where `$THE_ENCLAVE_IDENTIFIER` and the `$THE_SERVICE_IDENTIFIER` are [resource identifiers](../advanced-concepts/resource-identifier.md) for the enclave and services, respectively. The service identifier (name or UUID) is printed upon inspecting an enclave.
:::

:::note Number of log lines
Expand All @@ -23,7 +23,8 @@ Kurtosis will keep logs for up to 4 weeks before removing them to prevent logs f
The following optional arguments can be used:
1. `-a`, `--all` can be used to retrieve all logs.
1. `-n`, `--num=uint32` can be used to retrieve X last log lines. (eg. `-n 10` will retrieve last 10 log lines, similar to `tail -n 10`)
1. `-f`, `-follow` can be added to continue following the logs, similar to `tail -f`.
1. `-f`, `--follow` can be added to continue following the logs, similar to `tail -f`.
1. `-x`, `--all-services` can be used to retrieve logs for all services in an enclave. Another option is to pass in the escaped wildcard operator like so `kurtosis service logs enclave-name '*'`
1. `--match=text` can be used for filtering the log lines containing the text.
1. `--regex-match="regex"` can be used for filtering the log lines containing the regex. This filter will also work for text but will have degraded performance.
1. `-v`, `--invert-match` can be used to invert the filter condition specified by either `--match` or `--regex-match`. Log lines NOT containing the match will be returned.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,6 @@ func (service *EngineConnectServerService) Clean(ctx context.Context, connectArg
}

func (service *EngineConnectServerService) GetServiceLogs(ctx context.Context, connectArgs *connect.Request[kurtosis_engine_rpc_api_bindings.GetServiceLogsArgs], stream *connect.ServerStream[kurtosis_engine_rpc_api_bindings.GetServiceLogsResponse]) error {

args := connectArgs.Msg
enclaveIdentifier := args.GetEnclaveIdentifier()
enclaveUuid, err := service.enclaveManager.GetEnclaveUuidForEnclaveIdentifier(context.Background(), enclaveIdentifier)
Expand Down
Loading