diff --git a/api/log/output.go b/api/log/output.go index 61013d0..b135577 100644 --- a/api/log/output.go +++ b/api/log/output.go @@ -11,8 +11,9 @@ import ( ) type filteredOutput struct { - out output.LogOutput - labels map[string]struct{} + out output.LogOutput + labels map[string]struct{} + lineCount int } func (o *filteredOutput) FormatAndPrintln(ts time.Time, lbls loghttp.LabelSet, maxLabelsLen int, line string) { @@ -22,14 +23,29 @@ func (o *filteredOutput) FormatAndPrintln(ts time.Time, lbls loghttp.LabelSet, m } } o.out.FormatAndPrintln(ts, lbls, maxLabelsLen, line) + o.lineCount++ } func (o filteredOutput) WithWriter(w io.Writer) output.LogOutput { return o.out.WithWriter(w) } -func NewStdOut(mode string, noLabels bool, labels ...string) (output.LogOutput, error) { - out, err := output.NewLogOutput(os.Stdout, mode, &output.LogOutputOptions{ +func (o filteredOutput) LineCount() int { + return o.lineCount +} + +type Output interface { + output.LogOutput + // LineCount returns the amount of lines the output has processed + LineCount() int +} + +func NewStdOut(mode string, noLabels bool, labels ...string) (Output, error) { + return NewOutput(os.Stdout, mode, noLabels, labels...) +} + +func NewOutput(w io.Writer, mode string, noLabels bool, labels ...string) (Output, error) { + out, err := output.NewLogOutput(w, mode, &output.LogOutputOptions{ NoLabels: noLabels, ColoredOutput: true, Timezone: time.Local, }) if err != nil { diff --git a/logs/logs.go b/logs/logs.go index 57d1c33..aaf36bb 100644 --- a/logs/logs.go +++ b/logs/logs.go @@ -7,7 +7,6 @@ import ( "time" "github.com/alecthomas/kong" - "github.com/grafana/loki/pkg/logcli/output" "github.com/grafana/loki/pkg/logproto" "github.com/ninech/nctl/api" "github.com/ninech/nctl/api/log" @@ -30,7 +29,7 @@ type logsCmd struct { To time.Time `help:"Ignore since flag and stop looking for logs at this absolute time (RFC3339)" placeholder:"2025-01-01T15:00:00+01:00"` Output string `help:"Configures the log output format. ${enum}" short:"o" enum:"default,json" default:"default"` NoLabels bool `help:"disable labels in log output"` - out output.LogOutput + out log.Output } var logRetention = time.Duration(time.Hour * 24 * 30) @@ -70,7 +69,14 @@ func (cmd *logsCmd) Run(ctx context.Context, client *api.Client, queryString str return client.Log.TailQuery(ctx, 0, out, query) } - return client.Log.QueryRange(ctx, out, query) + if err := client.Log.QueryRange(ctx, out, query); err != nil { + return err + } + if out.LineCount() == 0 { + return fmt.Errorf("no logs found between %s and %s", start.Format(time.RFC3339), end.Format(time.RFC3339)) + } + + return nil } type queryOperator string diff --git a/logs/logs_test.go b/logs/logs_test.go index bd1bd20..81f92c8 100644 --- a/logs/logs_test.go +++ b/logs/logs_test.go @@ -9,11 +9,9 @@ import ( "testing" "time" - "github.com/grafana/loki/pkg/logcli/output" apps "github.com/ninech/apis/apps/v1alpha1" "github.com/ninech/nctl/api" "github.com/ninech/nctl/api/log" - "github.com/ninech/nctl/internal/test" "github.com/stretchr/testify/assert" ) @@ -99,9 +97,7 @@ func TestRun(t *testing.T) { tc := tc t.Run(name, func(t *testing.T) { var buf bytes.Buffer - out, err := output.NewLogOutput(&buf, log.Mode(tc.cmd.Output), &output.LogOutputOptions{ - NoLabels: true, ColoredOutput: false, Timezone: time.Local, - }) + out, err := log.NewOutput(&buf, log.Mode(tc.cmd.Output), true) if err != nil { t.Fatal(err) } @@ -117,7 +113,7 @@ func TestRun(t *testing.T) { } if tc.expectedLines != 0 { - assert.Equal(t, test.CountLines(buf.String()), tc.expectedLines) + assert.Equal(t, out.LineCount(), tc.expectedLines) } if tc.cmd.Output == "json" {