From 4d94d07850f9b26cef01f90c7ebbea76ddda56ef Mon Sep 17 00:00:00 2001 From: Lucas Roesler Date: Sun, 15 Dec 2019 16:54:13 +0100 Subject: [PATCH] Allow log requests to specify a namespace filter **What** - Add `Namespace` field to the log request and response so that users can specify the namespace of the function. This is required to support the new multi-namespace support. Using this, a user can deploy a function with the same name to multiple namespaces. E.g. to `dev` and `prod` namespaces. The namespace field is required so that the user can target the specific deployment of the function. It is expected the that the empty namespace will be treated as "in the default namespace" Note that this does not actually implement any filtering logic, it only allows the log providers to accept and return the information. faas-provider and log-provider implementation will need to update and handle the new field accordingly. Signed-off-by: Lucas Roesler --- logs/example/main.go | 1 + logs/handler.go | 1 + logs/handler_test.go | 21 ++++++++------------- logs/logs.go | 16 ++++++++++++++-- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/logs/example/main.go b/logs/example/main.go index 0386036..8b4c518 100644 --- a/logs/example/main.go +++ b/logs/example/main.go @@ -30,6 +30,7 @@ func (s staticLogRequestor) Query(ctx context.Context, r logs.Request) (<-chan l resp <- logs.Message{ Name: r.Name, + Namespace: r.Namespace, Instance: "fake", Timestamp: time.Now(), Text: m, diff --git a/logs/handler.go b/logs/handler.go index 0ab10a0..70616d8 100644 --- a/logs/handler.go +++ b/logs/handler.go @@ -107,6 +107,7 @@ func NewLogHandlerFunc(requestor Requester, timeout time.Duration) http.HandlerF func parseRequest(r *http.Request) (logRequest Request, err error) { query := r.URL.Query() logRequest.Name = getValue(query, "name") + logRequest.Namespace = getValue(query, "namespace") logRequest.Instance = getValue(query, "instance") tailStr := getValue(query, "tail") if tailStr != "" { diff --git a/logs/handler_test.go b/logs/handler_test.go index 5b9c2a2..6fb718b 100644 --- a/logs/handler_test.go +++ b/logs/handler_test.go @@ -19,7 +19,7 @@ func Test_logsHandlerDoesNotLeakGoroutinesWhenProviderClosesStream(t *testing.T) defer goleak.VerifyNoLeaks(t) msgs := []Message{ - Message{Name: "funcFoo", Text: "msg 0"}, + Message{Name: "funcFoo", Text: "msg 0", Namespace: "default"}, Message{Name: "funcFoo", Text: "msg 1"}, } @@ -54,7 +54,7 @@ func Test_logsHandlerDoesNotLeakGoroutinesWhenClientClosesConnection(t *testing. defer goleak.VerifyNoLeaks(t) msgs := []Message{ - Message{Name: "funcFoo", Text: "msg 0"}, + Message{Name: "funcFoo", Text: "msg 0", Namespace: "default"}, Message{Name: "funcFoo", Text: "msg 1"}, } @@ -103,12 +103,6 @@ func Test_GETRequestParsing(t *testing.T) { err: "", expectedRequest: Request{Name: "foobar"}, }, - { - name: "name only query", - rawQueryStr: "name=foobar", - err: "", - expectedRequest: Request{Name: "foobar"}, - }, { name: "multiple name values selects the last value", rawQueryStr: "name=foobar&name=theactual name", @@ -117,13 +111,14 @@ func Test_GETRequestParsing(t *testing.T) { }, { name: "valid request with every parameter", - rawQueryStr: "name=foobar&since=2019-02-16T09%3A10%3A06%2B00%3A00&tail=5&follow=true", + rawQueryStr: "name=foobar&since=2019-02-16T09%3A10%3A06%2B00%3A00&tail=5&follow=true&namespace=default", err: "", expectedRequest: Request{ - Name: "foobar", - Since: &sinceTime, - Tail: 5, - Follow: true, + Name: "foobar", + Namespace: "default", + Since: &sinceTime, + Tail: 5, + Follow: true, }, }, } diff --git a/logs/logs.go b/logs/logs.go index 6a48c50..4069c40 100644 --- a/logs/logs.go +++ b/logs/logs.go @@ -16,6 +16,9 @@ import ( type Request struct { // Name is the function name and is required Name string `json:"name"` + // Namespace is the namespace the function is deployed to, how a namespace is defined + // is faas-provider specific + Namespace string `json:"namespace"` // Instance is the optional container name, that allows you to request logs from a specific function instance Instance string `json:"instance"` // Since is the optional datetime value to start the logs from @@ -29,13 +32,19 @@ type Request struct { // String implements that Stringer interface and prints the log Request in a consistent way that // allows you to safely compare if two requests have the same value. func (r Request) String() string { - return fmt.Sprintf("name:%s instance:%s since:%v tail:%d follow:%v", r.Name, r.Instance, r.Since, r.Tail, r.Follow) + return fmt.Sprintf( + "name:%s namespace: %s instance:%s since:%v tail:%d follow:%v", + r.Name, r.Namespace, r.Instance, r.Since, r.Tail, r.Follow, + ) } // Message is a specific log message from a function container log stream type Message struct { // Name is the function name Name string `json:"name"` + // Namespace is the namespace the function is deployed to, how a namespace is defined + // is faas-provider specific + Namespace string `json:"namespace"` // instance is the name/id of the specific function instance Instance string `json:"instance"` // Timestamp is the timestamp of when the log message was recorded @@ -46,5 +55,8 @@ type Message struct { // String implements the Stringer interface and allows for nice and simple string formatting of a log Message. func (m Message) String() string { - return fmt.Sprintf("%s %s (%s) %s", m.Timestamp.String(), m.Name, m.Instance, m.Text) + return fmt.Sprintf( + "%s %s (%s %s) %s", + m.Timestamp.String(), m.Name, m.Namespace, m.Instance, m.Text, + ) }