/** * Copyright 2014 55 Minutes (http://www.55minutes.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package fiftyfive.wicket.util; import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.ExecutionException; import fiftyfive.wicket.FoundationApplication; import org.apache.wicket.Application; import org.apache.wicket.Session; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.protocol.http.IRequestLogger; import org.apache.wicket.protocol.http.IRequestLogger.ISessionLogInfo; import org.apache.wicket.protocol.http.IRequestLogger.SessionData; import org.apache.wicket.request.IRequestHandler; import org.apache.wicket.request.IRequestMapper; import org.apache.wicket.request.component.IRequestableComponent; import org.apache.wicket.request.component.IRequestablePage; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.request.handler.IComponentRequestHandler; import org.apache.wicket.request.handler.IPageClassRequestHandler; import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.lang.Bytes; import org.apache.wicket.util.lang.Classes; import org.apache.wicket.util.string.Strings; import org.apache.wicket.util.time.Duration; import org.apache.wicket.util.time.Time; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility methods for logging detailed information about Wicket's internal * state for troubleshooting purposes. Most of these methods work only when * called within a Wicket thread. * * @since 2.0 */ public class LoggingUtils { private static final Logger LOGGER = LoggerFactory.getLogger( LoggingUtils.class ); /** Human-readable descriptions of Wicket's request listener types. */ private static final Map<String,String> LISTENER_DESCRIPTIONS; static { LISTENER_DESCRIPTIONS = new HashMap<String,String>(); LISTENER_DESCRIPTIONS.put( "IFormSubmitListener", "Processing Form Submission"); LISTENER_DESCRIPTIONS.put( "ILinkListener", "Processing Link Click" ); LISTENER_DESCRIPTIONS.put( "IOnChangeListener", "Processing Form Element OnChange Event" ); } /** * Writes to the logger a best-guess at the most concise description of * the exception by first unwrapping it (see {@link #unwrap upwrap}), then * writes a large amount of information regarding the current Wicket state * (see {@link #dumpWicketState dumpWicketState}), and finally writes the * full stack traces of the entire exception chain. * <p> * Example logger output: * <pre class="example"> * ParseException: Unparseable date: "1xxx07" * * Request: * URL = wicket/bookmarkable/fiftyfive.wicket.examples.formtest.FormTestPage?0&initialMonth=10.2007&startDate=1xxx07&endDate=11.10.2007 * Handler = RenderPageRequestHandler * Component = FormTestPage * Duration = 485 milliseconds * Session: * ID = 1sxy938y7qoqq942z4pnuqdqt * Info = TODO: Your session info goes here * Size = 716 bytes * Duration = 310 milliseconds * Application: * Active Sessions = 1 (1 peak) * Memory Usage = 25M used, 40M free, 533M max * IP Address = 172.16.1.14 * Uptime = 10.9 seconds * Headers: * Host = localhost:8080 * User-Agent = Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 * Accept = application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 * Cache-Control = max-age=0 * Accept-Language = en-us * Accept-Encoding = gzip, deflate * Cookie = JSESSIONID=1217fv4qjpnbnv1ewzzmonevh * Connection = keep-alive * * Message: Error calling method: public java.util.Date fiftyfive.wicket.examples.formtest.FormTestPage$1.getStartDate() on object: [ [Component id = calendar-control]] * * Root cause: * * java.text.ParseException: Unparseable date: "1xxx07" * at java.text.DateFormat.parse(DateFormat.java:337) * at fiftyfive.wicket.examples.formtest.FormTestPage$1.getStartDate(FormTestPage.java:82) * at java.lang.reflect.Method.invoke(Method.java:597) * at org.apache.wicket.util.lang.PropertyResolver$MethodGetAndSet.getValue(PropertyResolver.java:1112) * at org.apache.wicket.util.lang.PropertyResolver$ObjectAndGetSetter.getValue(PropertyResolver.java:637) * at org.apache.wicket.util.lang.PropertyResolver.getValue(PropertyResolver.java:96) * at org.apache.wicket.model.AbstractPropertyModel.getObject(AbstractPropertyModel.java:122) * at fiftyfive.wicket.datetime.RestrictedDatePicker.configure(RestrictedDatePicker.java:168) * at org.apache.wicket.extensions.yui.calendar.DatePicker.renderHead(DatePicker.java:260) * at org.apache.wicket.Component.renderHead(Component.java:2627) * at org.apache.wicket.markup.renderStrategy.ParentFirstHeaderRenderStrategy$1.component(ParentFirstHeaderRenderStrategy.java:70) * at org.apache.wicket.markup.renderStrategy.ParentFirstHeaderRenderStrategy$1.component(ParentFirstHeaderRenderStrategy.java:66) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:143) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:161) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:161) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:161) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:117) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:193) * at org.apache.wicket.MarkupContainer.visitChildren(MarkupContainer.java:941) * at org.apache.wicket.markup.renderStrategy.ParentFirstHeaderRenderStrategy.renderChildHeaders(ParentFirstHeaderRenderStrategy.java:64) * at org.apache.wicket.markup.renderStrategy.AbstractHeaderRenderStrategy.renderHeader(AbstractHeaderRenderStrategy.java:125) * at org.apache.wicket.markup.html.internal.HtmlHeaderContainer.onComponentTagBody(HtmlHeaderContainer.java:140) * at org.apache.wicket.Component.renderComponent(Component.java:2518) * at org.apache.wicket.MarkupContainer.onRender(MarkupContainer.java:1527) * at org.apache.wicket.Component.render_(Component.java:2380) * at org.apache.wicket.Component.render(Component.java:2307) * at org.apache.wicket.MarkupContainer.renderNext(MarkupContainer.java:1466) * at org.apache.wicket.MarkupContainer.renderAll(MarkupContainer.java:1589) * at org.apache.wicket.Page.onRender(Page.java:1139) * at org.apache.wicket.Component.render_(Component.java:2380) * at org.apache.wicket.Component.render(Component.java:2307) * at org.apache.wicket.Page.renderPage(Page.java:1289) * at org.apache.wicket.request.handler.render.WebPageRenderer.renderPage(WebPageRenderer.java:131) * at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:199) * at org.apache.wicket.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:149) * at org.apache.wicket.request.RequestHandlerStack.executeRequestHandler(RequestHandlerStack.java:84) * at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:206) * at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:248) * at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:131) * at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:184) * at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) * at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:83) * at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) * at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) * at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388) * at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) * at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) * at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) * at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:440) * at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) * at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114) * at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) * at org.mortbay.jetty.Server.handle(Server.java:326) * at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) * at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:926) * at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549) * at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212) * at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) * at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410) * at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582) * * * Complete stack: * * org.apache.wicket.WicketRuntimeException: Error calling method: public java.util.Date fiftyfive.wicket.examples.formtest.FormTestPage$1.getStartDate() on object: [ [Component id = calendar-control]] * at org.apache.wicket.util.lang.PropertyResolver$MethodGetAndSet.getValue(PropertyResolver.java:1116) * at org.apache.wicket.util.lang.PropertyResolver$ObjectAndGetSetter.getValue(PropertyResolver.java:637) * at org.apache.wicket.util.lang.PropertyResolver.getValue(PropertyResolver.java:96) * at org.apache.wicket.model.AbstractPropertyModel.getObject(AbstractPropertyModel.java:122) * at fiftyfive.wicket.datetime.RestrictedDatePicker.configure(RestrictedDatePicker.java:168) * at org.apache.wicket.extensions.yui.calendar.DatePicker.renderHead(DatePicker.java:260) * at org.apache.wicket.Component.renderHead(Component.java:2627) * at org.apache.wicket.markup.renderStrategy.ParentFirstHeaderRenderStrategy$1.component(ParentFirstHeaderRenderStrategy.java:70) * at org.apache.wicket.markup.renderStrategy.ParentFirstHeaderRenderStrategy$1.component(ParentFirstHeaderRenderStrategy.java:66) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:143) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:161) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:161) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:161) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:117) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:193) * at org.apache.wicket.MarkupContainer.visitChildren(MarkupContainer.java:941) * at org.apache.wicket.markup.renderStrategy.ParentFirstHeaderRenderStrategy.renderChildHeaders(ParentFirstHeaderRenderStrategy.java:64) * at org.apache.wicket.markup.renderStrategy.AbstractHeaderRenderStrategy.renderHeader(AbstractHeaderRenderStrategy.java:125) * at org.apache.wicket.markup.html.internal.HtmlHeaderContainer.onComponentTagBody(HtmlHeaderContainer.java:140) * at org.apache.wicket.Component.renderComponent(Component.java:2518) * at org.apache.wicket.MarkupContainer.onRender(MarkupContainer.java:1527) * at org.apache.wicket.Component.render_(Component.java:2380) * at org.apache.wicket.Component.render(Component.java:2307) * at org.apache.wicket.MarkupContainer.renderNext(MarkupContainer.java:1466) * at org.apache.wicket.MarkupContainer.renderAll(MarkupContainer.java:1589) * at org.apache.wicket.Page.onRender(Page.java:1139) * at org.apache.wicket.Component.render_(Component.java:2380) * at org.apache.wicket.Component.render(Component.java:2307) * at org.apache.wicket.Page.renderPage(Page.java:1289) * at org.apache.wicket.request.handler.render.WebPageRenderer.renderPage(WebPageRenderer.java:131) * at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:199) * at org.apache.wicket.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:149) * at org.apache.wicket.request.RequestHandlerStack.executeRequestHandler(RequestHandlerStack.java:84) * at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:206) * at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:248) * at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:131) * * java.lang.RuntimeException: java.text.ParseException: Unparseable date: "1xxx07" * at fiftyfive.wicket.examples.formtest.FormTestPage$1.getStartDate(FormTestPage.java:87) * at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) * at java.lang.reflect.Method.invoke(Method.java:597) * at org.apache.wicket.util.lang.PropertyResolver$MethodGetAndSet.getValue(PropertyResolver.java:1112) * at org.apache.wicket.util.lang.PropertyResolver$ObjectAndGetSetter.getValue(PropertyResolver.java:637) * at org.apache.wicket.util.lang.PropertyResolver.getValue(PropertyResolver.java:96) * at org.apache.wicket.model.AbstractPropertyModel.getObject(AbstractPropertyModel.java:122) * at fiftyfive.wicket.datetime.RestrictedDatePicker.configure(RestrictedDatePicker.java:168) * at org.apache.wicket.extensions.yui.calendar.DatePicker.renderHead(DatePicker.java:260) * at org.apache.wicket.Component.renderHead(Component.java:2627) * at org.apache.wicket.markup.renderStrategy.ParentFirstHeaderRenderStrategy$1.component(ParentFirstHeaderRenderStrategy.java:70) * at org.apache.wicket.markup.renderStrategy.ParentFirstHeaderRenderStrategy$1.component(ParentFirstHeaderRenderStrategy.java:66) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:143) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:161) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:161) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:161) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:117) * at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:193) * at org.apache.wicket.MarkupContainer.visitChildren(MarkupContainer.java:941) * at org.apache.wicket.markup.renderStrategy.ParentFirstHeaderRenderStrategy.renderChildHeaders(ParentFirstHeaderRenderStrategy.java:64) * at org.apache.wicket.markup.renderStrategy.AbstractHeaderRenderStrategy.renderHeader(AbstractHeaderRenderStrategy.java:125) * at org.apache.wicket.markup.html.internal.HtmlHeaderContainer.onComponentTagBody(HtmlHeaderContainer.java:140) * at org.apache.wicket.Component.renderComponent(Component.java:2518) * at org.apache.wicket.MarkupContainer.onRender(MarkupContainer.java:1527) * at org.apache.wicket.Component.render_(Component.java:2380) * at org.apache.wicket.Component.render(Component.java:2307) * at org.apache.wicket.MarkupContainer.renderNext(MarkupContainer.java:1466) * at org.apache.wicket.MarkupContainer.renderAll(MarkupContainer.java:1589) * at org.apache.wicket.Page.onRender(Page.java:1139) * at org.apache.wicket.Component.render_(Component.java:2380) * at org.apache.wicket.Component.render(Component.java:2307) * at org.apache.wicket.Page.renderPage(Page.java:1289) * at org.apache.wicket.request.handler.render.WebPageRenderer.renderPage(WebPageRenderer.java:131) * at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:199) * at org.apache.wicket.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:149) * at org.apache.wicket.request.RequestHandlerStack.executeRequestHandler(RequestHandlerStack.java:84) * at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:206) * at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:248) * at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:131)</pre> */ public static void logException(Logger logger, Exception e) { Args.notNull(logger, "logger"); Args.notNull(e, "e"); try { Throwable unwrapped = unwrap(e); logger.error(String.format( "%s: %s%n%n%s%n%n%s", Classes.simpleName(unwrapped.getClass()), unwrapped.getMessage(), dumpWicketState(), Strings.toString(e) )); } catch(Exception loggingEx) { // We should never arrive here, because it means that something // went terribly wrong in our logging code. Since our code failed, // fall back to simple logging so that Wicket error handling // can continue uninterrupted. LOGGER.error("Unexpected exception during logging", loggingEx); logger.error("RuntimeException", e); } } /** * Attempts to find the most meaningful exception in a runtime exception * chain by stripping away the exceptions commonly used as "wrappers", * namely: RuntimeException, WicketRuntimeException, * InvocationTargetException and ExecutionException. These four exception * types are usually language cruft that don't add much desciptive value. * <p> * For example, if the exception chain is: * <pre class="example"> * WicketRuntimeException * -> InvocationTargetException * -> MyBusinessException * -> SQLException</pre> * <p> * Then the unwrapped exception would be {@code MyBusinessException}. */ public static Throwable unwrap(Throwable e) { Args.notNull(e, "e"); Throwable unwrapped = e; while(true) { Throwable cause = null; if(unwrapped instanceof WicketRuntimeException || unwrapped instanceof InvocationTargetException || unwrapped instanceof ExecutionException || unwrapped.getClass().equals(RuntimeException.class)) { cause = unwrapped.getCause(); } if(null == cause || unwrapped == cause) { break; } unwrapped = cause; } return unwrapped; } /** * Returns a multi-line string that describes the current Wicket request * cycle in great detail. Example output: * <pre class="example"> * Request: * URL = wicket/bookmarkable/fiftyfive.wicket.examples.formtest.FormTestPage?0&initialMonth=10.2007&startDate=1xxx07&endDate=11.10.2007 * Handler = RenderPageRequestHandler * Component = FormTestPage * Duration = 485 milliseconds * Session: * ID = 1sxy938y7qoqq942z4pnuqdqt * Info = TODO: Your session info goes here * Size = 716 bytes * Duration = 310 milliseconds * Application: * Active Sessions = 1 (1 peak) * Memory Usage = 25M used, 40M free, 533M max * IP Address = 172.16.1.14 * Uptime = 10.9 seconds * Headers: * Host = localhost:8080 * User-Agent = Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 * Accept = application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 * Cache-Control = max-age=0 * Accept-Language = en-us * Accept-Encoding = gzip, deflate * Cookie = JSESSIONID=1217fv4qjpnbnv1ewzzmonevh * Connection = keep-alive</pre> * <p> * Note that session duration and application active sessions are only * available if Wicket's request logging facility is enabled. */ public static String dumpWicketState() { return String.format( "Request:%n%s%nSession:%n%s%nApplication:%n%s%nHeaders:%n%s", formatMapEntries(getRequestInfo().entrySet(), " "), formatMapEntries(getSessionInfo().entrySet(), " "), formatMapEntries(getApplicationInfo().entrySet(), " "), formatMapEntries(HttpUtils.getHeaders(), " ") ); } /** * Returns a Map with information associated with the following keys: * <ul> * <li>{@code URL}</li> * <li>{@code Handler}</li> * <li>{@code Component}</li> * <li>{@code Duration}</li> * </ul> */ public static Map<String,Object> getRequestInfo() { Map<String,Object> info = new LinkedHashMap<String,Object>(); info.put("URL", HttpUtils.getRelativeRequestUrl()); info.put("Handler", describeRequestHandler()); info.put("Component", describeRequestComponent()); info.put("Duration", getRequestDuration()); return info; } /** * Returns a Map with information associated with the following keys: * <ul> * <li>{@code ID}</li> * <li>{@code Info} (if session implements {@link ISessionLogInfo})</li> * <li>{@code Size}</li> * <li>{@code Duration} (if {@link IRequestLogger} is enabled)</li> * </ul> */ public static Map<String,Object> getSessionInfo() { Session sess = Session.get(); Object detail = "--ISessionLogInfo not implemented--"; if(sess instanceof ISessionLogInfo) { detail = ((ISessionLogInfo) sess).getSessionInfo(); } Map<String,Object> info = new LinkedHashMap<String,Object>(); if(sess != null) { info.put("ID", sess.getId()); info.put("Info", detail); info.put("Size", Bytes.bytes(sess.getSizeInBytes())); Duration dur = getSessionDuration(); if(dur != null) { info.put("Duration", getSessionDuration()); } } return info; } /** * Returns a Map with information associated with the following keys: * <ul> * <li>{@code Active Sessions} (if {@link IRequestLogger} is enabled)</li> * <li>{@code Memory Usage}</li> * <li>{@code IP Address}</li> * <li>{@code Uptime} (if app is a {@link FoundationApplication})</li> * </ul> */ public static Map<String,Object> getApplicationInfo() { Map<String,Object> info = new LinkedHashMap<String,Object>(); String active = describeActiveSessions(); if(active != null) { info.put("Active Sessions", active); } info.put("Memory Usage", describeMemoryUsage()); info.put("IP Address", getHostIpAddress()); Application app = Application.get(); if(app instanceof FoundationApplication) { info.put("Uptime", ((FoundationApplication) app).getUptime()); } return info; } /** * Returns a human-readable description of the original handler of the * current request. This is simply the name of the * {@link IRequestHandler} class, like {@code RenderPageRequestHandler}. */ public static String describeRequestHandler() { IRequestHandler handler = guessOriginalRequestHandler(); // TODO: more descriptive than this? return handler != null ? Classes.simpleName(handler.getClass()) : null; } /** * Returns a description of component or page that is currently being * processed by the Wicket framework. If a component is being executed, the * description will be in the form: * <pre class="example"> * PageClass > ComponentClass (superclass if component is anonymous) [wicket:id path]</pre> * <p> * Example: * <pre class="example"> * MyPage > MyPanel$1 (Link) [path:to:link]</pre> * <p> * If a page is being rendered, the description will be the page class. */ public static String describeRequestComponent() { IRequestHandler handler = guessOriginalRequestHandler(); Class<? extends IRequestablePage> pageClass = null; IRequestableComponent component = null; if(handler instanceof IPageClassRequestHandler) { pageClass = ((IPageClassRequestHandler) handler).getPageClass(); } if(handler instanceof IComponentRequestHandler) { component = ((IComponentRequestHandler) handler).getComponent(); } StringBuffer desc = new StringBuffer(); if(pageClass != null) { desc.append(Classes.simpleName(pageClass)); } if(component != null) { String classDesc = null; if(component.getClass().isAnonymousClass()) { classDesc = String.format( "%s (%s)", Classes.simpleName(component.getClass()), Classes.simpleName(component.getClass().getSuperclass()) ); } else { classDesc = Classes.simpleName(component.getClass()); } desc.append(String.format( " > %s [%s]", classDesc, component.getPageRelativePath() )); } return desc.length() > 0 ? desc.toString() : null; } /** * Returns the amount of time the current request has taken up until * this point. */ public static Duration getRequestDuration() { Time start = Time.millis(RequestCycle.get().getStartTime()); return Duration.elapsed(start); } /** * Returns the amount of time the currently session has been active. * Depends on Wicket's {@link IRequestLogger} being enabled. If it is not, * returns {@code null}. */ public static Duration getSessionDuration() { Date start = null; Session currSession = Session.get(); IRequestLogger log = Application.get().getRequestLogger(); if(log != null && currSession != null && currSession.getId() != null) { String sessionId = currSession.getId(); SessionData[] sessions = log.getLiveSessions(); if(sessions != null) { for(SessionData sess : sessions) { if(sessionId.equals(sess.getSessionId())) { start = sess.getStartDate(); break; } } } } return nullSafeElapsed(start); } /** * Returns the IP address hosting this JVM, or {@code null} if it could * not be determined. */ public static String getHostIpAddress() { try { InetAddress host = InetAddress.getLocalHost(); return host.getHostAddress(); } catch (Exception ex) { // ignore } return null; } /** * Returns a string that describes the JVM's memory conditions in this * format: {@code 36M used, 29M free, 533M max}. */ public static String describeMemoryUsage() { Runtime runtime = Runtime.getRuntime(); long free = runtime.freeMemory(); return String.format( "%sM used, %sM free, %sM max", (runtime.totalMemory() - free) / 1000000, free / 1000000, runtime.maxMemory() / 1000000 ); } /** * Returns a string that describes the active sessions in this format: * {@code 5 (16 peak)}. This information comes from the application's * {@link IRequestLogger}. If the logger is not enabled, returns * {@code null}. */ public static String describeActiveSessions() { IRequestLogger log = Application.get().getRequestLogger(); if(null == log) return null; SessionData[] sessions = log.getLiveSessions(); if(null == sessions) return null; return String.format( "%d (%d peak)", sessions.length, log.getPeakSessions() ); } /** * Returns a Duration of time elapsed since the specified date, or * {@code null} or the date is {@code null}. */ private static Duration nullSafeElapsed(Date since) { return null == since ? null : Duration.elapsed(Time.valueOf(since)); } /** * Formats a Map with on entry per line plus a specified indent. * Keys are padded and left-aligned so that they are all the same width. */ private static String formatMapEntries(Collection entries, String indent) { StringBuffer buf = new StringBuffer(); int width = 1; for(Map.Entry e : (Collection<Map.Entry>) entries) { int length = e.getKey().toString().length(); if(length > width) { width = length; } } for(Map.Entry e : (Collection<Map.Entry>) entries) { if(buf.length() > 0) { buf.append(String.format("%n")); } buf.append(String.format( "%s%-" + width + "s = %s", indent, e.getKey(), e.getValue() == null ? "N/A" : e.getValue() )); } return buf.toString(); } private static IRequestHandler guessOriginalRequestHandler() { IRequestMapper mapper = Application.get().getRootRequestMapper(); return mapper.mapRequest(RequestCycle.get().getRequest()); } /** * Not meant to be instantiated. */ private LoggingUtils() { super(); } }