diff --git a/fission/function.go b/fission/function.go index 7ed69544..25f602fd 100644 --- a/fission/function.go +++ b/fission/function.go @@ -444,6 +444,11 @@ func fnLogs(c *cli.Context) error { Namespace: metav1.NamespaceDefault, } + recordLimit := c.Int("recordcount") + if recordLimit <= 0 { + recordLimit = 1000 + } + f, err := client.FunctionGet(m) checkErr(err, "get function") @@ -463,10 +468,11 @@ func fnLogs(c *cli.Context) error { select { case <-requestChan: logFilter := logdb.LogFilter{ - Pod: fnPod, - Function: f.Metadata.Name, - FuncUid: string(f.Metadata.UID), - Since: t, + Pod: fnPod, + Function: f.Metadata.Name, + FuncUid: string(f.Metadata.UID), + Since: t, + RecordLimit: recordLimit, } logEntries, err := logDB.GetLogs(logFilter) if err != nil { diff --git a/fission/logdb/influxdb.go b/fission/logdb/influxdb.go index 63fd4b35..b322055d 100644 --- a/fission/logdb/influxdb.go +++ b/fission/logdb/influxdb.go @@ -22,6 +22,8 @@ import ( "log" "net/http" "net/url" + "sort" + "strconv" "strings" "time" @@ -74,12 +76,13 @@ func (influx InfluxDB) GetLogs(filter LogFilter) ([]LogEntry, error) { parameters := make(map[string]interface{}) parameters["funcuid"] = filter.FuncUid parameters["time"] = timestamp + //the parameters above are only for the where clause and do not work with LIMIT if filter.Pod != "" { - queryCmd = "select * from \"log\" where \"funcuid\" = $funcuid AND \"pod\" = $pod AND \"time\" > $time ORDER BY time ASC" + queryCmd = "select * from \"log\" where \"funcuid\" = $funcuid AND \"pod\" = $pod AND \"time\" > $time LIMIT " + strconv.Itoa(filter.RecordLimit) parameters["pod"] = filter.Pod } else { - queryCmd = "select * from \"log\" where \"funcuid\" = $funcuid AND \"time\" > $time ORDER BY time ASC" + queryCmd = "select * from \"log\" where \"funcuid\" = $funcuid AND \"time\" > $time LIMIT " + strconv.Itoa(filter.RecordLimit) } query := influxdbClient.NewQueryWithParameters(queryCmd, INFLUXDB_DATABASE, "", parameters) @@ -95,6 +98,10 @@ func (influx InfluxDB) GetLogs(filter LogFilter) ([]LogEntry, error) { if err != nil { log.Fatal(err) } + seqNum, err := strconv.Atoi(row[1].(string)) + if err != nil { + return logEntries, err + } logEntries = append(logEntries, LogEntry{ //The attributes of the LogEntry are selected as relative to their position in InfluxDB's line protocol response Timestamp: t, @@ -105,10 +112,21 @@ func (influx InfluxDB) GetLogs(filter LogFilter) ([]LogEntry, error) { Namespace: row[14].(string), //kubernetes_namespace_name Pod: row[15].(string), //kubernetes_pod_name Stream: row[18].(string), //stream + Sequence: seqNum, //sequence tag }) } } } + 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/fission/logdb/logdb.go b/fission/logdb/logdb.go index 61b79b8e..1d37b5e2 100644 --- a/fission/logdb/logdb.go +++ b/fission/logdb/logdb.go @@ -32,16 +32,18 @@ type LogDatabase interface { } type LogFilter struct { - Pod string - Function string - FuncUid string - Since time.Time + Pod string + Function string + FuncUid string + Since time.Time + RecordLimit int } type LogEntry struct { Timestamp time.Time Message string Stream string + Sequence int Container string Namespace string FuncName string diff --git a/fission/main.go b/fission/main.go index becdb764..ad4a7778 100644 --- a/fission/main.go +++ b/fission/main.go @@ -51,6 +51,7 @@ func main() { fnHeaderFlag := cli.StringSliceFlag{Name: "header, H", Usage: "request headers"} fnEntryPointFlag := cli.StringFlag{Name: "entrypoint", Usage: "entry point for environment v2 to load with"} fnBuildCmdFlag := cli.StringFlag{Name: "buildcmd", Usage: "build command for builder to run with"} + fnLogCountFlag := cli.StringFlag{Name: "recordcount", Usage: "the n most recent log records"} fnSubcommands := []cli.Command{ {Name: "create", Usage: "Create new function (and optionally, an HTTP route to it)", Flags: []cli.Flag{fnNameFlag, fnEnvNameFlag, fnCodeFlag, fnPackageFlag, fnSrcArchiveFlag, fnDeployArchiveFlag, fnEntryPointFlag, fnBuildCmdFlag, htUrlFlag, htMethodFlag}, Action: fnCreate}, @@ -59,7 +60,7 @@ func main() { {Name: "update", Usage: "Update function source code", Flags: []cli.Flag{fnNameFlag, fnEnvNameFlag, fnCodeFlag, fnPackageFlag, fnSrcArchiveFlag, fnDeployArchiveFlag, fnEntryPointFlag, fnBuildCmdFlag}, Action: fnUpdate}, {Name: "delete", Usage: "Delete function", Flags: []cli.Flag{fnNameFlag}, Action: fnDelete}, {Name: "list", Usage: "List all functions", Flags: []cli.Flag{}, Action: fnList}, - {Name: "logs", Usage: "Display function logs", Flags: []cli.Flag{fnNameFlag, fnPodFlag, fnFollowFlag, fnDetailFlag, fnLogDBTypeFlag}, Action: fnLogs}, + {Name: "logs", Usage: "Display function logs", Flags: []cli.Flag{fnNameFlag, fnPodFlag, fnFollowFlag, fnDetailFlag, fnLogDBTypeFlag, fnLogCountFlag}, Action: fnLogs}, {Name: "pods", Usage: "Display function pods", Flags: []cli.Flag{fnNameFlag, fnLogDBTypeFlag}, Action: fnPods}, {Name: "test", Usage: "Test a function", Flags: []cli.Flag{fnNameFlag, fnEnvNameFlag, fnCodeFlag, fnPackageFlag, fnSrcArchiveFlag, htMethodFlag, fnBodyFlag, fnHeaderFlag}, Action: fnTest}, }