@Override public void init(ServletConfig servletConfig) throws ServletException { super.init(servletConfig); boolean disableAuthorization = Boolean.TRUE.toString().equalsIgnoreCase(servletConfig.getInitParameter(DISABLE_AUTHORIZATION_INIT_PARAM)); if (!disableAuthorization) { String credentials = null; String username = servletConfig.getInitParameter(USERNAME_INIT_PARAM); String password = servletConfig.getInitParameter(PASSWORD_INIT_PARAM); if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) { credentials = username.trim() + ":" + password.trim(); } else { credentials = DEFAULT_CREDENTIALS; } this.encodedCredentials = BaseEncoding.base64().encode(credentials.getBytes()); } this.objectMapper = new ObjectMapper() .registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.MICROSECONDS, false)) .registerModule(new HealthCheckModule()) .setSerializationInclusion(JsonInclude.Include.NON_NULL) .setTimeZone(TimeZone.getDefault()) .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z")); this.graphiteMetricFormatter = new GraphiteMetricFormatter(TimeUnit.SECONDS, TimeUnit.MICROSECONDS); try { this.threadDumpGenerator = new ThreadDump(ManagementFactory.getThreadMXBean()); } catch (NoClassDefFoundError ignore) { } ServletContext servletContext = servletConfig.getServletContext(); String servletSpecVersion = servletContext.getMajorVersion() + "." + servletContext.getMinorVersion(); this.serverInfo = ServerInfo.create(servletContext.getServerInfo(), servletSpecVersion); }
/** * Binds the thread dump to the CORS aware URL {@code /metrics/threads} where the metrics access key is * provided in the form field {@code key} or an {@code Authorization: Jenkins-Metrics-Key {key}} header * * @param req the request * @param key the key from the form field. * @return the {@link HttpResponse} * @throws IllegalAccessException if the access attempt is invalid. */ @SuppressWarnings("unused") // stapler binding @Restricted(NoExternalUse.class) // stapler binding @RequirePOST public HttpResponse doThreads(StaplerRequest req, @QueryParameter("key") String key) throws IllegalAccessException { requireCorrectMethod(req); if (StringUtils.isBlank(key)) { key = getKeyFromAuthorizationHeader(req); } Metrics.checkAccessKeyThreadDump(key); return Metrics.cors(key, new ThreadDumpResponse(new ThreadDump(ManagementFactory.getThreadMXBean()))); }
@Test public void dump() throws Exception { byte[] bytes = new byte[0]; new MockUnit(Request.class, Response.class, ByteArrayOutputStream.class) .expect(unit -> { ThreadMXBean tmxb = unit.mock(ThreadMXBean.class); unit.mockStatic(ManagementFactory.class); expect(ManagementFactory.getThreadMXBean()).andReturn(tmxb); ByteArrayOutputStream stream = unit.constructor(ByteArrayOutputStream.class).build(); expect(stream.toByteArray()).andReturn(bytes); ThreadDump td = unit.constructor(ThreadDump.class) .args(ThreadMXBean.class) .build(tmxb); td.dump(stream); unit.registerMock(ThreadDump.class, td); }) .expect(unit -> { Response rsp = unit.get(Response.class); expect(rsp.type(MediaType.plain)).andReturn(rsp); expect(rsp.status(Status.OK)).andReturn(rsp); expect(rsp.header("Cache-Control", "must-revalidate,no-cache,no-store")).andReturn(rsp); rsp.send(bytes); }) .run(unit -> { new ThreadDumpHandler().handle(unit.get(Request.class), unit.get(Response.class)); }); }
public Outcome threadDump() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); new ThreadDump( ManagementFactory.getThreadMXBean() ).dump( baos ); return outcomes().ok( baos.toByteArray() ).asTextPlain().build(); }
public ThreadDumpResponse(ThreadDump threadDump) { this.threadDump = threadDump; }
/** * Web binding for {@literal /threads} * * @return the response */ @Restricted(NoExternalUse.class) // only for use by stapler web binding public HttpResponse doThreads() { return new ThreadDumpResponse(new ThreadDump(ManagementFactory.getThreadMXBean())); }