When logging in Revel you should use the controller.LogIf you have services running in the background you should use the revel.AppLog
Internally Revel uses log15 to do the core work, moreinformation about the log handlers can be found there.
Below is the logger interface.
MultiLoggerinterface{// New returns a new Logger that has this logger's context plus the given contextNew(ctx...interface{})MultiLogger// SetHandler updates the logger to write records to the specified handler.SetHandler(hLogHandler)Debug(msgstring,ctx...interface{})Debugf(msgstring,params...interface{})Info(msgstring,ctx...interface{})Infof(msgstring,params...interface{})Warn(msgstring,ctx...interface{})Warnf(msgstring,params...interface{})Error(msgstring,ctx...interface{})Errorf(msgstring,params...interface{})Crit(msgstring,ctx...interface{})Critf(msgstring,params...interface{})//// Logs a message as an Crit and exitsFatal(msgstring,ctx...interface{})Fatalf(msgstring,params...interface{})//// Logs a message as an Crit and panicsPanic(msgstring,ctx...interface{})Panicf(msgstring,params...interface{})}
Usage
Log Contexts
Logging using these Debug,Info,Warn,Error,Crit
methods will expect the message values in key value pairs. For example revel.AppLog.Debug("Hi there")
is fine revel.AppLog.Debug("Hi there", 25)
will panic (only passed one argument for the context). revel.AppLog.Debug("Hi there","age",25,"sex","yes","state",254)
is fine. This will produce a log message that includes the context age,sex,state like .
INFO2017/08/0222:31:41test.go:168:HiThereage=25sex=yesstate=254
or in json like
{"caller":"test.go:168","lvl":3,"t":"2017-08-02T22:34:08.303112145-07:00","age":25,"sex":"yes","state":254}
If you want you can fork a new log from the control logger to continue using in your code or to pass to the model - consider this
func(c*FooController)Edit(idint)revel.Result{log:=c.Log.New("id",id)log.Debug("Reading the output")output,err:=model.Load(log,id)iferr!=nil{log.Errorf("Failed to load :%s",err.Error())}...}
Could produce the following output (if an error occurred)
INFO 22:31:41 app test.go:168: Reading the output id=25
ERROR 22:31:41 app test.go:168: Failed to load: Not Found id=25
Log formats
Logging using these Debugf,Infof,Warnf,Errorf,Critf
methods allows you to output a formatted string for the message. likerevel.AppLog.Debugf("Hi %s ", "Grace")
. Only existing contexts will be applied to them. For example look at the log.Errorf below
func(c*FooController)Edit(idint)revel.Result{log:=c.Log.New("id",id)log.Debug("Reading the output")output,err:=model.Load(log,id)iferr!=nil{log.Errorf("Failed to load :%s",err.Error())}...}
Could produce the following output (if an error occurred)
INFO 22:31:41 app test.go:168: Reading the output id=25
ERROR 22:31:41 app test.go:168: Failed to load: Not Found id=25
App.conf
Configuration examples1) All log messages that match the filter module=app
to stdout, all messages that are error messages send to stderr. Order is significant here, the second statement log.error.output = stderr
replaces the error handler specified by the log.all
of the first line.
log.all.filter.module.app = stdout # Log all loggers for the application to the stdout
log.error.output = stderr # Log all loggers for Revel errors to the stderr
2) Existing configurations will work as well, you can even expand on them
log.debug.output = stdout # Outputs to the stdout
log.info.output = myloghandler # Outputs to the function in LogFunctionMap
log.warn.output = stderr # Outputs to the stderr
log.request.output = myloghandler
log.error.output = somefile/log.json # Outputs to the file specified file using JSON format
log.error.filter.module.revel = stdout # Filters based on context module.revel, outputs to stdout
log.error.filter.module.revel.context.route = stdout # Filters based on context module.revel, context route outputs to stdout
log.critical.output = stderr # Outputs to the stderr
To summarize the log output can be a named function contained in logger.LogFunctionMap
. If that function does not exist then it is assumed to be a file name, the file name extension will choose the output format. The stderr
and stdout
are two predefined functions which may be overriden if desired
Filtered logging
A log filter can specify a series of key, values that will only be logged to if ALL the keys and values match a context in the log. For example the following will log at level errorto the stdout if the log message contains the context module=revel
log.error.filter.module.revel = stdout
Filters are additive, they do not replace existing error handlers - for example in the following error messages that are logged with the context of module=revel
will be sent to thestdout
and to the json file
log.all.output = stdout
log.error.filter.module.revel = /var/log/revel/revel.json
Filters may be empty so that you can make use the additive feature, the following sends all errors to both stdout
and all-errors.json
log.all.output = stdout
log.error.filter = /var/log/revel/all-errors.json
Inverse filters can be applied by using nfilter for example, consider the following
log.all.filter.module.app = stdout # Log all loggers for the application to the stdout
log.error.output = stderr # Log all errors to stderr
In this case any application error would end up logging to both stdout and stderr - which in some cases (like output to a file) would be useful but if you do not want to send duplicate messages to the console you can do the following
log.all.filter.module.app = stdout # Log all loggers for the application to the stdout
log.error.nfilter.module.app = stderr # Everything else that logs an error to stderr
The log.error.nfilter.module.app
is the inversion of the first filter, with the type of error.
File logging
For file logging revel uses lumberjack.Logger to stream the output to file. The following configuration options can be set
log.compressBackups = true # Compress the backups after rotation default true
log.maxsize = 1024 # The max file size before rotation in MB degault 10G
log.maxagelog.maxage= 14 # The max age of the file before rotation occurs default 14 days
log.maxbackups = 14 # The max number of old log files to keep default 14
These are global options, you can however apply unique options by Customizing Log Handling
More configuration options
log.colorize = true # Turns off colorization for console output
log.smallDate = true # Outputs just the time for the terminal output
Customizing Log Handling
The following code adds a new output called stdoutjson
logger.LogFunctionMap["stdoutjson"]=func(c*logger.CompositeMultiHandler,options*logger.LogOptions){// Set the json formatter to os.Stdout, replace any existing handlers for the level specifiedc.SetJson(os.Stdout,options)}logger.LogFunctionMap["longtermstorage"]=func(c*logger.CompositeMultiHandler,options*logger.LogOptions){options.SetExtendedOptions("maxAgeDays",30,"maxSizeMB",1024*10,"maxBackups",50)c.SetJsonFile("/var/log/revel/longterm.json",options)}
This setting in app.conf
would activate the above logger for all log messages of level Warnand error messages from the module=revel
log.warn.output = stdoutjson
log.error.filter.module.revel = longtermstorage
It is important to note that your logger function may be called with a nil
options.Ctx
(this is the revel.Config
).
The special cases
log.request.output assigns a handler for messages which are on the info channel and have the section=requestlog assigned to them. If log.request.output is not specified then messages willbe logged directly to the same handler handling the info log level.
log.trace usage in initialization files is deprecated and replace by log.debug
- If log.critical is not specified and log.error has been. Then the error handler will receive the critical messages as well
Deprecated Logs
The following loggers are deprecated, the will continue to function but will output something like this INFO 22:16:10 app harness.go LOG DEPRECATED Listening on :9000 module=app section=deprecated
revel.TRACErevel.INFOrevel.WARNrevel.ERROR
Internal structure
Revel provides a single root logger called revel.RootLog. The logger is forked into the following loggers
- revel.RevelLog Contains context of module=revel
- revel.AppLog Contains context of module=app
module.Log on Startup of revel, it contains the context of module=modulename.
revel.AppLog is forked to create a logger forcontroller.Log A new instance is created on every request, and contains context information like, the source ip, request path and request method. If the controller handling the response is from a module it will be forked from module.Log
Request logger
Sample format: terminal format
log.request.output = stdout
be logged directly to the same handler handling the info
log level.
INFO 2017/08/02 22:31:41 server-engine.go:168: Request Stats ip=::1 path=/public/img/favicon.png method=GET action=Static.Serve namespace=static\\ start=2017/08/02 22:31:41 status=200 duration_seconds=0.0007656
JSON Format
log.request.output = /var/log/revel/requestlog.json
{"action":"Static.Serve","caller":"server-engine.go:168","duration_seconds":0.00058336,"ip":"::1","lvl":3,
"method":"GET","msg":"Request Stats","namespace":"static\\","path":"/public/img/favicon.png",
"start":"2017-08-02T22:34:08-0700","status":200,"t":"2017-08-02T22:34:08.303112145-07:00"}
- Issues tagged with log
Module Logs
To fetch a logger initialized for a module you can use the revel.RegisterModuleInit
like below
varmoduleLoggerlogger.MultiLoggerfuncinit(){revel.RegisterModuleInit(func(module*revel.Module){moduleLogger=module.LogmoduleLogger.Debug("Assigned Logger")})}
The callback
registered in the revel.RegisterModuleInit
is called before the revel.OnAppStart
functions are.