diff --git a/pkg/fission-cli/function.go b/pkg/fission-cli/function.go index 2b756a7c..3ab18d3e 100644 --- a/pkg/fission-cli/function.go +++ b/pkg/fission-cli/function.go @@ -730,6 +730,8 @@ func fnLogs(c *cli.Context) error { Namespace: fnNamespace, } + logReverseQuery := !c.Bool("f") && c.Bool("r") + recordLimit := c.Int("recordcount") if recordLimit <= 0 { recordLimit = 1000 @@ -758,6 +760,7 @@ func fnLogs(c *cli.Context) error { Function: f.Metadata.Name, FuncUid: string(f.Metadata.UID), Since: t, + Reverse: logReverseQuery, RecordLimit: recordLimit, } logEntries, err := logDB.GetLogs(logFilter) diff --git a/pkg/fission-cli/logdb/influxdb.go b/pkg/fission-cli/logdb/influxdb.go index 591dc282..ca7ee56f 100644 --- a/pkg/fission-cli/logdb/influxdb.go +++ b/pkg/fission-cli/logdb/influxdb.go @@ -22,7 +22,6 @@ import ( "net/http" "net/url" "path" - "sort" "strconv" "strings" "time" @@ -66,13 +65,18 @@ func (influx InfluxDB) GetLogs(filter LogFilter) ([]LogEntry, error) { parameters["time"] = timestamp //the parameters above are only for the where clause and do not work with LIMIT + orderCondition := " order by \"time\" asc" + if filter.Reverse { + orderCondition = " order by \"time\" desc" + } + if filter.Pod != "" { // wait for bug fix for fluent-bit influxdb plugin - queryCmd = "select * from /^log*/ where (\"funcuid\" = $funcuid OR \"kubernetes_labels_functionUid\" = $funcuid) AND \"pod\" = $pod AND \"time\" > $time LIMIT " + strconv.Itoa(filter.RecordLimit) + queryCmd = "select * from /^log*/ where (\"funcuid\" = $funcuid OR \"kubernetes_labels_functionUid\" = $funcuid) AND \"pod\" = $pod AND \"time\" > $time " + orderCondition + " LIMIT " + strconv.Itoa(filter.RecordLimit) parameters["pod"] = filter.Pod } else { // wait for bug fix for fluent-bit influxdb plugin - queryCmd = "select * from /^log*/ where (\"funcuid\" = $funcuid OR \"kubernetes_labels_functionUid\" = $funcuid) AND \"time\" > $time LIMIT " + strconv.Itoa(filter.RecordLimit) + queryCmd = "select * from /^log*/ where (\"funcuid\" = $funcuid OR \"kubernetes_labels_functionUid\" = $funcuid) AND \"time\" > $time " + orderCondition + " LIMIT " + strconv.Itoa(filter.RecordLimit) } query := influxdbClient.NewQueryWithParameters(queryCmd, INFLUXDB_DATABASE, "", parameters) @@ -125,16 +129,7 @@ func (influx InfluxDB) GetLogs(filter LogFilter) ([]LogEntry, error) { } } } - sort.Slice(logEntries, func(i, j int) bool { - if logEntries[i].Timestamp.Before(logEntries[j].Timestamp) { - return true - } - if logEntries[j].Timestamp.Before(logEntries[i].Timestamp) { - return false - } - return logEntries[i].Sequence < logEntries[j].Sequence - }) return logEntries, nil } diff --git a/pkg/fission-cli/logdb/logdb.go b/pkg/fission-cli/logdb/logdb.go index e5ff6ff9..41d61a51 100644 --- a/pkg/fission-cli/logdb/logdb.go +++ b/pkg/fission-cli/logdb/logdb.go @@ -34,6 +34,7 @@ type LogFilter struct { Function string FuncUid string Since time.Time + Reverse bool RecordLimit int } diff --git a/pkg/fission-cli/main.go b/pkg/fission-cli/main.go index 0dd83c0f..1aafd334 100644 --- a/pkg/fission-cli/main.go +++ b/pkg/fission-cli/main.go @@ -117,6 +117,7 @@ func NewCliApp() *cli.App { fnBuildCmdFlag := cli.StringFlag{Name: "buildcmd", Usage: "build command for builder to run with"} fnSecretFlag := cli.StringSliceFlag{Name: "secret", Usage: "function access to secret, should be present in the same namespace as the function. You can provide multiple secrets using multiple --secrets flags."} fnCfgMapFlag := cli.StringSliceFlag{Name: "configmap", Usage: "function access to configmap, should be present in the same namespace as the function. You can provide multiple configmaps using multiple --configmap flags."} + fnLogReverseQueryFlag := cli.BoolFlag{Name: "reverse, r", Usage: "specify the log reverse query base on time, it will be invalid if the 'follow' flag is specified"} fnLogCountFlag := cli.StringFlag{Name: "recordcount", Usage: "the n most recent log records"} fnForceFlag := cli.BoolFlag{Name: "force", Usage: "Force update a package even if it is used by one or more functions"} fnExecutorTypeFlag := cli.StringFlag{Name: "executortype", Value: types.ExecutorTypePoolmgr, Usage: "Executor type for execution; one of 'poolmgr', 'newdeploy' defaults to 'poolmgr'"} @@ -131,7 +132,7 @@ func NewCliApp() *cli.App { // TODO : for fnList, i feel like it's nice to allow --fns all, to list functions across all namespaces for cluster admins, although, this is against ns isolation. // so, in the future, if we end up using kubeconfig in fission cli and enforcing rolebindings to be created for users by admins etc, we can add this option at the time. {Name: "list", Usage: "List all functions in a namespace if specified, else, list functions across all namespaces", Flags: []cli.Flag{fnNamespaceFlag}, Action: fnList}, - {Name: "logs", Usage: "Display function logs", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag, fnPodFlag, fnFollowFlag, fnDetailFlag, fnLogDBTypeFlag, fnLogCountFlag}, Action: fnLogs}, + {Name: "logs", Usage: "Display function logs", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag, fnPodFlag, fnFollowFlag, fnDetailFlag, fnLogDBTypeFlag, fnLogReverseQueryFlag, fnLogCountFlag}, Action: fnLogs}, {Name: "test", Usage: "Test a function", Flags: []cli.Flag{fnNameFlag, fnNamespaceFlag, fnEnvNameFlag, fnCodeFlag, fnSrcArchiveFlag, htMethodFlag, fnBodyFlag, fnHeaderFlag, fnQueryFlag, fnTimeoutFlag}, Action: fnTest},