** 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:**** pre>** syntax: fantom** ** 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)** }** }** <pre** ** `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: ** ** syntax: fantom ** @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:** ** syntax: fantom ** @Contribute { serviceType=RequestLoggers# }** Void contributeRequestLoggers(Configuration config) {** config["myLogger"] = config.build(MyRequestLogger#)** }** constmixin RequestLogger {** Called *before* all request processing.virtual Void logIncoming(){}** Called *after* all request processing.virtual Void logOutgoing(){}}