Skip to content

Commit b91991b

Browse files
authored
Add Tail Option for Kubernetes Logs Query (#60)
It is now possible to specify a `tail` options when querying Kubernetes logs. This allows user to limit the results of a query to the last `n` lines of logs. By default the tail option is set to 0, which means no limit.
1 parent 993fa10 commit b91991b

File tree

7 files changed

+29
-12
lines changed

7 files changed

+29
-12
lines changed

pkg/kubernetes/client.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ type Client interface {
4343
GetNamespaces(ctx context.Context) (*data.Frame, error)
4444
GetResources(ctx context.Context, user string, groups []string, resourceId, namespace, parameterName, parameterValue string, wide bool) (*data.Frame, error)
4545
GetContainers(ctx context.Context, user string, groups []string, resourceId, namespace, name string) (*data.Frame, error)
46-
GetLogs(ctx context.Context, user string, groups []string, resourceId, namespace, name, container, filter string, timeRange backend.TimeRange) (*data.Frame, error)
46+
GetLogs(ctx context.Context, user string, groups []string, resourceId, namespace, name, container, filter string, tail int64, timeRange backend.TimeRange) (*data.Frame, error)
4747
GetResource(ctx context.Context, resourceId string) (*Resource, error)
4848
Proxy(user string, groups []string, requestUrl string, w http.ResponseWriter, r *http.Request)
4949
}
@@ -395,7 +395,7 @@ func (c *client) getPodsAndContainers(ctx context.Context, user string, groups [
395395
// The timeRange parameter is used to filter the log lines based on their
396396
// timestamp. Only log lines that are within the time range are included in the
397397
// data frame.
398-
func (c *client) GetLogs(ctx context.Context, user string, groups []string, resourceId, namespace, name, container, filter string, timeRange backend.TimeRange) (*data.Frame, error) {
398+
func (c *client) GetLogs(ctx context.Context, user string, groups []string, resourceId, namespace, name, container, filter string, tail int64, timeRange backend.TimeRange) (*data.Frame, error) {
399399
ctx, span := tracing.DefaultTracer().Start(ctx, "GetLogs")
400400
defer span.End()
401401
span.SetAttributes(attribute.Key("user").String(user))
@@ -425,11 +425,16 @@ func (c *client) GetLogs(ctx context.Context, user string, groups []string, reso
425425
go func(pod string) {
426426
defer streamsWG.Done()
427427

428-
stream, err := c.clientset.CoreV1().Pods(namespace).GetLogs(pod, &corev1.PodLogOptions{
428+
options := &corev1.PodLogOptions{
429429
Container: container,
430430
Timestamps: true,
431431
SinceTime: &metav1.Time{Time: timeRange.From},
432-
}).Stream(ctx)
432+
}
433+
if tail > 0 {
434+
options.TailLines = &tail
435+
}
436+
437+
stream, err := c.clientset.CoreV1().Pods(namespace).GetLogs(pod, options).Stream(ctx)
433438
if err != nil {
434439
span.RecordError(err)
435440
span.SetStatus(codes.Error, err.Error())

pkg/kubernetes/client_mock.go

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/kubernetes/client_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func TestGetLogs(t *testing.T) {
169169
require.NoError(t, err)
170170

171171
t.Run("should return logs", func(t *testing.T) {
172-
actualLogs, err := client.GetLogs(context.Background(), "", nil, "pod", "default", "echoserver", "echoserver", "", backend.TimeRange{From: time.Now().Add(-1 * time.Hour), To: time.Now().Add(1 * time.Hour)})
172+
actualLogs, err := client.GetLogs(context.Background(), "", nil, "pod", "default", "echoserver", "echoserver", "", 0, backend.TimeRange{From: time.Now().Add(-1 * time.Hour), To: time.Now().Add(1 * time.Hour)})
173173
require.NoError(t, err)
174174
require.Equal(t, "timestamp", actualLogs.Fields[0].Name)
175175
require.Equal(t, "body", actualLogs.Fields[1].Name)
@@ -187,7 +187,7 @@ func TestGetLogs(t *testing.T) {
187187
})
188188

189189
t.Run("should return filtered logs", func(t *testing.T) {
190-
actualLogs, err := client.GetLogs(context.Background(), "", nil, "pod", "default", "echoserver", "echoserver", "build", backend.TimeRange{From: time.Now().Add(-1 * time.Hour), To: time.Now().Add(1 * time.Hour)})
190+
actualLogs, err := client.GetLogs(context.Background(), "", nil, "pod", "default", "echoserver", "echoserver", "build", 0, backend.TimeRange{From: time.Now().Add(-1 * time.Hour), To: time.Now().Add(1 * time.Hour)})
191191
require.NoError(t, err)
192192
require.Equal(t, "timestamp", actualLogs.Fields[0].Name)
193193
require.Equal(t, "body", actualLogs.Fields[1].Name)

pkg/models/query.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type QueryModelKubernetesLogs struct {
3333
Name string `json:"name"`
3434
Container string `json:"container"`
3535
Filter string `json:"filter"`
36+
Tail int64 `json:"tail"`
3637
}
3738

3839
type QueryModelHelmReleases struct {

pkg/plugin/kubernetes.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,16 +233,17 @@ func (d *Datasource) handleKubernetesLogs(ctx context.Context, query concurrent.
233233
return backend.ErrorResponseWithErrorSource(err)
234234
}
235235

236-
d.logger.Info("handleKubernetesLogs query", "user", user, "groups", groups, "resourceId", qm.ResourceId, "namespace", qm.Namespace, "name", qm.Name, "container", qm.Container, "filter", qm.Filter)
236+
d.logger.Info("handleKubernetesLogs query", "user", user, "groups", groups, "resourceId", qm.ResourceId, "namespace", qm.Namespace, "name", qm.Name, "container", qm.Container, "filter", qm.Filter, "tail", qm.Tail)
237237
span.SetAttributes(attribute.Key("user").String(user))
238238
span.SetAttributes(attribute.Key("groups").StringSlice(groups))
239239
span.SetAttributes(attribute.Key("resourceId").String(qm.ResourceId))
240240
span.SetAttributes(attribute.Key("namespace").String(qm.Namespace))
241241
span.SetAttributes(attribute.Key("name").String(qm.Name))
242242
span.SetAttributes(attribute.Key("container").String(qm.Container))
243243
span.SetAttributes(attribute.Key("filter").String(qm.Filter))
244+
span.SetAttributes(attribute.Key("tail").Int64(qm.Tail))
244245

245-
frame, err := d.kubeClient.GetLogs(ctx, user, groups, qm.ResourceId, qm.Namespace, qm.Name, qm.Container, qm.Filter, query.DataQuery.TimeRange)
246+
frame, err := d.kubeClient.GetLogs(ctx, user, groups, qm.ResourceId, qm.Namespace, qm.Name, qm.Container, qm.Filter, qm.Tail, query.DataQuery.TimeRange)
246247
if err != nil {
247248
d.logger.Error("Failed to get logs", "error", err.Error())
248249
span.RecordError(err)

src/datasource/components/queryeditor/KubernetesLogs.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ export function KubernetesLogs({
7979
/>
8080
</InlineFieldRow>
8181
<InlineFieldRow>
82+
<InlineField label="Tail">
83+
<Input
84+
onChange={(event: ChangeEvent<HTMLInputElement>) => {
85+
onChange({ ...query, tail: parseInt(event.target.value, 10) });
86+
}}
87+
value={query.tail || 0}
88+
/>
89+
</InlineField>
8290
<InlineField label="Filter" grow={true}>
8391
<Input
8492
id="query-editor-filter"

src/datasource/types/query.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export const DEFAULT_QUERIES: Record<QueryType, Partial<Query>> = {
4444
name: '',
4545
container: '',
4646
filter: '',
47+
tail: 0,
4748
},
4849
'helm-releases': {
4950
namespace: 'default',
@@ -116,6 +117,7 @@ export interface QueryModelKubernetesLogs {
116117
name?: string;
117118
container?: string;
118119
filter?: string;
120+
tail?: number;
119121
}
120122

121123
export interface QueryModelHelmReleases {

0 commit comments

Comments
 (0)