diff --git a/pkg/kubernetes/pods.go b/pkg/kubernetes/pods.go index f36f1bee..b053cd09 100644 --- a/pkg/kubernetes/pods.go +++ b/pkg/kubernetes/pods.go @@ -1,11 +1,14 @@ package kubernetes import ( + "bufio" "bytes" "context" "errors" "fmt" + "strings" + "github.com/containers/kubernetes-mcp-server/pkg/version" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -18,9 +21,6 @@ import ( "k8s.io/client-go/tools/remotecommand" "k8s.io/metrics/pkg/apis/metrics" metricsv1beta1api "k8s.io/metrics/pkg/apis/metrics/v1beta1" - "k8s.io/utils/ptr" - - "github.com/containers/kubernetes-mcp-server/pkg/version" ) // DefaultTailLines is the default number of lines to retrieve from the end of the logs @@ -94,7 +94,7 @@ func (k *Kubernetes) PodsDelete(ctx context.Context, namespace, name string) (st k.ResourcesDelete(ctx, &schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}, namespace, name) } -func (k *Kubernetes) PodsLog(ctx context.Context, namespace, name, container string, previous bool, tail int64) (string, error) { +func (k *Kubernetes) PodsLog(ctx context.Context, namespace, name, container string, previous bool, tail int64, query string) (string, error) { pods := k.AccessControlClientset().CoreV1().Pods(k.NamespaceOrDefault(namespace)) logOptions := &v1.PodLogOptions{ @@ -102,24 +102,28 @@ func (k *Kubernetes) PodsLog(ctx context.Context, namespace, name, container str Previous: previous, } - // Only set tailLines if a value is provided (non-zero) - if tail > 0 { - logOptions.TailLines = &tail - } else { - // Default to DefaultTailLines lines when not specified - logOptions.TailLines = ptr.To(DefaultTailLines) + req := pods.GetLogs(name, logOptions) + stream, err := req.Stream(ctx) + if err != nil { + return "", errors.New("failed to open get Log stream") } + defer stream.Close() - req := pods.GetLogs(name, logOptions) - res := req.Do(ctx) - if res.Error() != nil { - return "", res.Error() + logData := make([]string, 0) + scanner := bufio.NewScanner(stream) + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, query) { + logData = append(logData, line) + } } - rawData, err := res.Raw() - if err != nil { - return "", err + + rows := int64(len(logData)) + if rows >= tail { + logData = logData[rows-tail : rows] } - return string(rawData), nil + result := strings.Join(logData, "\n") + return result, nil } func (k *Kubernetes) PodsRun(ctx context.Context, namespace, name, image string, port int32) ([]*unstructured.Unstructured, error) { diff --git a/pkg/toolsets/core/pods.go b/pkg/toolsets/core/pods.go index f1988686..7634a6f3 100644 --- a/pkg/toolsets/core/pods.go +++ b/pkg/toolsets/core/pods.go @@ -205,8 +205,12 @@ func initPods() []api.ServerTool { Type: "boolean", Description: "Return previous terminated container logs (Optional)", }, + "query": { + Type: "string", + Description: "filter logs by query", + }, }, - Required: []string{"name"}, + Required: []string{"name", "query"}, }, Annotations: api.ToolAnnotations{ Title: "Pods: Log", @@ -404,7 +408,13 @@ func podsLog(params api.ToolHandlerParams) (*api.ToolCallResult, error) { } } - ret, err := params.PodsLog(params.Context, ns.(string), name.(string), container.(string), previousBool, tailInt) + query := params.GetArguments()["query"] + if query == nil { + query = "" + } + + ret, err := params.PodsLog(params.Context, ns.(string), name.(string), container.(string), previousBool, tailInt, + query.(string)) if err != nil { return api.NewToolCallResult("", fmt.Errorf("failed to get pod %s log in namespace %s: %v", name, ns, err)), nil } else if ret == "" {