@ -6,7 +6,6 @@ import (
"net/http"
"net/http"
"time"
"time"
"github.com/gin-gonic/contrib/ginrus"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin"
@ -27,6 +26,63 @@ type Handler struct {
// DoNotPrivateKeyChecking is used for testing
// DoNotPrivateKeyChecking is used for testing
var DoNotPrivateKeyChecking = false
var DoNotPrivateKeyChecking = false
type loggerEntryWithFields interface {
WithFields ( fields logrus . Fields ) * logrus . Entry
}
// Ginrus returns a gin.HandlerFunc (middleware) that logs requests using logrus.
//
// Requests with errors are logged using logrus.Error().
// Requests without errors are logged using logrus.Info().
//
// It receives:
// 1. A time package format string (e.g. time.RFC3339).
// 2. A boolean stating whether to use UTC time zone or local.
// 3. Optionally, a list of paths to skip logging for (this is why
// we are not using upstream github.com/gin-gonic/contrib/ginrus)
func Ginrus ( logger loggerEntryWithFields , timeFormat string , utc bool , notlogged ... string ) gin . HandlerFunc {
var skip map [ string ] struct { }
if length := len ( notlogged ) ; length > 0 {
skip = make ( map [ string ] struct { } , length )
for _ , path := range notlogged {
skip [ path ] = struct { } { }
}
}
return func ( c * gin . Context ) {
start := time . Now ( )
// some evil middlewares modify this values
path := c . Request . URL . Path
c . Next ( )
// log only when path is not being skipped
if _ , ok := skip [ path ] ; ! ok {
end := time . Now ( )
latency := end . Sub ( start )
if utc {
end = end . UTC ( )
}
entry := logger . WithFields ( logrus . Fields {
"status" : c . Writer . Status ( ) ,
"method" : c . Request . Method ,
"path" : path ,
"ip" : c . ClientIP ( ) ,
"latency" : latency ,
"user-agent" : c . Request . UserAgent ( ) ,
"time" : end . Format ( timeFormat ) ,
} )
if len ( c . Errors ) > 0 {
// Append error field if this is an erroneous request.
entry . Error ( c . Errors . String ( ) )
} else {
entry . Info ( )
}
}
}
}
// New initializes the http handlers
// New initializes the http handlers
func New ( store stores . Store ) ( * Handler , error ) {
func New ( store stores . Store ) ( * Handler , error ) {
if ! util . GetConfig ( ) . EnableDebugMode {
if ! util . GetConfig ( ) . EnableDebugMode {
@ -78,7 +134,12 @@ func (h *Handler) setHandlers() error {
if err := h . addTemplatesFromFS ( [ ] string { "token.html" , "protected.html" } ) ; err != nil {
if err := h . addTemplatesFromFS ( [ ] string { "token.html" , "protected.html" } ) ; err != nil {
return errors . Wrap ( err , "could not add templates from FS" )
return errors . Wrap ( err , "could not add templates from FS" )
}
}
h . engine . Use ( ginrus . Ginrus ( logrus . StandardLogger ( ) , time . RFC3339 , false ) )
if ! util . GetConfig ( ) . EnableDebugMode {
// if we are not in debug mode, do not log healthchecks
h . engine . Use ( Ginrus ( logrus . StandardLogger ( ) , time . RFC3339 , false , "/ok" ) )
} else {
h . engine . Use ( Ginrus ( logrus . StandardLogger ( ) , time . RFC3339 , false ) )
}
protected := h . engine . Group ( "/api/v1/protected" )
protected := h . engine . Group ( "/api/v1/protected" )
if util . GetConfig ( ) . AuthBackend == "oauth" {
if util . GetConfig ( ) . AuthBackend == "oauth" {
logrus . Info ( "Using OAuth auth backend" )
logrus . Info ( "Using OAuth auth backend" )
@ -96,6 +157,7 @@ func (h *Handler) setHandlers() error {
h . engine . GET ( "/api/v1/info" , h . handleInfo )
h . engine . GET ( "/api/v1/info" , h . handleInfo )
h . engine . GET ( "/d/:id/:hash" , h . handleDelete )
h . engine . GET ( "/d/:id/:hash" , h . handleDelete )
h . engine . GET ( "/ok" , h . handleHealthcheck )
// Handling the shorted URLs, if no one exists, it checks
// Handling the shorted URLs, if no one exists, it checks
// in the filesystem and sets headers for caching
// in the filesystem and sets headers for caching