From a4d5742390592bea8224c3e97aef767940696328 Mon Sep 17 00:00:00 2001 From: John Mulligan Date: Sun, 8 Jul 2018 14:19:04 -0400 Subject: [PATCH 1/3] middleware: log the incoming request prior to processing It is useful to log the request as it is being made to the server rather than relying entirely on logging generated after the request. Logging before the request is processed can help a person debugging with understanding when the client first made the request. Log the client's user agent string. Signed-off-by: John Mulligan --- glusterd2/middleware/request_logging.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/glusterd2/middleware/request_logging.go b/glusterd2/middleware/request_logging.go index cc314d2d7..c81d86296 100644 --- a/glusterd2/middleware/request_logging.go +++ b/glusterd2/middleware/request_logging.go @@ -14,8 +14,16 @@ import ( // Apache Common Log Format (CLF) func LogRequest(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - entry := log.WithField("reqid", gdctx.GetReqID(r.Context()).String()) + entry := log.WithFields(log.Fields{ + "subsys": "rest", + "reqid": gdctx.GetReqID(r.Context()).String(), + }) + entry.WithFields(log.Fields{ + "method": r.Method, + "url": r.URL, + "client": r.UserAgent(), + }).Info("HTTP Request") delete(entry.Data, logging.SourceField) - handlers.LoggingHandler(entry.Writer(), next).ServeHTTP(w, r) + handlers.CombinedLoggingHandler(entry.Writer(), next).ServeHTTP(w, r) }) } From d432b5ad01d0c2fd971b5a707b3198aa47d74d20 Mon Sep 17 00:00:00 2001 From: John Mulligan Date: Sun, 8 Jul 2018 14:59:59 -0400 Subject: [PATCH 2/3] rest client: support sending and extending the user agent Support having the rest client library send a more specific user agent string to the server. Provide a mechanism for tools built upon that library to add more specific user agent information. Use the api in the glusercli command line tool to specify itself. Signed-off-by: John Mulligan --- glustercli/cmd/common.go | 3 +++ pkg/restclient/common.go | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/glustercli/cmd/common.go b/glustercli/cmd/common.go index bc6471ab3..cc51f8c8d 100644 --- a/glustercli/cmd/common.go +++ b/glustercli/cmd/common.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/gluster/glusterd2/pkg/restclient" + "github.com/gluster/glusterd2/version" ) var ( @@ -20,6 +21,8 @@ var ( func initRESTClient(hostname, user, secret, cacert string, insecure bool) { client = restclient.New(hostname, user, secret, cacert, insecure) + client.ExtendAgent( + fmt.Sprintf("glustercli/%v", version.GlusterdVersion)) } func isConnectionRefusedErr(err error) bool { diff --git a/pkg/restclient/common.go b/pkg/restclient/common.go index 02a421c9e..4d0dbd1e5 100644 --- a/pkg/restclient/common.go +++ b/pkg/restclient/common.go @@ -13,6 +13,7 @@ import ( "time" "github.com/gluster/glusterd2/pkg/api" + "github.com/gluster/glusterd2/version" "github.com/dgrijalva/jwt-go" ) @@ -29,11 +30,16 @@ type Client struct { password string cacert string insecure bool + + // Add to the identifier to further specify the client + // using the api. + agent string } // New creates new instance of Glusterd REST Client func New(baseURL string, username string, password string, cacert string, insecure bool) *Client { - return &Client{baseURL, username, password, cacert, insecure} + return &Client{baseURL, username, password, cacert, insecure, + fmt.Sprintf("GlusterD2-rest-client/%v", version.GlusterdVersion)} } func parseHTTPError(jsonData []byte) string { @@ -105,6 +111,7 @@ func (c *Client) do(method string, url string, data interface{}, expectStatusCod if err != nil { return err } + c.setAgent(req) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/json") req.Close = true @@ -163,3 +170,19 @@ func (c *Client) do(method string, url string, data interface{}, expectStatusCod func (c *Client) Ping() error { return c.get("/ping", nil, http.StatusOK, nil) } + +func (c *Client) setAgent(req *http.Request) { + req.Header.Set("User-Agent", + fmt.Sprintf("%v (Go-http-client/1.1)", c.agent)) +} + +// ExtendAgent adds the given string to the client's user agent +// by prefixing it to the existing agent information. +// This allows client programs to identify themselves more than +// just something using the rest client api. +func (c *Client) ExtendAgent(a string) { + // new additions to the agent identifier go to the + // beginning of the string. It is meant to read like: + // foo (based on) bar (based on) baz, etc... + c.agent = fmt.Sprintf("%v %v", a, c.agent) +} From e4b594572b4206d465c54f209569b6eaab8b99d3 Mon Sep 17 00:00:00 2001 From: John Mulligan Date: Mon, 9 Jul 2018 13:45:36 -0400 Subject: [PATCH 3/3] rest client: add mechanism to have server log cli arguments Extend the cli such that it can send it's original command line arguments to the server so that the server may log the original command that initiated the api call. Signed-off-by: John Mulligan --- glustercli/cmd/root.go | 4 ++++ glusterd2/middleware/request_logging.go | 8 ++++++-- pkg/restclient/common.go | 23 +++++++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/glustercli/cmd/root.go b/glustercli/cmd/root.go index a6fef09aa..6ac4f6634 100644 --- a/glustercli/cmd/root.go +++ b/glustercli/cmd/root.go @@ -47,6 +47,10 @@ var RootCmd = &cobra.Command{ } initRESTClient(flagEndpoints[0], flagUser, secret, flagCacert, flagInsecure) + if len(os.Args) > 1 { + args := []string{"glustercli"} + client.SetOriginArgs(append(args, os.Args[1:]...)) + } }, } diff --git a/glusterd2/middleware/request_logging.go b/glusterd2/middleware/request_logging.go index c81d86296..9890e10bc 100644 --- a/glusterd2/middleware/request_logging.go +++ b/glusterd2/middleware/request_logging.go @@ -14,10 +14,14 @@ import ( // Apache Common Log Format (CLF) func LogRequest(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - entry := log.WithFields(log.Fields{ + f := log.Fields{ "subsys": "rest", "reqid": gdctx.GetReqID(r.Context()).String(), - }) + } + if origin := r.Header.Get("X-Gluster-Origin-Args"); origin != "" { + f["origin"] = origin + } + entry := log.WithFields(f) entry.WithFields(log.Fields{ "method": r.Method, "url": r.URL, diff --git a/pkg/restclient/common.go b/pkg/restclient/common.go index 4d0dbd1e5..eeaac77b6 100644 --- a/pkg/restclient/common.go +++ b/pkg/restclient/common.go @@ -33,13 +33,15 @@ type Client struct { // Add to the identifier to further specify the client // using the api. - agent string + agent string + originArgs []string } // New creates new instance of Glusterd REST Client func New(baseURL string, username string, password string, cacert string, insecure bool) *Client { return &Client{baseURL, username, password, cacert, insecure, - fmt.Sprintf("GlusterD2-rest-client/%v", version.GlusterdVersion)} + fmt.Sprintf("GlusterD2-rest-client/%v", version.GlusterdVersion), + []string{}} } func parseHTTPError(jsonData []byte) string { @@ -121,6 +123,8 @@ func (c *Client) do(method string, url string, data interface{}, expectStatusCod req.Header.Set("Authorization", "bearer "+getAuthToken(c.username, c.password)) } + c.sendOriginArgs(req) + tr := &http.Transport{ DisableCompression: true, DisableKeepAlives: true, @@ -186,3 +190,18 @@ func (c *Client) ExtendAgent(a string) { // foo (based on) bar (based on) baz, etc... c.agent = fmt.Sprintf("%v %v", a, c.agent) } + +func (c *Client) sendOriginArgs(req *http.Request) { + if len(c.originArgs) != 0 { + req.Header.Set("X-Gluster-Origin-Args", + fmt.Sprintf("1:%#v", strings.Join(c.originArgs, " "))) + } +} + +// SetOriginArgs provides a way for tools using this library to +// inform the server what arguments were provided to generate +// the api call(s). The contents of the array are meant only for +// human interpretation but will generally be command line args. +func (c *Client) SetOriginArgs(a []string) { + c.originArgs = a +}