package jetbrains.buildServer.profile; import jetbrains.buildServer.controllers.*; import jetbrains.buildServer.serverSide.auth.*; import jetbrains.buildServer.log.Loggers; import jetbrains.buildServer.serverSide.SBuildServer; import jetbrains.buildServer.util.StringUtil; import jetbrains.buildServer.web.openapi.WebControllerManager; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; public class ProfilerController extends BaseController { private final Profiler myProfiler; public ProfilerController(@NotNull final SBuildServer server, @NotNull final WebControllerManager manager, @NotNull final Profiler profiler, @NotNull final AuthorizationInterceptor authInterceptor) { super(server); myProfiler = profiler; String url = "/admin/profiler.html"; manager.registerController(url, this); final RequestPermissionsChecker permissionsChecker = new RequestPermissionsChecker() { public void checkPermissions(@NotNull final AuthorityHolder authorityHolder, @NotNull final HttpServletRequest request) throws AccessDeniedException { if (!authorityHolder.isPermissionGrantedGlobally(Permission.MANAGE_SERVER_INSTALLATION)) { throw new AccessDeniedException(authorityHolder, "You do not have enough permissions to start / stop server profiling"); } } }; authInterceptor.addPathBasedPermissionsChecker(url, permissionsChecker); } @Nullable protected ModelAndView doHandle(@NotNull final HttpServletRequest request, @NotNull final HttpServletResponse response) throws Exception { new AjaxRequestProcessor().processRequest(request, response, new AjaxRequestProcessor.RequestHandler() { public void handleRequest(@NotNull final HttpServletRequest request, @NotNull final HttpServletResponse response, @NotNull final Element xmlResponse) { final String action = request.getParameter("profilerAction"); if (action == null) return; try { doAction(request, action); } catch (Throwable e) { Loggers.SERVER.warnAndDebugDetails("Failed to handle profiler action '" + action + "'", e); ActionErrors errors = new ActionErrors(); errors.addError("profilerProblem", "Failed to handle profiler action '" + action + "': " + getMessageWithNested(e)); errors.serialize(xmlResponse); } } }); return null; } static private String getMessageWithNested(Throwable e) { String result = e.toString(); Throwable cause = e.getCause(); if (cause != null) { result += " Caused by: " + getMessageWithNested(cause); } return result; } private void doAction(final HttpServletRequest request, final String action) throws Exception { if ("StartCpu".equals(action)) { myProfiler.startProfiler(); } else if ("CaptureCPU".equals(action)) { try { String result = myProfiler.captureAndStop(); addSuccessMessage(request, "CPU snapshot is saved to the file on the server: \"" + result + "\"" + getFileSizeString(result)); } catch (Exception e) { throw new Exception("Cannot capture CPU snapshot.", e); } } else if ("StopCPU".equals(action)) { myProfiler.stopProfiler(); } else if ("CaptureMemory".equals(action)) { try { String result = myProfiler.captureMemorySnapshot(); addSuccessMessage(request, "Memory snapshot is saved to the file on the server: \"" + result + "\"" + getFileSizeString(result)); } catch (Exception e) { throw new Exception("Cannot capture memory snapshot.", e); } } } private String getFileSizeString(final String fileName) { try { return " (" + StringUtil.formatFileSize(new File(fileName).length()) + ")"; } catch (Exception e) { return ""; } } private void addSuccessMessage(HttpServletRequest request, String result) { if (result != null) { getOrCreateMessages(request).addMessage("profilerMessage", result); } } }