Skip to content

Commit 9f5d314

Browse files
committed
revel#1055 logger fix and improvements
1 parent 9362851 commit 9f5d314

File tree

4 files changed

+159
-40
lines changed

4 files changed

+159
-40
lines changed

revel.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,18 @@ var (
8585
"error": gocolorize.NewColor("red"),
8686
}
8787

88-
error_log = revelLogs{c: colors["error"], w: os.Stderr}
88+
errorLog = revelLogs{c: colors["error"], w: os.Stderr}
8989

9090
// Loggers
9191
TRACE = log.New(ioutil.Discard, "TRACE ", log.Ldate|log.Ltime|log.Lshortfile)
92-
INFO = log.New(ioutil.Discard, "", 0)
92+
INFO = log.New(ioutil.Discard, "INFO ", log.Ldate|log.Ltime|log.Lshortfile)
9393
WARN = log.New(ioutil.Discard, "WARN ", log.Ldate|log.Ltime|log.Lshortfile)
94-
ERROR = log.New(&error_log, "ERROR ", log.Ldate|log.Ltime|log.Lshortfile)
94+
ERROR = log.New(&errorLog, "ERROR ", log.Ldate|log.Ltime|log.Lshortfile)
95+
96+
// Revel request access log, not exposed from package.
97+
// However output settings can be controlled from app.conf
98+
requestLog = log.New(ioutil.Discard, "", 0)
99+
requestLogTimeFormat = "2006/01/02 15:04:05.000"
95100

96101
Initialized bool
97102

@@ -205,6 +210,10 @@ func Init(mode, importPath, srcPath string) {
205210
WARN = getLogger("warn")
206211
ERROR = getLogger("error")
207212

213+
// Revel request access logger, not exposed from package.
214+
// However output settings can be controlled from app.conf
215+
requestLog = getLogger("request")
216+
208217
loadModules()
209218

210219
Initialized = true
@@ -227,24 +236,16 @@ func getLogger(name string) *log.Logger {
227236
case "stderr":
228237
newlog = revelLogs{c: colors[name], w: os.Stderr}
229238
logger = newLogger(&newlog)
239+
case "off":
240+
return newLogger(ioutil.Discard)
230241
default:
231-
if output == "off" {
232-
output = os.DevNull
233-
}
234-
235242
if !filepath.IsAbs(output) {
236-
output = BasePath + string(filepath.Separator) + output
237-
}
243+
output = filepath.Join(BasePath, output)
244+
}
238245

239246
logPath := filepath.Dir(output)
240-
if _, err := os.Stat(logPath); err != nil {
241-
if os.IsNotExist(err) {
242-
if err := os.MkdirAll(logPath, 0755); err != nil {
243-
log.Fatalln("Failed to create log directory", output, ":", err)
244-
}
245-
} else {
246-
log.Fatalln("Failed to stat log directory", output, ":", err)
247-
}
247+
if err := createDir(logPath); err != nil {
248+
log.Fatalln(err)
248249
}
249250

250251
file, err := os.OpenFile(output, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
@@ -254,6 +255,11 @@ func getLogger(name string) *log.Logger {
254255
logger = newLogger(file)
255256
}
256257

258+
if strings.EqualFold(name, "request") {
259+
logger.SetFlags(0)
260+
return logger
261+
}
262+
257263
// Set the prefix / flags.
258264
flags, found := Config.Int("log." + name + ".flags")
259265
if found {

server.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ func handle(w http.ResponseWriter, r *http.Request) {
4141
}
4242

4343
func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn) {
44-
t1 := time.Now()
45-
INFO.Println("\nStarted", r.Method, r.URL.String(), "at", time.Now().Format(time.RFC3339), "from", r.RemoteAddr)
44+
// For now this okay to put logger here for all the requests
45+
// However, it's best to have logging handler at server entry level
46+
start := time.Now()
4647

4748
var (
4849
req = NewRequest(r)
@@ -62,8 +63,18 @@ func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn)
6263
w.Close()
6364
}
6465

65-
duration := fmt.Sprintf("%.2fms", float64(time.Since(t1).Nanoseconds()/1e4)/100.0)
66-
INFO.Println("Completed", c.Response.Status, "in", duration, "\n")
66+
// Revel request access log format
67+
// RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath
68+
// Sample format:
69+
// 2016/05/25 17:46:37.112 127.0.0.1 200 270.157µs GET /
70+
requestLog.Printf("%v %v %v %10v %v %v",
71+
start.Format(requestLogTimeFormat),
72+
ClientIP(r),
73+
c.Response.Status,
74+
time.Since(start),
75+
r.Method,
76+
r.URL.Path,
77+
)
6778
}
6879

6980
// InitServer intializes the server and returns the handler

skeleton/conf/app.conf.template

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ app.name = {{ .AppName }}
1515
# into your application
1616
app.secret = {{ .Secret }}
1717

18+
# Revel running behind proxy like nginx, haproxy, etc
19+
app.behind.proxy = false
20+
1821

1922
# The IP address on which to listen.
2023
http.addr =
@@ -74,10 +77,12 @@ results.chunked = false
7477

7578

7679
# Prefixes for each log message line
77-
# log.trace.prefix = "TRACE "
78-
# log.warn.prefix = "WARN "
79-
# log.error.prefix = "ERROR "
80-
# log.info.prefix = ""
80+
# User can override these prefix values within any section
81+
# For e.g: [dev], [prod], etc
82+
log.trace.prefix = "TRACE "
83+
log.info.prefix = "INFO "
84+
log.warn.prefix = "WARN "
85+
log.error.prefix = "ERROR "
8186

8287

8388
# The default language of this application.
@@ -136,6 +141,27 @@ log.warn.output = stderr
136141
log.error.output = stderr
137142

138143

144+
# Revel log flags. Possible flags defined by the Go `log` package,
145+
# please refer https://golang.org/pkg/log/#pkg-constants
146+
# Go log is "Bits or'ed together to control what's printed"
147+
# Examples:
148+
# 0 => just log the message, turn off the flags
149+
# 3 => log.LstdFlags (log.Ldate|log.Ltime)
150+
# 19 => log.Ldate|log.Ltime|log.Lshortfile
151+
# 23 => log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile
152+
log.trace.flags = 19
153+
log.info.flags = 19
154+
log.warn.flags = 19
155+
log.error.flags = 19
156+
157+
158+
# Revel request access log
159+
# Access log line format:
160+
# RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath
161+
# Sample format:
162+
# 2016/05/25 17:46:37.112 127.0.0.1 200 270.157µs GET /
163+
log.request.output = stderr
164+
139165

140166
################################################################################
141167
# Section: prod
@@ -157,6 +183,29 @@ module.testrunner =
157183

158184

159185
log.trace.output = off
160-
log.info.output = %(app.name)s.log
161-
log.warn.output = %(app.name)s.log
162-
log.error.output = %(app.name)s.log
186+
log.info.output = off
187+
log.warn.output = log/%(app.name)s.log
188+
log.error.output = log/%(app.name)s.log
189+
190+
# Revel log flags. Possible flags defined by the Go `log` package,
191+
# please refer https://golang.org/pkg/log/#pkg-constants
192+
# Go log is "Bits or'ed together to control what's printed"
193+
# Examples:
194+
# 0 => just log the message, turn off the flags
195+
# 3 => log.LstdFlags (log.Ldate|log.Ltime)
196+
# 19 => log.Ldate|log.Ltime|log.Lshortfile
197+
# 23 => log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile
198+
log.trace.flags = 3
199+
log.info.flags = 3
200+
log.warn.flags = 3
201+
log.error.flags = 3
202+
203+
204+
# Revel request access log
205+
# Access log line format:
206+
# RequestStartTime ClientIP ResponseStatus RequestLatency HTTPMethod URLPath
207+
# Sample format:
208+
# 2016/05/25 17:46:37.112 127.0.0.1 200 270.157µs GET /
209+
# Example:
210+
# log.request.output = %(app.name)s-request.log
211+
log.request.output = off

util.go

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package revel
22

33
import (
44
"bytes"
5+
"fmt"
56
"io"
67
"io/ioutil"
8+
"net"
9+
"net/http"
710
"net/url"
811
"os"
912
"reflect"
@@ -13,6 +16,18 @@ import (
1316
"github.com/revel/revel/config"
1417
)
1518

19+
const (
20+
DefaultFileContentType = "application/octet-stream"
21+
)
22+
23+
var (
24+
cookieKeyValueParser = regexp.MustCompile("\x00([^:]*):([^\x00]*)\x00")
25+
hdrForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
26+
hdrRealIP = http.CanonicalHeaderKey("X-Real-Ip")
27+
28+
mimeConfig *config.Context
29+
)
30+
1631
// Add some more methods to the default Template.
1732
type ExecutableTemplate interface {
1833
Execute(io.Writer, interface{}) error
@@ -65,10 +80,6 @@ func FindMethod(recvType reflect.Type, funcVal reflect.Value) *reflect.Method {
6580
return nil
6681
}
6782

68-
var (
69-
cookieKeyValueParser = regexp.MustCompile("\x00([^:]*):([^\x00]*)\x00")
70-
)
71-
7283
// Takes the raw (escaped) cookie value and parses out key values.
7384
func ParseKeyValueCookie(val string, cb func(key, val string)) {
7485
val, _ = url.QueryUnescape(val)
@@ -79,10 +90,6 @@ func ParseKeyValueCookie(val string, cb func(key, val string)) {
7990
}
8091
}
8192

82-
const DefaultFileContentType = "application/octet-stream"
83-
84-
var mimeConfig *config.Context
85-
8693
// Load mime-types.conf on init.
8794
func LoadMimeConfig() {
8895
var err error
@@ -92,10 +99,6 @@ func LoadMimeConfig() {
9299
}
93100
}
94101

95-
func init() {
96-
OnAppStart(LoadMimeConfig)
97-
}
98-
99102
// Returns a MIME content type based on the filename's extension.
100103
// If no appropriate one is found, returns "application/octet-stream" by default.
101104
// Additionally, specifies the charset as UTF-8 for text/* types.
@@ -172,3 +175,53 @@ func Equal(a, b interface{}) bool {
172175
}
173176
return false
174177
}
178+
179+
// ClientIP method returns client IP address from HTTP request.
180+
//
181+
// Note: Set property "app.behind.proxy" to true only if Revel is running
182+
// behind proxy like nginx, haproxy, apache, etc. Otherwise
183+
// you may get inaccurate Client IP address. Revel parses the
184+
// IP address in the order of X-Forwarded-For, X-Real-IP.
185+
//
186+
// By default revel will get http.Request's RemoteAddr
187+
func ClientIP(r *http.Request) string {
188+
if Config.BoolDefault("app.behind.proxy", false) {
189+
// Header X-Forwarded-For
190+
if fwdFor := strings.TrimSpace(r.Header.Get(hdrForwardedFor)); fwdFor != "" {
191+
index := strings.Index(fwdFor, ",")
192+
if index == -1 {
193+
return fwdFor
194+
}
195+
return fwdFor[:index]
196+
}
197+
198+
// Header X-Real-Ip
199+
if realIP := strings.TrimSpace(r.Header.Get(hdrRealIP)); realIP != "" {
200+
return realIP
201+
}
202+
}
203+
204+
if remoteAddr, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
205+
return remoteAddr
206+
}
207+
208+
return ""
209+
}
210+
211+
// createDir method creates nested directories if not exists
212+
func createDir(path string) error {
213+
if _, err := os.Stat(path); err != nil {
214+
if os.IsNotExist(err) {
215+
if err = os.MkdirAll(path, 0755); err != nil {
216+
return fmt.Errorf("Failed to create directory '%v': %v", path, err)
217+
}
218+
} else {
219+
return fmt.Errorf("Failed to create directory '%v': %v", path, err)
220+
}
221+
}
222+
return nil
223+
}
224+
225+
func init() {
226+
OnAppStart(LoadMimeConfig)
227+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy