diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample
index aebcfafa96..31fed0c022 100644
--- a/custom/conf/app.ini.sample
+++ b/custom/conf/app.ini.sample
@@ -497,6 +497,7 @@ MODE = console
 BUFFER_LEN = 10000
 ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
 LEVEL = Trace
+REDIRECT_MACARON_LOG = false
 
 ; For "console" mode only
 [log.console]
diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
index 8254316716..89eb9af78c 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
@@ -279,6 +279,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
 - `ROOT_PATH`: **\<empty\>**: Root path for log files.
 - `MODE`: **console**: Logging mode. For multiple modes, use a comma to separate values.
 - `LEVEL`: **Trace**: General log level. \[Trace, Debug, Info, Warn, Error, Critical\]
+- `REDIRECT_MACARON_LOG`: **false**: Redirects the Macaron log to the Gitea logger.
 
 ## Cron (`cron`)
 
diff --git a/modules/log/log.go b/modules/log/log.go
index 36038d3d0c..98a8014b51 100644
--- a/modules/log/log.go
+++ b/modules/log/log.go
@@ -154,6 +154,48 @@ type LoggerInterface interface {
 
 type loggerType func() LoggerInterface
 
+// LoggerAsWriter is a io.Writer shim around the gitea log
+type LoggerAsWriter struct {
+	level int
+}
+
+// NewLoggerAsWriter creates a Writer representation of the logger with setable log level
+func NewLoggerAsWriter(level string) *LoggerAsWriter {
+	l := &LoggerAsWriter{}
+	switch strings.ToUpper(level) {
+	case "TRACE":
+		l.level = TRACE
+	case "DEBUG":
+		l.level = DEBUG
+	case "INFO":
+		l.level = INFO
+	case "WARN":
+		l.level = WARN
+	case "ERROR":
+		l.level = ERROR
+	case "CRITICAL":
+		l.level = CRITICAL
+	case "FATAL":
+		l.level = FATAL
+	default:
+		l.level = INFO
+	}
+	return l
+}
+
+// Write implements the io.Writer interface to allow spoofing of macaron
+func (l *LoggerAsWriter) Write(p []byte) (int, error) {
+	l.Log(string(p))
+	return len(p), nil
+}
+
+// Log takes a given string and logs it at the set log-level
+func (l *LoggerAsWriter) Log(msg string) {
+	for _, logger := range loggers {
+		logger.writerMsg(0, l.level, msg)
+	}
+}
+
 var adapters = make(map[string]loggerType)
 
 // Register registers given logger provider to adapters.
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 77f0725d00..0859b81c40 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -393,10 +393,11 @@ var (
 	LibravatarService     *libravatar.Libravatar
 
 	// Log settings
-	LogLevel    string
-	LogRootPath string
-	LogModes    []string
-	LogConfigs  []string
+	LogLevel           string
+	LogRootPath        string
+	LogModes           []string
+	LogConfigs         []string
+	RedirectMacaronLog bool
 
 	// Attachment settings
 	AttachmentPath         string
@@ -767,6 +768,7 @@ func NewContext() {
 	LogLevel = getLogLevel("log", "LEVEL", "Info")
 	LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log"))
 	forcePathSeparator(LogRootPath)
+	RedirectMacaronLog = Cfg.Section("log").Key("REDIRECT_MACARON_LOG").MustBool(false)
 
 	sec := Cfg.Section("server")
 	AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea")
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 48d1dc6a7f..58274626c0 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -6,6 +6,7 @@ package routes
 
 import (
 	"encoding/gob"
+	"fmt"
 	"net/http"
 	"os"
 	"path"
@@ -45,12 +46,34 @@ import (
 	macaron "gopkg.in/macaron.v1"
 )
 
+func giteaLogger(l *log.LoggerAsWriter) macaron.Handler {
+	return func(ctx *macaron.Context) {
+		start := time.Now()
+
+		l.Log(fmt.Sprintf("[Macaron] Started %s %s for %s", ctx.Req.Method, ctx.Req.RequestURI, ctx.RemoteAddr()))
+
+		ctx.Next()
+
+		rw := ctx.Resp.(macaron.ResponseWriter)
+		l.Log(fmt.Sprintf("[Macaron] Completed %s %s %v %s in %v", ctx.Req.Method, ctx.Req.RequestURI, rw.Status(), http.StatusText(rw.Status()), time.Since(start)))
+	}
+}
+
 // NewMacaron initializes Macaron instance.
 func NewMacaron() *macaron.Macaron {
 	gob.Register(&u2f.Challenge{})
-	m := macaron.New()
-	if !setting.DisableRouterLog {
-		m.Use(macaron.Logger())
+	var m *macaron.Macaron
+	if setting.RedirectMacaronLog {
+		loggerAsWriter := log.NewLoggerAsWriter("INFO")
+		m = macaron.NewWithLogger(loggerAsWriter)
+		if !setting.DisableRouterLog {
+			m.Use(giteaLogger(loggerAsWriter))
+		}
+	} else {
+		m = macaron.New()
+		if !setting.DisableRouterLog {
+			m.Use(macaron.Logger())
+		}
 	}
 	m.Use(macaron.Recovery())
 	if setting.EnableGzip {