-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add abcsessions, abcrender, abcmiddleware
- Loading branch information
Showing
26 changed files
with
4,223 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
Copyright (c) 2016 The ABCWeb Authors. All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are | ||
met: | ||
|
||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above | ||
copyright notice, this list of conditions and the following disclaimer | ||
in the documentation and/or other materials provided with the | ||
distribution. | ||
* Neither the name of VolatileTech nor the names of its | ||
contributors may be used to endorse or promote products derived from | ||
this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# ABCMiddleware | ||
|
||
[](https://github.com/volatiletech/abcmiddleware/blob/master/LICENSE) | ||
[](https://godoc.org/github.com/volatiletech/abcmiddleware) | ||
[](http://goreportcard.com/report/volatiletech/abcmiddleware) | ||
|
||
## Available Middleware | ||
|
||
* Zap - Zap middleware handles web request logging using Zap | ||
* Recover - Recover middleware recovers panics that occur and gracefully logs their error | ||
|
||
See GoDoc for API usage. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package abcmiddleware | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"time" | ||
|
||
chimiddleware "github.com/pressly/chi/middleware" | ||
"go.uber.org/zap" | ||
) | ||
|
||
// zapResponseWriter is a wrapper that includes that http status and size for logging | ||
type zapResponseWriter struct { | ||
http.ResponseWriter | ||
status int | ||
size int | ||
} | ||
|
||
// Zap middleware handles web request logging using Zap | ||
func (m Middleware) Zap(next http.Handler) http.Handler { | ||
fn := func(w http.ResponseWriter, r *http.Request) { | ||
t := time.Now() | ||
zw := &zapResponseWriter{ResponseWriter: w} | ||
|
||
// Serve the request | ||
next.ServeHTTP(zw, r) | ||
|
||
// Write the request log line | ||
writeZap(m.Log, r, t, zw.status, zw.size) | ||
} | ||
|
||
return http.HandlerFunc(fn) | ||
} | ||
|
||
// RequestIDLogger middleware creates a derived logger to include logging of the | ||
// Request ID, and inserts it into the context object | ||
func (m Middleware) RequestIDLogger(next http.Handler) http.Handler { | ||
fn := func(w http.ResponseWriter, r *http.Request) { | ||
requestID := chimiddleware.GetReqID(r.Context()) | ||
derivedLogger := m.Log.With(zap.String("request_id", requestID)) | ||
r = r.WithContext(context.WithValue(r.Context(), CtxLoggerKey, derivedLogger)) | ||
next.ServeHTTP(w, r) | ||
} | ||
|
||
return http.HandlerFunc(fn) | ||
} | ||
|
||
// Log returns the Request ID scoped logger from the request Context | ||
// and panics if it cannot be found. This function is only ever used | ||
// by your controllers if your app uses the RequestID middlewares, | ||
// otherwise you should use the controller's receiver logger directly. | ||
func Log(r *http.Request) *zap.Logger { | ||
v := r.Context().Value(CtxLoggerKey) | ||
log, ok := v.(*zap.Logger) | ||
if !ok { | ||
panic("cannot get derived request id logger from context object") | ||
} | ||
return log | ||
} | ||
|
||
func writeZap(log *zap.Logger, r *http.Request, t time.Time, status int, size int) { | ||
elapsed := time.Now().Sub(t) | ||
var protocol string | ||
if r.TLS == nil { | ||
protocol = "http" | ||
} else { | ||
protocol = "https" | ||
} | ||
|
||
v := r.Context().Value(CtxLoggerKey) | ||
if v != nil { | ||
var ok bool | ||
log, ok = v.(*zap.Logger) | ||
if !ok { | ||
panic("cannot get derived request id logger from context object") | ||
} | ||
} | ||
|
||
// log all the fields | ||
log.Info(fmt.Sprintf("%s request", protocol), | ||
zap.Int("status", status), | ||
zap.String("method", r.Method), | ||
zap.String("uri", r.RequestURI), | ||
zap.Bool("tls", r.TLS != nil), | ||
zap.String("protocol", r.Proto), | ||
zap.String("host", r.Host), | ||
zap.String("remote_addr", r.RemoteAddr), | ||
zap.Int("size", size), | ||
zap.Duration("elapsed", elapsed), | ||
) | ||
} | ||
|
||
func (z *zapResponseWriter) WriteHeader(code int) { | ||
z.status = code | ||
z.ResponseWriter.WriteHeader(code) | ||
} | ||
|
||
func (z *zapResponseWriter) Write(b []byte) (int, error) { | ||
size, err := z.ResponseWriter.Write(b) | ||
z.size += size | ||
return size, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package abcmiddleware | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
"testing" | ||
|
||
"go.uber.org/zap" | ||
) | ||
|
||
func TestLog(t *testing.T) { | ||
t.Parallel() | ||
|
||
ctx := context.Background() | ||
z, err := zap.NewDevelopment() | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
ctx = context.WithValue(ctx, CtxLoggerKey, z) | ||
r := &http.Request{} | ||
r = r.WithContext(ctx) | ||
|
||
// Ensure log can be called successfully. Ignore response because we don't | ||
// need to validate anything. | ||
_ = Log(r) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package abcmiddleware | ||
|
||
import "go.uber.org/zap" | ||
|
||
// CtxLoggerKey is the http.Request Context lookup key for the request ID logger | ||
const CtxLoggerKey = "request_id_logger" | ||
|
||
// Middleware exposes useful variables to every abcmiddleware handler | ||
type Middleware struct { | ||
// Log is used for logging in your middleware and to | ||
// create a derived logger that includes the request ID. | ||
Log *zap.Logger | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package abcmiddleware | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
|
||
"go.uber.org/zap" | ||
) | ||
|
||
// Recover middleware recovers panics that occur and gracefully logs their error | ||
func (m Middleware) Recover(next http.Handler) http.Handler { | ||
fn := func(w http.ResponseWriter, r *http.Request) { | ||
defer func() { | ||
if err := recover(); err != nil { | ||
var protocol string | ||
if r.TLS == nil { | ||
protocol = "http" | ||
} else { | ||
protocol = "https" | ||
} | ||
|
||
var log *zap.Logger | ||
v := r.Context().Value(CtxLoggerKey) | ||
if v != nil { | ||
var ok bool | ||
log, ok = v.(*zap.Logger) | ||
if !ok { | ||
panic("cannot get derived request id logger from context object") | ||
} | ||
// log with the request_id scoped logger | ||
log.Error(fmt.Sprintf("%s request error", protocol), | ||
zap.String("method", r.Method), | ||
zap.String("uri", r.RequestURI), | ||
zap.Bool("tls", r.TLS != nil), | ||
zap.String("protocol", r.Proto), | ||
zap.String("host", r.Host), | ||
zap.String("remote_addr", r.RemoteAddr), | ||
zap.String("error", fmt.Sprintf("%+v", err)), | ||
) | ||
} else { | ||
// log with the logger attached to middleware struct if | ||
// cannot find request_id scoped logger | ||
m.Log.Error(fmt.Sprintf("%s request error", protocol), | ||
zap.String("method", r.Method), | ||
zap.String("uri", r.RequestURI), | ||
zap.Bool("tls", r.TLS != nil), | ||
zap.String("protocol", r.Proto), | ||
zap.String("host", r.Host), | ||
zap.String("remote_addr", r.RemoteAddr), | ||
zap.String("error", fmt.Sprintf("%+v", err)), | ||
) | ||
} | ||
|
||
// Return a http 500 with the HTTP body of "Internal Server Error" | ||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | ||
} | ||
}() | ||
|
||
next.ServeHTTP(w, r) | ||
} | ||
|
||
return http.HandlerFunc(fn) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
Copyright (c) 2016 The ABCWeb Authors. All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are | ||
met: | ||
|
||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above | ||
copyright notice, this list of conditions and the following disclaimer | ||
in the documentation and/or other materials provided with the | ||
distribution. | ||
* Neither the name of VolatileTech nor the names of its | ||
contributors may be used to endorse or promote products derived from | ||
this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package abcrender | ||
|
||
import ( | ||
"io" | ||
|
||
"github.com/unrolled/render" | ||
) | ||
|
||
// Renderer implements template rendering methods. | ||
// If you'd like to create a renderer that uses a different rendering engine | ||
// opposed to standard text/templates or html/templates you can do so by | ||
// implementing this interface. | ||
type Renderer interface { | ||
Data(w io.Writer, status int, v []byte) error | ||
JSON(w io.Writer, status int, v interface{}) error | ||
Text(w io.Writer, status int, v string) error | ||
// HTML renders a HTML template. Example: | ||
// Assumes you have a template in ./templates called "home.tmpl" | ||
// $ mkdir -p templates && echo "<h1>Hello {{.}}</h1>" > templates/home.tmpl | ||
// HTML(w, http.StatusOK, "home", "World") | ||
HTML(w io.Writer, status int, name string, binding interface{}) error | ||
// HTMLWithLayout renders a HTML template using a different layout to the | ||
// one specified in your renderer's configuration. Example: | ||
// Example: HTMLWithLayout(w, http.StatusOK, "home", "World", "layout") | ||
HTMLWithLayout(w io.Writer, status int, name string, binding interface{}, layout string) error | ||
} | ||
|
||
// Render implements the HTML and HTMLWithLayout functions on the Renderer | ||
// interface and imbeds the unrolled Render type to satisfy the rest of the interface. | ||
// The custom HTML/HTMLWithLayout implementation is required due to the Render | ||
// HTML function having a package-specific type for the layout string (Render.HTMLOptions) | ||
type Render struct { | ||
*render.Render | ||
} | ||
|
||
// HTML renders a HTML template by calling unrolled Render package's HTML function | ||
func (r *Render) HTML(w io.Writer, status int, name string, binding interface{}) error { | ||
return r.Render.HTML(w, status, name, binding) | ||
} | ||
|
||
// HTMLWithLayout renders a HTML template using a specified layout file by calling | ||
// unrolled Render package's HTML function with a HTMLOptions argument | ||
func (r *Render) HTMLWithLayout(w io.Writer, status int, name string, binding interface{}, layout string) error { | ||
return r.Render.HTML(w, status, name, binding, render.HTMLOptions{Layout: layout}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
Copyright (c) 2016 The ABCWeb Authors. All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are | ||
met: | ||
|
||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above | ||
copyright notice, this list of conditions and the following disclaimer | ||
in the documentation and/or other materials provided with the | ||
distribution. | ||
* Neither the name of VolatileTech nor the names of its | ||
contributors may be used to endorse or promote products derived from | ||
this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Oops, something went wrong.