Documentation
¶
Overview ¶
Package gohm is a tiny Go library with HTTP middleware functions.
gohm provides a small collection of middleware functions to be used when creating a HTTP micro service written in Go.
One function in particular, gohm.Error, is not used as HTTP middleware, but as a helper for emitting a sensible error message back to the HTTP client when the HTTP request could not be fulfilled. It emits a text response beginning with the status code, the human friendly status message, followed by an optional text message. It is meant to be a drop in replacement for http.Error message, that formats the error message in a more conventional way to include the status code and message.
// Example function which guards downstream handlers to ensure only HTTP GET method used // to access resource. func onlyGet(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { gohm.Error(w, r.Method, http.StatusMethodNotAllowed) // 405 Method Not Allowed: POST return } next.ServeHTTP(w, r) }) }
All the other gohm functions are HTTP middleware functions, designed to wrap any HTTP handler, composing some functionality around it. They can be interchanged and used with other HTTP middleware functions providing those functions adhere to the http.Handler interface and have a ServeHTTP(http.ResponseHandler, *http.Request) method.
mux := http.NewServeMux() var h http.HandlerFunc = someHandler h = gohm.WithGzip(h) h = gohm.ConvertPanicsToErrors(h) h = gohm.WithTimeout(globalTimeout, h) h = gohm.LogErrors(os.Stderr, h) mux.Handle("/static/", h)
*NOTE:* When both the WithTimeout and the ConvertPanicsToErrors are used, the WithTimeout ought to wrap the ConvertPanicsToErrors. This is because timeout handlers in Go are generally implemented using a separate goroutine, and the panic could occur in an alternate goroutine and not get caught by the ConvertPanicsToErrors.
Index ¶
- Constants
- func ConvertPanicsToErrors(next http.Handler) http.Handler
- func Error(w http.ResponseWriter, text string, code int)
- func LogAll(out io.Writer, next http.Handler) http.Handler
- func LogAllWithFormat(format string, out io.Writer, next http.Handler) http.Handler
- func LogErrors(out io.Writer, next http.Handler) http.Handler
- func LogErrorsWithFormat(format string, out io.Writer, next http.Handler) http.Handler
- func LogStatusBitmask(bitmask *uint32, out io.Writer, next http.Handler) http.Handler
- func LogStatusBitmaskWithFormat(format string, bitmask *uint32, out io.Writer, next http.Handler) http.Handler
- func Status1xxCounter(counter *expvar.Int, next http.Handler) http.Handlerdeprecated
- func Status2xxCounter(counter *expvar.Int, next http.Handler) http.Handlerdeprecated
- func Status3xxCounter(counter *expvar.Int, next http.Handler) http.Handlerdeprecated
- func Status4xxCounter(counter *expvar.Int, next http.Handler) http.Handlerdeprecated
- func Status5xxCounter(counter *expvar.Int, next http.Handler) http.Handlerdeprecated
- func StatusAllCounter(counter *expvar.Int, next http.Handler) http.Handlerdeprecated
- func StatusCounters(counters *Counters, next http.Handler) http.Handler
- func WithCloseNotifier(next http.Handler) http.Handler
- func WithGzip(next http.Handler) http.Handler
- func WithTimeout(timeout time.Duration, next http.Handler) http.Handler
- type Counters
- func (c Counters) Get1xx() uint64
- func (c Counters) Get2xx() uint64
- func (c Counters) Get3xx() uint64
- func (c Counters) Get4xx() uint64
- func (c Counters) Get5xx() uint64
- func (c Counters) GetAll() uint64
- func (c Counters) GetAndReset1xx() uint64
- func (c Counters) GetAndReset2xx() uint64
- func (c Counters) GetAndReset3xx() uint64
- func (c Counters) GetAndReset4xx() uint64
- func (c Counters) GetAndReset5xx() uint64
- func (c Counters) GetAndResetAll() uint64
Constants ¶
const ( LogStatus1xx uint32 = 1 // LogStatus1xx used to log HTTP requests which have a 1xx response LogStatus2xx uint32 = 2 // LogStatus2xx used to log HTTP requests which have a 2xx response LogStatus3xx uint32 = 4 // LogStatus3xx used to log HTTP requests which have a 3xx response LogStatus4xx uint32 = 8 // LogStatus4xx used to log HTTP requests which have a 4xx response LogStatus5xx uint32 = 16 // LogStatus5xx used to log HTTP requests which have a 5xx response LogStatusAll uint32 = 1 | 2 | 4 | 8 | 16 // LogStatusAll used to log all HTTP requests LogStatusErrors uint32 = 8 | 16 // LogStatusAll used to log HTTP requests which have 4xx or 5xx response )
const ApacheCommonLogFormat = "{client-ip} - - [{begin}] \"{method} {uri} {proto}\" {status} {bytes}"
ApacheCommonLogFormat (CLF) is the default log line format for Apache Web Server. It is included here for users of this library that would like to easily specify log lines out to be emitted using the Apache Common Log Format (CLR).
"%h %l %u %t \"%r\" %>s %b" "{remote-hostname} {remote-logname} {remote-user} {begin-time} \"{first-line-of-request}\" {status} {bytes}" "{remote-ip} - - {begin-time} \"{first-line-of-request}\" {status} {bytes}"
const DefaultLogFormat = "{client-ip} [{begin-iso8601}] \"{method} {uri} {proto}\" {status} {bytes} {duration}"
DefaultLogFormat is the default log line format used by this library.
Variables ¶
This section is empty.
Functions ¶
func ConvertPanicsToErrors ¶
ConvertPanicsToErrors returns a new http.Handler that catches all panics that may be caused by the specified http.Handler, and responds with an appropriate http status code and message.
mux := http.NewServeMux() mux.Handle("/example/path", gohm.ConvertPanicsToErrors(someHandler))
func Error ¶
func Error(w http.ResponseWriter, text string, code int)
Error formats and emits the specified error message text and status code information to the http.ResponseWriter, to be consumed by the client of the service. This particular helper function has nothing to do with emitting log messages on the server side, and only creates a response for the client. Typically handlers will call this method prior to invoking return to exit to whichever handler invoked it.
// example function which guards downstream handlers to ensure only HTTP GET method used // to access resource. func onlyGet(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { gohm.Error(w, r.Method, http.StatusMethodNotAllowed) // 405 Method Not Allowed: POST return } next.ServeHTTP(w, r) }) }
func LogAll ¶
LogAll returns a new http.Handler that logs HTTP requests and responses using the gohm.DefaultLogFormat to the specified io.Writer.
mux := http.NewServeMux() mux.Handle("/example/path", gohm.LogAll(os.Stderr, someHandler))
func LogAllWithFormat ¶ added in v1.5.0
LogAllWithFormat returns a new http.Handler that logs HTTP requests and responses using the specified log format string to the specified io.Writer.
mux := http.NewServeMux() format := "{http-CLIENT-IP} {http-USER} [{end}] \"{method} {uri} {proto}\" {status} {bytes} {duration}" mux.Handle("/example/path", gohm.LogAllWithFormat(format, os.Stderr, someHandler))
func LogErrors ¶
LogErrors returns a new http.Handler that logs HTTP requests that result in response errors, or more specifically, HTTP status codes that are either 4xx or 5xx. The handler will output lines using the gohm.DefaultLogFormat to the specified io.Writer.
mux := http.NewServeMux() mux.Handle("/example/path", gohm.LogErrors(os.Stderr, someHandler))
func LogErrorsWithFormat ¶ added in v1.5.0
LogErrorsWithFormat returns a new http.Handler that logs HTTP requests that result in response errors, or more specifically, HTTP status codes that are either 4xx or 5xx. The handler will output lines using the specified log format string to the specified io.Writer.
mux := http.NewServeMux() format := "{http-CLIENT-IP} {http-USER} [{end}] \"{method} {uri} {proto}\" {status} {bytes} {duration}" mux.Handle("/example/path", gohm.LogErrorsWithFormat(format, os.Stderr, someHandler))
func LogStatusBitmask ¶ added in v1.2.0
LogStatusBitmask returns a new http.Handler that logs HTTP requests that have a status code that matches any of the status codes in the specified bitmask. The handler will output lines using the gohm.DefaultLogFormat to the specified io.Writer.
The bitmask parameter is used to specify which HTTP requests ought to be logged based on the HTTP status code returned by the next http.Handler.
mux := http.NewServeMux() logBitmask := uint32(gohm.LogStatus4xx|gohm.LogStatus5xx) mux.Handle("/example/path", gohm.LogStatusBitmask(&logBitmask, os.Stderr, someHandler))
func LogStatusBitmaskWithFormat ¶ added in v1.2.0
func LogStatusBitmaskWithFormat(format string, bitmask *uint32, out io.Writer, next http.Handler) http.Handler
LogStatusBitmaskWithFormat returns a new http.Handler that logs HTTP requests that have a status code that matches any of the status codes in the specified bitmask. The handler will output lines in the specified log format string to the specified io.Writer.
The following format directives are supported:
begin: time request received (apache log time format) begin-epoch: time request received (epoch) begin-iso8601: time request received (ISO-8601 time format) bytes: response size client: client-ip:client-port client-ip: client IP address client-port: client port duration: duration of request from begin to end, (seconds with millisecond precision) end: time request completed (apache log time format) end-epoch: time request completed (epoch) end-iso8601: time request completed (ISO-8601 time format) method: request method, e.g., GET or POST proto: request protocol, e.g., HTTP/1.1 status: response status code uri: request URI
In addition, values from HTTP request headers can also be included in the log by prefixing the HTTP header name with http-. In the below example, each log line will begin with the value of the HTTP request header CLIENT-IP followed by the value of the HTTP request header USER:
format := "{http-CLIENT-IP} {http-USER} [{end}] \"{method} {uri} {proto}\" {status} {bytes} {duration}"
The bitmask parameter is used to specify which HTTP requests ought to be logged based on the HTTP status code returned by the next http.Handler.
mux := http.NewServeMux() format := "{http-CLIENT-IP} {http-USER} [{end}] \"{method} {uri} {proto}\" {status} {bytes} {duration}" logBitmask := uint32(gohm.LogStatus4xx|gohm.LogStatus5xx) mux.Handle("/example/path", gohm.LogStatusBitmaskWithFormat(format, &logBitmask, os.Stderr, someHandler))
func Status1xxCounter
deprecated
Status1xxCounter returns a new http.Handler that composes the specified next http.Handler, and increments the specified counter when the response status code is not 1xx.
Deprecated: Use gohm.StatusCounters instead.
var counter1xx = expvar.NewInt("counter1xx") mux := http.NewServeMux() mux.Handle("/example/path", gohm.Status1xxCounter(counter1xx, someHandler))
func Status2xxCounter
deprecated
Status2xxCounter returns a new http.Handler that composes the specified next http.Handler, and increments the specified counter when the response status code is not 2xx.
Deprecated: Use gohm.StatusCounters instead.
var counter2xx = expvar.NewInt("counter2xx") mux := http.NewServeMux() mux.Handle("/example/path", gohm.Status2xxCounter(counter2xx, someHandler))
func Status3xxCounter
deprecated
Status3xxCounter returns a new http.Handler that composes the specified next http.Handler, and increments the specified counter when the response status code is not 3xx.
Deprecated: Use gohm.StatusCounters instead.
var counter3xx = expvar.NewInt("counter3xx") mux := http.NewServeMux() mux.Handle("/example/path", gohm.Status3xxCounter(counter3xx, someHandler))
func Status4xxCounter
deprecated
Status4xxCounter returns a new http.Handler that composes the specified next http.Handler, and increments the specified counter when the response status code is not 4xx.
Deprecated: Use gohm.StatusCounters instead.
var counter4xx = expvar.NewInt("counter4xx") mux := http.NewServeMux() mux.Handle("/example/path", gohm.Status4xxCounter(counter4xx, someHandler))
func Status5xxCounter
deprecated
Status5xxCounter returns a new http.Handler that composes the specified next http.Handler, and increments the specified counter when the response status code is not 5xx.
Deprecated: Use gohm.StatusCounters instead.
var counter5xx = expvar.NewInt("counter5xx") mux := http.NewServeMux() mux.Handle("/example/path", gohm.Status5xxCounter(counter5xx, someHandler))
func StatusAllCounter
deprecated
added in
v1.1.0
StatusAllCounter returns a new http.Handler that composes the specified next http.Handler, and increments the specified counter for every query.
Deprecated: Use gohm.StatusCounters instead.
var counterAll = expvar.NewInt("counterAll") mux := http.NewServeMux() mux.Handle("/example/path", gohm.StatusAllCounter(counterAll, someHandler))
func StatusCounters ¶ added in v1.4.0
StatusCounters returns a new http.Handler that increments the specified gohm.Counters for every HTTP response based on the status code of the specified http.Handler.
var counters gohm.Counters mux := http.NewServeMux() mux.Handle("/example/path", gohm.StatusCounters(&counters, someHandler)) // later on... status1xxCounter := counters.Get1xx()
func WithCloseNotifier ¶ added in v1.6.0
WithCloseNotifier returns a new http.Handler that attempts to detect when the client has closed the connection, and if it does so, immediately returns with an appropriate error message to be logged, while sending a signal to context-aware downstream handlers.
mux := http.NewServeMux() mux.Handle("/example/path", gohm.WithCloseNotifier(someHandler))
func WithGzip ¶
WithGzip returns a new http.Handler that optionally compresses the response text using the gzip compression algorithm when the HTTP request's Accept-Encoding header includes the string "gzip".
mux := http.NewServeMux() mux.Handle("/example/path", gohm.WithGzip(someHandler))
func WithTimeout ¶
WithTimeout returns a new http.Handler that creates a watchdog goroutine to detect when the timeout has expired. It also modifies the request to add a context timeout, because while not all handlers use context and respect context timeouts, it's likely that more and more will over time as context becomes more popular.
Unlike when using http.TimeoutHandler, if a downstream http.Handler panics, this handler will catch that panic in the other goroutine and re-play it in the primary goroutine, allowing upstream handlers to catch the panic if desired. Panics may be caught by the gohm.ConvertPanicsToErrors handler when placed upstream of this handler.
mux := http.NewServeMux() mux.Handle("/example/path", gohm.WithTimeout(10 * time.Second, someHandler))
Types ¶
type Counters ¶ added in v1.4.0
type Counters struct {
// contains filtered or unexported fields
}
Counters structure stores status counters used to track number of HTTP responses resulted in various status codes. The counts are grouped by the status code groups.
var counters gohm.Counters mux := http.NewServeMux() mux.Handle("/example/path", gohm.StatusCounters(&counters, someHandler)) // later on... countOf1xx := counters.Get1xx() countOf2xx := counters.Get2xx() countOf3xx := counters.Get3xx() countOf4xx := counters.Get4xx() countOf5xx := counters.Get5xx() countTotal := counters.GetAll()
func (Counters) Get1xx ¶ added in v1.4.0
Get1xx returns number of HTTP responses resulting in a 1xx status code.
func (Counters) Get2xx ¶ added in v1.4.0
Get2xx returns number of HTTP responses resulting in a 2xx status code.
func (Counters) Get3xx ¶ added in v1.4.0
Get3xx returns number of HTTP responses resulting in a 3xx status code.
func (Counters) Get4xx ¶ added in v1.4.0
Get4xx returns number of HTTP responses resulting in a 4xx status code.
func (Counters) Get5xx ¶ added in v1.4.0
Get5xx returns number of HTTP responses resulting in a 5xx status code.
func (Counters) GetAll ¶ added in v1.4.0
GetAll returns total number of HTTP responses, regardless of status code.
func (Counters) GetAndReset1xx ¶ added in v1.4.0
GetAndReset1xx returns number of HTTP responses resulting in a 1xx status code, and resets the counter to 0.
func (Counters) GetAndReset2xx ¶ added in v1.4.0
GetAndReset2xx returns number of HTTP responses resulting in a 2xx status code, and resets the counter to 0.
func (Counters) GetAndReset3xx ¶ added in v1.4.0
GetAndReset3xx returns number of HTTP responses resulting in a 3xx status code, and resets the counter to 0.
func (Counters) GetAndReset4xx ¶ added in v1.4.0
GetAndReset4xx returns number of HTTP responses resulting in a 4xx status code, and resets the counter to 0.
func (Counters) GetAndReset5xx ¶ added in v1.4.0
GetAndReset5xx returns number of HTTP responses resulting in a 5xx status code, and resets the counter to 0.
func (Counters) GetAndResetAll ¶ added in v1.4.0
GetAndResetAll returns number of HTTP responses resulting in a All status code, and resets the counter to 0.