Skip to content

Latest commit

 

History

History
96 lines (74 loc) · 3.1 KB

monitor.md

File metadata and controls

96 lines (74 loc) · 3.1 KB

Monitor

Overview

Monitor is a middleware construct of RESTful package. That can be used to execute functions pre and post requests. On server before and after handling a request. On client side before sending a request and after receiving the response.

Monitor can be used for various purposes, such as logging, create various metrics, service charging, message filtering, or authentication.

The concept is somewhat overlapping with container sidecars. Sidecars are completely independent, can be added or removed, and upgradeable independently. But they are more expensive, may require network interface tweaking, and problematic in serverless environment. Monitor does not have these issues.

Server

Monitor is available for Server, Router and Route classes, including sub-routers.

Built-in Logger is based on Monitor.

func pre(w http.ResponseWriter, r *http.Request) *http.Request {
    // Whatever to do before processing the request.
    fmt.Println("Begin")

    // If you write a response here, the handler function is not called.
    // Use it to terminate the request instead of let it being served.
    if r.URL.Path == "/error" {
        w.WriteHeader(http.StatusBadRequest)
    }

    // You may return a new Request structure, e.g. altering the original context.
    // Or return nil if the original request is fine.
    return nil
}

func post(w http.ResponseWriter, r *http.Request, statusCode int) {
    // Whatever to do after processing the request.
    // You can use the status code.
    fmt.Println("Ended with ", statusCode)

    // If the pre function changed the context, e.g. added a new value, then r.Context() contains that change.
}

func main() {
    ...
    router := restful.NewRouter().Monitor(pre, post)
    ...
}

Monitor is practically a wrapper around the original handler functions. You may apply several such wrappers.

router = router.Monitor(pre1, post1).Monitor(pre2, nil).Monitor(nil, post3)

Monitor is quite similar to Middleware of Gorilla/Mux. The result is the same that the original handler is wrapped by another handler. The syntax is a bit different. Probably slightly more convenient in some cases, especially when status code of the wrapped handler is needed.

Client

Client-side monitor is similar to server-side. The interface is different. Several Monitors can be added.

func pre(req *http.Request) (*http.Response, error) {
    // If response or error is returned, then the intended request is not sent.
    if req.URL.Path == "/error" {
        return nil, errors.New("don't do that")
    } else if req.URL.Path == "/404" {
        return &http.Response{StatusCode: http.StatusNotFound, Status: "404 Not Found", Request: req}, nil
    }

    req.Header.Add("My-Header", "hello")
    return nil, nil
}

func post(req *http.Request, resp *http.Response, err error) *http.Response {
    if resp != nil && resp.StatusCode < 300 {
        fmt.Println("All went fine.")
    }
    return nil
}

func main() {
    client := restful.NewClient()
    client.Monitor(pre, post)
    err := client.Get(context.Background(), "https://example.com/data", nil)
    ...
}