I have an Interceptor on Struts2, and I want for some pages to redirect to the ssl version of them.
Example: http://localhost/xhtml/path.do?ossesionid=value1 to https://localhost/xhtml/path.do?ossesionid=value1
For doing this I created a Interceptor that does this:
public String intercept(ActionInvocation invocation) throws Exception {
// initialize request and response
final ActionContext context = invocation.getInvocationContext();
final HttpServletRequest request = (HttpServletRequest) context
.get(StrutsStatics.HTTP_REQUEST);
final HttpServletResponse response = (HttpServletResponse) context
.get(StrutsStatics.HTTP_RESPONSE);
// check scheme
String scheme = request.getScheme().toLowerCase();
// check method
String method = request.getMethod().toUpperCase();
// If the action class uses the SSLProtected marker annotation, then see
// if we need to
// redirect to the SSL protected version of this page
if (invocation.getAction() instanceof SSLProtected) {
if (HTTP_GET.equals(method) && SCHEME_HTTP.equals(scheme)) {
// initialize https port
String httpsPortParam = request.getSession().getServletContext().getInitParameter(HTTP_PORT_PARAM);
int httpsPort = httpsPortParam == null ? HTTPS_PORT : Integer.parseInt(httpsPortParam);
response.setCharacterEncoding("UTF-8");
URI uri = new URI(SCHEME_HTTPS, null, request.getServerName(), httpsPort, response.encodeRedirectURL(request.getRequestURI()), request.getQueryString(), null);
log.debug("Going to SSL mode, redirecting to " + uri.toString());
response.sendRedirect(uri.toString());
return null;
}
}
My problem is that I expect this
https://localhost/xhtml/path.do?ossesionid=value1
and got
https://localhost/xhtml/path.do;jsessionid=value1?osessionid=value1
And I'm Completly lost! help anyone?
i strongly suggest you to use S2-SSL plugin which is more flexible and provides a much better support to handle switch from SSL to non-SSL and vice-versa.
regarding generation of Jsessionid,JSESSIONID cookie is created/sent when session is created. Session is created when your code calls request.getSession() or request.getSession(true) for the first time. If you just want get session.You have ways to disable the creation of Jsessionid
There are number of way you can disable the creation of this id, please refer to this discussion thread.
I am still not sure what is the problem you are facing with this session-id as it is a very common case in web applications
is-it-possible-to-disable-jsessionid-in-tomcat-servlet
Related
I have a scenario where I want to store session information across multiple sessions in Application # 2. We have two applications deployed on a tomcat server. Our use case is as follows:
A. Web Application # 1 makes a HTTP Post request to Application # 2 using a HTTP Rest Client. POST request contains a JSON http request body encapsulating the data to be send to Application # 2. The code block is as follows:
RestTemplate template = new RestTemplate();
final SearchCustomer customer = new SearchCustomer();
restTemplate.execute(
SEND_CUSTOMER_PROFILE, HttpMethod.POST,
new SearchRequestCallback(searchCustomer), null);
The request callback function is
static class SearchRequestCallback implements RequestCallback {
/**
* Write a JSON response to the request body.
*/
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
HttpHeaders httpHeaders = request.getHeaders();
List<MediaType> acceptableMediaTypes = new LinkedList<>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(acceptableMediaTypes);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
request.getBody().write(
new Gson().toJson(this.searchCustomer).getBytes(StandardCharsets.UTF_8.displayName()));
}
}
The second application has a Spring controller with the following set up
#Controller
public class SearchCustomerController {
/**
* Builds customer profile knowledge graph.
*
* <p>This is invoked as an synchronous request.
*/
#RequestMapping(value="/searchProfilePayload.go", method=RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
public void constructSearchCustomerProfileKnowledgeGraph(
#RequestBody final SearchCustomer customer, HttpServletRequest request) {
UserContext userContext =
(UserContext) request.getSession().getAttribute("userContext");
if (userContext == null) {
// Perform heavy operation to fetch user session.
userContext = UserContextHelper.getUserContext(request);
request.getSession("userContext", userContext)
}
userContext.setCustomerProfile(customer);
}
}
When I make a call to another URI within the application # 2 say via browser, I want it done in such as way that the session attributes are retained when making this call. Is there a way to do that?
I know about URL rewriting that stores JSESSIONIDin the cookie, but I don't think how you can set the value when making a rest call, and using the same JESSIONID to maintain session attributes.
Is there a better way to do this? These have no answers. I have looked at these links, but none seem to answer my question.
HTTP and Sessions
comparison of ways to maintain state
jraahhali is spot on.
Set the cookie header with the value of JSESSIONID=${sessionId} or use it directly in the url as per the URL rewriting link.
First step is to retrieve the JSESSIONID from the initial response (this will depend on how you decide to set the session id - URL or Cookies, lets assume by cookie for now)
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
HttpHeaders httpHeaders = request.getHeaders();
List<MediaType> acceptableMediaTypes = new LinkedList<>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
httpHeaders.setAccept(acceptableMediaTypes);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
request.getBody().write(
new Gson().toJson(this.searchCustomer).getBytes(StandardCharsets.UTF_8.displayName()));
ClientHttpResponse response = request.execute();
String sessionId = response.getHeaders().get(HttpHeaders.SET_COOKIE).split(":")[1].trim(); // I didnt test this, will prolly get a NPE :P
this.sessionId = sessionId;
}
Then in subsequent requests (ie from the app #1 or a browser or whatever)
if (this.sessionId != null && !this.sessionId.equals(""))
httpHeaders.set(HttpHeaders.COOKIE, "JSESSIONID=" + this.sessionId);
// ...
request.execute();
Note if you really want to use a browser as the other client then I would use the URL rewriting method for ease of use ...
I have developed a custom tag library in Java which I use in my web application.
I am not sure why but my doTag() is not setting up cookie at all. I have cleared my cache and restarted my computer as well. Here is the code:
public class UserVersionOfSite extends EvenSimplerTagSupport {
private static final Log logger = LogFactory.getLog(UserVersionOfSite.class);
private StringWriter sw = new StringWriter();
#Override
public void doTag() throws IOException, JspException {
getJspBody().invoke(sw); //get the tag body and put it in StringWriter object
//get request object to get cookie value
PageContext ctx = (PageContext)getJspContext();
HttpServletRequest httpServletRequest = (HttpServletRequest) ctx.getRequest();
HttpServletResponse httpServletResponse = (HttpServletResponse) ctx.getResponse();
if(httpServletRequest.getParameterMap().containsKey("show_full_site")) {
logger.debug("show_full_site ");
if(!checkIfCookieExists(httpServletRequest)){
Cookie cookie = new Cookie("SHOW_FULL_SITE",httpServletRequest.getParameter("show_full_site"));
cookie.setMaxAge(86400);
httpServletResponse.addCookie(cookie);
//write the tag output
if(!httpServletRequest.getParameter("show_full_site").equalsIgnoreCase("true")){
//write the response
getJspContext().getOut().println(sw.toString());
}
}else{
String cookieValueString = getCookieValue(httpServletRequest.getCookies(),"SHOW_FULL_SITE","false");
if(!cookieValueString.equalsIgnoreCase("true")){
//write the response
getJspContext().getOut().println(sw.toString());
}
}
}
}
#Override
public String getResult() throws IOException {
return "User version of site";
}
public String getCookieValue(Cookie[] cookies,
String cookieName,
String defaultValue) {
for(int i=0; i<cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookieName.equals(cookie.getName()))
return(cookie.getValue());
}
return(defaultValue);
}
public boolean checkIfCookieExists(HttpServletRequest httpServletRequest){
logger.debug("inside checkIfCookieExists()");
boolean cookiePresent = Arrays.asList(httpServletRequest.getCookies()).contains( "SHOW_FULL_SITE" );
return cookiePresent;
}
}
Even I tried adding the code without using if else statements but still no success. Is there any thing critical I am missing?
Any ideas guys??!!! I have checked the browser's setting as well, but there is nothing there which is blocking a creation of cookie!
I realise the horse has probably bolted by the time I'm posting this but, for the benefit of others stumbling across it, I think the problem may be related to the feature of RequestDispatcher highlighted in this question: unable to add a cookie included in JSP via jsp:include
your following line inside checkIfCookieExists() method is wrong:
Arrays.asList(httpServletRequest.getCookies()).contains( "SHOW_FULL_SITE" );
HttpServletRequest.getCookies() returns Cookie[]. You are wrapping it inside a List and checking for a string "SHOW_FULL_SITE" inside this.
Coming back to your question- how do you know cookie is not being set in the HTTP headers? Try using browser plugins like firebug to see the HTTP response headers coming from server. Also set the path of cookie before adding it to response e.g.
Cookie cookie = new Cookie("SHOW_FULL_SITE",httpServletRequest.getParameter("show_full_site"));
cookie.setMaxAge(86400);
cookie.setPath("/");
I have a login form that calls a certain LoginBean, which returns a ajax callback parameter indicating whether the credentials are valid or not.
The code is as follows:
public void doLogin() {
Authentication authenticationRequestToken =
new UsernamePasswordAuthenticationToken(user, password);
try {
Authentication authenticationResponseToken =
authenticationManager.authenticate(authenticationRequestToken);
SecurityContextHolder.getContext().
setAuthentication(authenticationResponseToken);
if (authenticationResponseToken.isAuthenticated()) {
RequestContext context = RequestContext.getCurrentInstance();
FacesMessage msg;
boolean loggedIn = true;
msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Welcome", user);
FacesContext.getCurrentInstance().addMessage(null, msg);
context.addCallbackParam("loggedIn", loggedIn);
}
} .authenticate(...) catches ...
// Here I need some code that continue whatever j_spring_security_check
// would do after authenticating.
}
The way my application is working now, after this call to doLogin(), the form is submited to j_spring_security_check, and then the authentication process takes place again, wasting previous work.
I'm trying to find a solution for this, any help is appreciated.
So, the bottom line is that I need something that would simulate what happens when j_spring_security_check is intercepted by the filters (or a way to force this interception explicitly), so the processing would take place behind the button, not after the form is submited.
It will be better if you just forward to the spring security authentication url instead of using the SecurityContextHolder yourself. Look at this code:
public String doLogin() throws ServletException, IOException {
FacesContext context = FacesContext.getCurrentInstance();
String springCheckUrl = this.buildSpringSecurityCheckUrl();
HttpServletRequest request = (HttpServletRequest) context
.getExternalContext().getRequest();
RequestDispatcher dispatcher = request
.getRequestDispatcher(springCheckUrl);
dispatcher.forward((ServletRequest) request,
(ServletResponse) context.getExternalContext.getResponse());
context.responseComplete();
return null;
}
private String buildSpringSecurityCheckUrl() {
StringBuilder springCheckUrl = new StringBuilder(
"/j_spring_security_check").append("?").append("j_username")
.append("=").append(this.userName.trim()).append("&")
.append("j_password").append("=")
.append(this.userPassword.trim());
return springCheckUrl.toString();
}
}
(Following up on this question: Getting raw XML response from Java web service client)
I've got a SOAP message handler that is able to get the raw XML of a web service response. I need to get this XML into the webservice client so I can perform some XSL transformations on the response before sending it on its way. I'm having trouble figuring out a good way to get data from a SOAP handler that catches incoming messages, and makes the raw XML available to a generated (from a WSDL) web service client. Any ideas if this is even feasible?
I've come up with something like this:
public class CustomSOAPHandler implements javax.xml.ws.handler.soap.SOAPHandler<javax.xml.ws.handler.soap.SOAPMessageContext>
{
private String myXML;
public String getMyXML()
{
return myXML;
}
...
public boolean handleMessage(SOAPMessageContext context)
{
...
myXML = this.getRawXML(context.getMessage());
}
//elsewhere in the application:
...
myService.doSomething(someRequest);
for (Handler h: ((BindingProvider)myService).getBinding().getHandlerChain())
{
if (h instanceof CustomSOAPHandler )
{
System.out.println("HandlerResult: "+ ((CustomSOAPHandler )h).getMyXML());
}
}
In very simple tests, this seems to work. But this solution feels somewhat like a cheap hack. I don't like setting the raw XML as a member of the chain handler, and I have a gut feeling this violates many other best practices. Does anyone have a more elegant way of doing this?
The two choices that seemed to work for me are both documented here. I didn't receive a response yet about whether using a ThreadLocal was fine or not, but I don't see why it shouldn't be.
My secoond method which was added to the original question was to go the route of the handler. While debugging the WS callout, I noticed that the invocationProperties map had the SOAP response as part of an internal packet structure within the responseContext object, but there appeared to be no way of getting to it. The ResponseContext was a set of name value pairs. However, when I read the source code for ResponseContext at this location, I saw that the code for the get method had a comment about returning null if it could not find an Application Scoped property, otherwise, it would read it from the packet invocationProperties, which seemed to be what I wanted. So I seached on how to set the scope on the key/value pair (Google: setting application-scope property for jaxws) that the context was introducing it low-and-behold, it was in the jax-ws spec that I referenced in the other thread.
I also did some reading about the Packet, https://jax-ws.java.net/nonav/jax-ws-20-fcs/arch/com/sun/xml/ws/api/message/Packet.html.
I hope this makes some sense for you. I was concerned that three wouldn't be anything to use JAXB against if the web service call resulted in a Soap FAULT, and I really wanted to log this packet, since it was being returned from a Payment Gateway which to this day has a number of undocumented results.
Good luck.
The solution was to use JAXB to convert the objects back to XML. I didn't really want to do this because it seems redundant to have the webservice client receive XML, convert it to a POJO, only to have that POJO converted back to XML, but it works.
Example of handler that passes out request / response message bodies:
public class MsgLogger implements SOAPHandler<SOAPMessageContext> {
public static String REQEST_BODY = "com.evil.request";
public static String RESPONSE_BODY = "com.evil.response";
#Override
public Set<QName> getHeaders() {
return null;
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
SOAPMessage msg = context.getMessage();
Boolean beforeRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(32_000);
context.getMessage().writeTo(baos);
String key = beforeRequest ? REQEST_BODY : RESPONSE_BODY;
context.put(key, baos.toString("UTF-8"));
context.setScope(key, MessageContext.Scope.APPLICATION);
} catch (SOAPException | IOException e) { }
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
#Override
public void close(MessageContext context) { }
}
To register handler and use preserved properties:
BindingProvider provider = (BindingProvider) port;
List<Handler> handlerChain = bindingProvider.getBinding().getHandlerChain();
handlerChain.add(new MsgLogger());
bindingProvider.getBinding().setHandlerChain(handlerChain);
Req req = ...;
Rsp rsp = port.serviceCall(req); // call WS Port
// Access saved message bodies:
Map<String, Object> responseContext = provider.getResponseContext();
String reqBody = (String) responseContext.get(MsgLogger.REQEST_BODY);
String rspBody = (String) responseContext.get(MsgLogger.RESPONSE_BODY);
TL;DR
Metro JAX WS RI docs says about MessageContext.Scope.APPLICATION property:
The message context object can also hold properties set by the client or provider. For instance, port proxy and dispatch objects both extend BindingProvider. A message context object can be obtained from both to represent the request or response context. Properties set in the request context can be read by the handlers, and the handlers may set properties on the message context objects passed to them. If these properties are set with the scope MessageContext.Scope.APPLICATION then they will be available in the response context to the client. On the server end, a context object is passed into the invoke method of a Provider.
metro-jax-ws/jaxws-ri/rt/src/main/java/com/sun/xml/ws/api/message/Packet.java contains property:
/**
* Lazily created set of handler-scope property names.
*
* <p>
* We expect that this is only used when handlers are present
* and they explicitly set some handler-scope values.
*
* #see #getHandlerScopePropertyNames(boolean)
*/
private Set<String> handlerScopePropertyNames;
On other hand metro-jax-ws/jaxws-ri/rt/src/main/java/com/sun/xml/ws/client/ResponseContext.java is an implementation of Map with:
public boolean containsKey(Object key) {
if(packet.supports(key))
return packet.containsKey(key); // strongly typed
if(packet.invocationProperties.containsKey(key))
// if handler-scope, hide it
return !packet.getHandlerScopePropertyNames(true).contains(key);
return false;
}
In SOAPHandler we can mark property as APPLICATION instead of default MessageContext.Scope.HANDLER:
/**
* Property scope. Properties scoped as <code>APPLICATION</code> are
* visible to handlers,
* client applications and service endpoints; properties scoped as
* <code>HANDLER</code>
* are only normally visible to handlers.
*/
public enum Scope {APPLICATION, HANDLER};
by:
/**
* Sets the scope of a property.
*
* #param name Name of the property associated with the
* <code>MessageContext</code>
* #param scope Desired scope of the property
* #throws java.lang.IllegalArgumentException if an illegal
* property name is specified
*/
public void setScope(String name, Scope scope);
As an alternative, instead of putting request/response details into the soap context, (in my case it did not work), you can put it into the ThreadLocal. So you need SOAPHandler, that #gavenkoa described (ty), but add it to the ThreadLocal instance, instead of the soap context.
Hello I've been trying to figure out generic way to log http requests in my application, so far no luck, here is how I handle the logging right now i.e:
#RequestMapping(value="register", method = RequestMethod.POST)
#ResponseBody
public String register(#RequestParam(value="param1",required=false) String param1, #RequestParam("param2") String param2, #RequestParam("param3") String param3, HttpServletRequest request){
long start = System.currentTimeMillis();
logger.info("!--REQUEST START--!");
logger.info("Request URL: " + request.getRequestURL().toString());
List<String> requestParameterNames = Collections.list((Enumeration<String>)request.getParameterNames());
logger.info("Parameter number: " + requestParameterNames.size());
for (String parameterName : requestParameterNames){
logger.info("Parameter name: " + parameterName + " - Parameter value: " + request.getParameter(parameterName));
}
//Some processing logic, call to the various services/methods with different parameters, response is always String(Json)
String response = service.callSomeServiceMethods(param1,param2,param3);
logger.info("Response is: " + response);
long end = System.currentTimeMillis();
logger.info("Requested completed in: " + (end-start) + "ms");
logger.info("!--REQUEST END--!");
return response;
}
So what I do right now for different controllers/methods is copy everything from beginning of the inside of the method until the processing logic which differs from method to method and then copy everything from below of that as showed in above template.
It is kind of messy, and there is a lot of code repetition(which I don't like). But I need to log everything.
Does anyone have more experience with this kinds of logging, can anyone shed some light on this?
EDIT: Also, see #membersound's comment on this answer, which improves this answer.
Spring supports this. See CommonsRequestLoggingFilter. If using Spring Boot, just register a bean of that type and Boot will apply it to the filter chain. Like:
#Bean
public Filter logFilter() {
CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true);
filter.setIncludePayload(true);
filter.setMaxPayloadLength(5120);
return filter;
}
Also, this logging filter requires the log level be set to DEBUG. E.g. do this in a logback.xml with:
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="DEBUG"/>
Use an interceptor:
extend HandlerInterceptorAdapter and override preHandle
define it with <mvc:interceptors> in dispatcher-servlet.xml
It will run for every request.
The main issue with reading request is that as soon as the input stream is consumed its gone whoof... and cannot be read again. So the input stream has to be cached. Instead of writing your own classes for caching (which can be found at several places on web), Spring provides a couple of useful classes i.e. ContentCachingRequestWrapper and ContentCachingResponseWrapper. These classes can be utilized very effectively, for example, in filters for logging purposes.
Define a filter in web.xml:
<filter>
<filter-name>loggingFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>loggingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Since the filter is declared as DelegatingFilterProxy, it can be declared as a bean using #Component or #Bean annotations. In the loggingFilter's doFilter method, wrap the request and response with spring provided classes before passing it to the filter chain:
HttpServletRequest requestToCache = new ContentCachingRequestWrapper(request);
HttpServletResponse responseToCache = new ContentCachingResponseWrapper(response);
chain.doFilter(requestToCache, responseToCache);
String requestData = getRequestData(requestToCache);
String responseData = getResponseData(responseToCache);
The input stream will be cached in the wrapped request as soon as the input stream is consumed after chain.doFilter(). Then it can be accessed as below:
public static String getRequestData(final HttpServletRequest request) throws UnsupportedEncodingException {
String payload = null;
ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
if (wrapper != null) {
byte[] buf = wrapper.getContentAsByteArray();
if (buf.length > 0) {
payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
}
}
return payload;
}
However, things are a bit different for response. Since the response was also wrapped before passing it to the filter chain, it will also be cached to the output stream as soon as it is written on its way back. But since the output stream will also be consumed so you have to copy the response back to the output stream using wrapper.copyBodyToResponse(). See below:
public static String getResponseData(final HttpServletResponse response) throws IOException {
String payload = null;
ContentCachingResponseWrapper wrapper =
WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
if (wrapper != null) {
byte[] buf = wrapper.getContentAsByteArray();
if (buf.length > 0) {
payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
wrapper.copyBodyToResponse();
}
}
return payload;
}
Hope it helps!
Here's a small library I wrote you can use: spring-mvc-logger
I made it available via maven central:
<dependency>
<groupId>com.github.isrsal</groupId>
<artifactId>spring-mvc-logger</artifactId>
<version>0.2</version>
</dependency>
Adding to what #B.Ali has answered. If you are using this in a spring asynchronous request (serlvet 3.0 or greater) handling scenario, then the following code is what worked for me.
public class OncePerRequestLoggingFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
boolean isFirstRequest = !isAsyncDispatch(request);
HttpServletRequest requestToUse = request;
HttpServletResponse responseToUse = response;
// The below check is critical and if not there, then the request/response gets corrupted.
// Probably because in async case the filter is invoked multiple times.
if (isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
requestToUse = new ContentCachingRequestWrapper(request);
}
if (isFirstRequest && !(response instanceof ContentCachingResponseWrapper)) {
responseToUse = new ContentCachingResponseWrapper(response);
}
filterChain.doFilter(requestToUse, responseToUse);
if (!isAsyncStarted(request)) {
ContentCachingResponseWrapper responseWrapper =
WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
responseWrapper.copyBodyToResponse(); // IMPORTANT to copy it back to response
}
}
#Override
protected boolean shouldNotFilterAsyncDispatch() {
return false; // IMPORTANT this is true by default and wont work in async scenario.
}
}
As any tech answer ... it depends ..
on the tech stack you are using and what your requirements are.
for example the more generic you want to make your logging, the further upfront you would want to do it. in your case, you are logging only requests which are logging enabled and being handled in the spring context. So you could be "missing" other requests.
I would look at the container or the web server you are using to run your app. That will remove this dependency on Spring. Plus containers provide you the flexibility of plugging in a logging provider and then configuring the format of the log outside code.
For example, if you are using Apache Web server, use Apache web server logging to log all HTTP requests in the access logging layer. But be careful, some of the logging options have performance penalties. Log only what you seriously need for an access pattern monitoring perspective.
If you are using tomcat, then tomcat also will allow you to log stuff. Search for Access Valve in the tomcat documentation for the tomcat you are using. That will open up a world of possibilities.
More extensive logging should be the domain of the exception strategy ie the kind of detail you want to see when a problem occurs in the system.