Thanks to visit codestin.com
Credit goes to github.com

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)