const mixinafBedSheet::RequestLogger
afBedSheet::RequestLogger
Implement to create HTTP request / response loggers.
logIncoming() is called once per request before any request processing, and logOutgoing() is called after all processing has finished. Here's an example basic logger:
using afIoc
using afConcurrent
const class BasicRequestLogger : RequestLogger {
@Inject private const HttpRequest httpReq
@Inject private const HttpResponse httpRes
@Inject private const LocalRef startTimeRef
@Inject private const Log log
new make(|This|in) { in(this) }
override Void logIncoming() {
startTimeRef.val = Duration.now
}
override Void logOutgoing() {
timeTaken := Duration.now.minus(startTimeRef.val).toLocale
msg := "${httpReq.httpMethod} ${httpReq.url.encode} ${httpRes.statusCode} in ${timeTaken}"
log.info(msg)
}
}
Middleware could be used to log HTTP requests, but Middleware is wrapped in an error handling mechanism. So if an error handler changes response, this may not be seen by the logger.
Requestloggers are invoked outside of error handling, so the response seen by the logger IS the response sent to the browser. The caveat to this, is that ALL errors raised by RequestLoggers are simply logged and swallowed. So unless you're monitoring the server logs, you're unlikely to see any logger problems.
IoC Configuration
Instances of RequestLogger should be contributed to the RequestLoggers service. Example:
@Contribute { serviceType=RequestLoggers# }
Void contributeRequestLoggers(Configuration config) {
config.add(MyRequestLogger())
}
A config key is not required, but it's polite to provide one so others may remove it, or order their loggers before or after yours. You can also use IoC to autobuild your logger should it have any dependencies:
@Contribute { serviceType=RequestLoggers# }
Void contributeRequestLoggers(Configuration config) {
config["myLogger"] = config.build(MyRequestLogger#)
}