├── .mvn ├── maven.config └── extensions.xml ├── docs ├── images │ ├── graphics.png │ ├── statistics.png │ ├── systemmonitor128.png │ ├── systemmonitor32.png │ └── system_infos_and_threads.png └── MonitoringScripts.md ├── .gitignore ├── Jenkinsfile ├── src ├── main │ ├── resources │ │ ├── index.jelly │ │ ├── META-INF │ │ │ └── hudson.remoting.ClassFilter │ │ ├── net │ │ │ └── bull │ │ │ │ └── javamelody │ │ │ │ └── NodesColumn │ │ │ │ └── column.jelly.bak │ │ └── org │ │ │ └── jvnet │ │ │ └── hudson │ │ │ └── plugins │ │ │ └── monitoring │ │ │ └── NodeMonitoringAction │ │ │ └── index.jelly │ └── java │ │ ├── org │ │ └── jvnet │ │ │ └── hudson │ │ │ └── plugins │ │ │ └── monitoring │ │ │ ├── NodesMonitoringActionFactory.java │ │ │ ├── NodesListener.java │ │ │ ├── PluginManagementLink.java │ │ │ ├── NodesManagementLink.java │ │ │ ├── NodeMonitoringAction.java │ │ │ ├── HudsonMonitoringFilter.java │ │ │ └── PluginImpl.java │ │ └── net │ │ └── bull │ │ └── javamelody │ │ ├── WaitingDurationQueueListener.java │ │ ├── NodesColumn.bak │ │ ├── CounterBuildStepListener.java │ │ ├── CounterRunListener.java │ │ ├── NodesCollector.java │ │ ├── RemoteCallHelper.java │ │ └── NodesController.java └── test │ └── java │ └── org │ └── jvnet │ └── hudson │ └── plugins │ └── monitoring │ └── MonitoringFilterIntegrationTest.java ├── .github ├── workflows │ └── jenkins-security-scan.yml └── FUNDING.yml ├── pom.xml ├── LICENSE └── README.md /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -------------------------------------------------------------------------------- /docs/images/graphics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/monitoring-plugin/HEAD/docs/images/graphics.png -------------------------------------------------------------------------------- /docs/images/statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/monitoring-plugin/HEAD/docs/images/statistics.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | work 3 | .settings 4 | .classpath 5 | .project 6 | *.iml 7 | *.ipr 8 | *.iws 9 | .idea/ 10 | -------------------------------------------------------------------------------- /docs/images/systemmonitor128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/monitoring-plugin/HEAD/docs/images/systemmonitor128.png -------------------------------------------------------------------------------- /docs/images/systemmonitor32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/monitoring-plugin/HEAD/docs/images/systemmonitor32.png -------------------------------------------------------------------------------- /docs/images/system_infos_and_threads.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/monitoring-plugin/HEAD/docs/images/system_infos_and_threads.png -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | /* `buildPlugin` step provided by: https://github.com/jenkins-infra/pipeline-library */ 4 | buildPlugin(useContainerAgent: true, configurations: [ 5 | [platform: 'linux', jdk: 21], 6 | [platform: 'windows', jdk: 17], 7 | ]) 8 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 | Jenkins' monitoring with JavaMelody. 9 | Open report after installation. 10 |
-------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.6 6 | 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/jenkins-security-scan.yml: -------------------------------------------------------------------------------- 1 | name: Jenkins Security Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [ opened, synchronize, reopened ] 9 | workflow_dispatch: 10 | 11 | permissions: 12 | security-events: write 13 | contents: read 14 | actions: read 15 | 16 | jobs: 17 | security-scan: 18 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 19 | with: 20 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. 21 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default. 22 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: evernat # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | #patreon: # Replace with a single Patreon username 5 | #open_collective: # Replace with a single Open Collective username 6 | #ko_fi: # Replace with a single Ko-fi username 7 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | #liberapay: # Replace with a single Liberapay username 10 | #issuehunt: # Replace with a single IssueHunt username 11 | #otechie: # Replace with a single Otechie username 12 | #custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/hudson.remoting.ClassFilter: -------------------------------------------------------------------------------- 1 | net.bull.javamelody.internal.model.CacheInformations 2 | net.bull.javamelody.internal.model.JCacheInformations 3 | net.bull.javamelody.internal.model.HeapHistogram 4 | net.bull.javamelody.internal.model.HeapHistogram$ClassInfo 5 | net.bull.javamelody.internal.model.JavaInformations 6 | net.bull.javamelody.internal.model.JobInformations 7 | net.bull.javamelody.internal.model.MBeanNode 8 | net.bull.javamelody.internal.model.MBeanNode$MBeanAttribute 9 | net.bull.javamelody.internal.model.MemoryInformations 10 | net.bull.javamelody.internal.model.ProcessInformations 11 | net.bull.javamelody.internal.model.ThreadInformations 12 | net.bull.javamelody.internal.model.TomcatInformations 13 | net.bull.javamelody.internal.model.HsErrPid 14 | -------------------------------------------------------------------------------- /src/test/java/org/jvnet/hudson/plugins/monitoring/MonitoringFilterIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package org.jvnet.hudson.plugins.monitoring; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.Matchers.startsWith; 5 | 6 | import org.htmlunit.html.HtmlPage; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.jvnet.hudson.test.JenkinsRule; 10 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 11 | 12 | @WithJenkins 13 | class MonitoringFilterIntegrationTest { 14 | 15 | private JenkinsRule rule; 16 | 17 | @BeforeEach 18 | void beforeEach(JenkinsRule rule) { 19 | this.rule = rule; 20 | } 21 | 22 | @Test 23 | void test() throws Exception { 24 | try (JenkinsRule.WebClient wc = rule.createWebClient()) { 25 | HtmlPage page = wc.goTo("monitoring"); 26 | assertThat(page.getTitleText(), startsWith("Monitoring JavaMelody")); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/jvnet/hudson/plugins/monitoring/NodesMonitoringActionFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.jvnet.hudson.plugins.monitoring; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Collection; 22 | import java.util.List; 23 | 24 | import hudson.Extension; 25 | import hudson.model.Action; 26 | import hudson.model.Computer; 27 | import hudson.model.TransientComputerActionFactory; 28 | 29 | /** 30 | * Generates a {@link NodeMonitoringAction} for the each slave computer. 31 | * @author Oleg Nenashev (o.v.nenashev@gmail.com), Emeric Vernat 32 | */ 33 | @Extension 34 | public class NodesMonitoringActionFactory extends TransientComputerActionFactory { 35 | /** {@inheritDoc} */ 36 | @Override 37 | public Collection createFor(Computer computer) { 38 | final List result = new ArrayList<>(); 39 | // Add a single monitoring action, which will handle all monitoring features 40 | result.add(new NodeMonitoringAction(computer, "Monitoring", "monitor.gif")); 41 | return result; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/net/bull/javamelody/WaitingDurationQueueListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package net.bull.javamelody; 19 | 20 | import java.util.Date; 21 | import java.util.concurrent.ConcurrentHashMap; 22 | import java.util.concurrent.ConcurrentMap; 23 | 24 | import hudson.Extension; 25 | import hudson.model.Queue.LeftItem; 26 | import hudson.model.Queue.WaitingItem; 27 | import hudson.model.queue.QueueListener; 28 | 29 | /** 30 | * Listener d'entrée et de sortie de la file d'attente pour calculer un indicateur d'attente. 31 | * @author Emeric Vernat 32 | */ 33 | @Extension 34 | public class WaitingDurationQueueListener extends QueueListener { 35 | private static final ConcurrentMap START_TIMES_BY_ID = new ConcurrentHashMap<>(); 36 | 37 | /** {@inheritDoc} */ 38 | @Override 39 | public void onEnterWaiting(WaitingItem wi) { 40 | START_TIMES_BY_ID.put(wi.getId(), new Date(wi.getInQueueSince())); 41 | } 42 | 43 | /** {@inheritDoc} */ 44 | @Override 45 | public void onLeft(LeftItem li) { 46 | START_TIMES_BY_ID.remove(li.getId()); 47 | } 48 | 49 | static long getWaitingDurationsSum() { 50 | final long now = System.currentTimeMillis(); 51 | long sum = 0; 52 | for (final Date date : START_TIMES_BY_ID.values()) { 53 | // now can be a bit before date 54 | sum += now - date.getTime(); 55 | } 56 | return Math.max(sum, 0); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/net/bull/javamelody/NodesColumn.bak: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package net.bull.javamelody; 19 | 20 | import hudson.Extension; 21 | import hudson.model.Computer; 22 | import hudson.node_monitors.AbstractNodeMonitorDescriptor; 23 | import hudson.node_monitors.NodeMonitor; 24 | 25 | import java.io.IOException; 26 | 27 | import jenkins.model.Jenkins; 28 | import net.sf.json.JSONObject; 29 | 30 | import org.kohsuke.stapler.StaplerRequest; 31 | 32 | /** 33 | * Add a Monitoring actions column in the nodes list. 34 | * This class is currently not used: NodesMonitoringActionFactory is used instead. 35 | * 36 | * @author Emeric Vernat 37 | */ 38 | public class NodesColumn extends NodeMonitor { 39 | @Extension 40 | public static final AbstractNodeMonitorDescriptor DESCRIPTOR = new AbstractNodeMonitorDescriptor() { 41 | @Override 42 | protected String monitor(Computer c) throws IOException, InterruptedException { 43 | return c.getName(); 44 | } 45 | 46 | @Override 47 | public String getDisplayName() { 48 | return "Monitoring"; 49 | } 50 | 51 | @Override 52 | public NodeMonitor newInstance(StaplerRequest req, JSONObject formData) 53 | throws FormException { 54 | return new NodesColumn(); 55 | } 56 | }; 57 | 58 | /** 59 | * Constructor. 60 | */ 61 | public NodesColumn() { 62 | super(); 63 | setIgnored(true); 64 | } 65 | 66 | /** 67 | * {@inheritDoc} 68 | */ 69 | @Override 70 | public String getColumnCaption() { 71 | // Hide this column from non-admins 72 | return Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER) ? super.getColumnCaption() 73 | : null; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/org/jvnet/hudson/plugins/monitoring/NodesListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.jvnet.hudson.plugins.monitoring; 19 | 20 | import java.io.IOException; 21 | 22 | import hudson.Extension; 23 | import hudson.model.Computer; 24 | import hudson.model.TaskListener; 25 | import hudson.slaves.ComputerListener; 26 | import hudson.slaves.OfflineCause; 27 | import jenkins.model.Jenkins; 28 | import net.bull.javamelody.NodesCollector; 29 | 30 | /** 31 | * Listener of nodes to update data when nodes become online or offline without 32 | * waiting 1 minute. 33 | * @author Emeric Vernat 34 | */ 35 | @Extension 36 | public class NodesListener extends ComputerListener { 37 | private NodesCollector nodesCollector; 38 | 39 | /** 40 | * Constructor. 41 | */ 42 | public NodesListener() { 43 | super(); 44 | } 45 | 46 | /** {@inheritDoc} */ 47 | @Override 48 | public void onOnline(Computer c, TaskListener listener) 49 | throws IOException, InterruptedException { 50 | scheduleCollectNow(); 51 | super.onOnline(c, listener); 52 | } 53 | 54 | /** {@inheritDoc} */ 55 | @Override 56 | public void onOffline(Computer c, OfflineCause cause) { 57 | scheduleCollectNow(); 58 | super.onOffline(c, cause); 59 | } 60 | 61 | private void scheduleCollectNow() { 62 | try { 63 | final NodesCollector collector = getNodesCollector(); 64 | if (collector != null) { 65 | collector.scheduleCollectNow(); 66 | } 67 | } catch (final IllegalStateException e) { 68 | // if timer already canceled, do nothing 69 | // [JENKINS-17757] IllegalStateException: Timer already cancelled from NodesCollector.scheduleCollectNow 70 | } 71 | } 72 | 73 | private NodesCollector getNodesCollector() { 74 | if (nodesCollector == null) { 75 | final Jenkins jenkins = Jenkins.get(); 76 | final PluginImpl pluginImpl = jenkins.getPlugin(PluginImpl.class); 77 | if (pluginImpl != null) { 78 | final HudsonMonitoringFilter monitoringFilter = pluginImpl.getFilter(); 79 | if (monitoringFilter != null) { 80 | nodesCollector = monitoringFilter.getNodesCollector(); 81 | } 82 | } 83 | } 84 | return nodesCollector; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/net/bull/javamelody/CounterBuildStepListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package net.bull.javamelody; 19 | 20 | import hudson.Extension; 21 | import hudson.model.AbstractBuild; 22 | import hudson.model.BuildListener; 23 | import hudson.model.BuildStepListener; 24 | import hudson.tasks.BuildStep; 25 | import net.bull.javamelody.internal.model.Counter; 26 | 27 | /** 28 | * Listener de debut et de fin de build-steps pour alimenter les tableaux des builds en cours, 29 | * et les statistiques des temps des builds. 30 | * @author Emeric Vernat 31 | */ 32 | @Extension 33 | public class CounterBuildStepListener extends BuildStepListener { 34 | private static final Counter BUILD_COUNTER = CounterRunListener.getBuildCounter(); 35 | private static final boolean DISABLED = Parameter.DISABLED.getValueAsBoolean(); 36 | 37 | /** 38 | * Constructor. 39 | */ 40 | public CounterBuildStepListener() { 41 | super(); 42 | } 43 | 44 | /** {@inheritDoc} */ 45 | @SuppressWarnings("rawtypes") 46 | @Override 47 | public void started(AbstractBuild build, BuildStep buildStep, BuildListener listener) { 48 | if (DISABLED || !BUILD_COUNTER.isDisplayed()) { 49 | return; 50 | } 51 | final String jobName = build.getProject().getName(); 52 | final String buildStepName = buildStep.getClass().getSimpleName(); 53 | // if (bs instanceof Describable) { 54 | // phrase générique en anglais (ou français, etc), peu instructive: 55 | // buildStepName = ((Describable) bs).getDescriptor().getDisplayName(); 56 | // } 57 | 58 | // TODO display specifics of builds step depending on type: 59 | // depending on the instanceof type of buildStep (hudson.tasks.Ant, hudson.tasks.BatchFile, etc), 60 | // we could cast and get the specifics of the instance of build step (ant targets, batch command, maven goals, etc) 61 | // instead of just the type of the build step 62 | 63 | final String name = jobName + " / " + buildStepName; 64 | BUILD_COUNTER.bindContextIncludingCpu(name); 65 | } 66 | 67 | /** {@inheritDoc} */ 68 | @SuppressWarnings("rawtypes") 69 | @Override 70 | public void finished(AbstractBuild build, BuildStep buildStep, BuildListener listener, 71 | boolean canContinue) { 72 | if (DISABLED || !BUILD_COUNTER.isDisplayed()) { 73 | return; 74 | } 75 | final boolean error = false; // is there a build step failure result? 76 | BUILD_COUNTER.addRequestForCurrentContext(error); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.jenkins-ci.plugins 6 | plugin 7 | 5.30 8 | 9 | 10 | org.jvnet.hudson.plugins 11 | monitoring 12 | hpi 13 | ${revision}${changelist} 14 | Monitoring 15 | Monitoring of Jenkins 16 | https://github.com/jenkinsci/${project.artifactId}-plugin 17 | 2009 18 | 19 | 20 | 2.7.0 21 | -SNAPSHOT 22 | 2.479.1 23 | jenkinsci/${project.artifactId}-plugin 24 | false 25 | 26 | 27 | 28 | 29 | evernat 30 | evernat@free.fr 31 | Emeric Vernat 32 | 33 | 34 | 35 | 36 | ASL 37 | https://www.apache.org/licenses/LICENSE-2.0.txt 38 | repo 39 | 40 | 41 | 42 | 43 | net.bull.javamelody 44 | javamelody-core 45 | 2.6.0 46 | 47 | 48 | com.lowagie 49 | itext 50 | 2.1.7 51 | 52 | 53 | bouncycastle 54 | bcmail-jdk14 55 | 56 | 57 | bouncycastle 58 | bcprov-jdk14 59 | 60 | 61 | bouncycastle 62 | bctsp-jdk14 63 | 64 | 65 | 66 | 67 | org.jenkins-ci.plugins.aws-java-sdk 68 | aws-java-sdk-cloudwatch 69 | 1.12.772-477.v650d756dcf6d 70 | true 71 | 72 | 73 | org.jenkins-ci.plugins 74 | apache-httpcomponents-client-4-api 75 | 4.5.14-208.v438351942757 76 | true 77 | 78 | 79 | 80 | 81 | scm:git:https://github.com/${gitHubRepo}.git 82 | scm:git:git@github.com:${gitHubRepo}.git 83 | https://github.com/${gitHubRepo} 84 | monitoring-2.6.0 85 | 86 | 87 | 88 | 89 | repo.jenkins-ci.org 90 | https://repo.jenkins-ci.org/public/ 91 | 92 | 93 | 94 | 95 | 96 | repo.jenkins-ci.org 97 | https://repo.jenkins-ci.org/public/ 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/main/java/org/jvnet/hudson/plugins/monitoring/PluginManagementLink.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.jvnet.hudson.plugins.monitoring; 19 | 20 | import org.kohsuke.stapler.Stapler; 21 | import org.kohsuke.stapler.StaplerRequest2; 22 | 23 | import hudson.Extension; 24 | import hudson.model.ManagementLink; 25 | import hudson.security.Permission; 26 | import jenkins.model.Jenkins; 27 | 28 | /** 29 | * {@link ManagementLink} of the plugin to add a link in the "/manage" page. 30 | * @author Emeric Vernat 31 | */ 32 | @Extension(ordinal = Integer.MAX_VALUE - 490) 33 | public class PluginManagementLink extends ManagementLink { 34 | /** 35 | * Mostly works like {@link hudson.model.Action#getIconFileName()}, except 36 | * that the expected icon size is 48x48, not 24x24. So if you give just a 37 | * file name, "/images/48x48" will be assumed. 38 | * @return As a special case, return null to exclude this object from the 39 | * management link. This is useful for defining 40 | * {@link ManagementLink} that only shows up under certain 41 | * circumstances. 42 | */ 43 | @Override 44 | public String getIconFileName() { 45 | return "monitor.gif"; 46 | } 47 | 48 | /** 49 | * Returns a short description of what this link does. This text is the one 50 | * that's displayed in grey. This can include HTML, although the use of 51 | * block tags is highly discouraged. 52 | * Optional. 53 | */ 54 | @Override 55 | public String getDescription() { 56 | return "Monitoring of memory, cpu, http requests and more in the Jenkins instance."; 57 | } 58 | 59 | /** 60 | * Gets the string to be displayed. 61 | * The convention is to capitalize the first letter of each word, such as 62 | * "Test Result". 63 | */ 64 | @Override 65 | public String getDisplayName() { 66 | return "Monitoring of Jenkins instance"; 67 | } 68 | 69 | /** {@inheritDoc} */ 70 | @Override 71 | public Permission getRequiredPermission() { 72 | //This link is displayed to any user with permission to access the management menu 73 | return Jenkins.READ; 74 | } 75 | 76 | /** {@inheritDoc} */ 77 | @Override 78 | public String getUrlName() { 79 | final StaplerRequest2 req = Stapler.getCurrentRequest2(); 80 | if (req != null) { 81 | return req.getContextPath() + "/monitoring"; 82 | } 83 | return "/monitoring"; 84 | } 85 | 86 | /** 87 | * Name of the category for this management link. Exists so that plugins with core dependency pre-dating the version 88 | * when this was introduced can define a category. 89 | * 90 | * TODO when the core version is >2.226 change this to override {@code getCategory()} instead 91 | * 92 | * @return name of the desired category, one of the enum values of Category, e.g. {@code STATUS}. 93 | * @since 2.226 94 | */ 95 | public String getCategoryName() { 96 | return "STATUS"; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/net/bull/javamelody/CounterRunListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package net.bull.javamelody; 19 | 20 | import hudson.Extension; 21 | import hudson.model.AbstractBuild; 22 | import hudson.model.Result; 23 | import hudson.model.TaskListener; 24 | import hudson.model.listeners.RunListener; 25 | import net.bull.javamelody.internal.common.Parameters; 26 | import net.bull.javamelody.internal.model.Counter; 27 | 28 | /** 29 | * Listener de debut et de fin de builds pour alimenter les tableaux des builds en cours, 30 | * le graphique du nombre de builds en cours et les statistiques des temps des builds. 31 | * @author Emeric Vernat 32 | */ 33 | @Extension 34 | @SuppressWarnings("rawtypes") 35 | public class CounterRunListener extends RunListener { 36 | private static final Counter BUILD_COUNTER = new Counter(Counter.BUILDS_COUNTER_NAME, 37 | "jobs.png"); 38 | private static final boolean COUNTER_HIDDEN = Parameters 39 | .isCounterHidden(BUILD_COUNTER.getName()); 40 | private static final boolean DISABLED = Parameter.DISABLED.getValueAsBoolean(); 41 | 42 | /** 43 | * Constructor. 44 | */ 45 | public CounterRunListener() { 46 | super(AbstractBuild.class); 47 | // le compteur est affiche sauf si le parametre displayed-counters dit 48 | // le contraire 49 | BUILD_COUNTER.setDisplayed(!COUNTER_HIDDEN); 50 | } 51 | 52 | static Counter getBuildCounter() { 53 | return BUILD_COUNTER; 54 | } 55 | 56 | /** {@inheritDoc} */ 57 | @Override 58 | public void onStarted(AbstractBuild r, TaskListener listener) { 59 | super.onStarted(r, listener); 60 | 61 | if (DISABLED || !BUILD_COUNTER.isDisplayed()) { 62 | return; 63 | } 64 | if (isMavenModuleBuild(r)) { 65 | // si job maven, alors ok pour MavenModuleSetBuild, 66 | // mais pas ok pour le MavenBuild de chaque module Maven, 67 | // car onStarted et onCompleted seraient appelees sur des threads differents 68 | // et des builds resteraient affiches "en cours" 69 | return; 70 | } 71 | final String name = r.getProject().getName(); 72 | BUILD_COUNTER.bindContextIncludingCpu(name); 73 | JdbcWrapper.RUNNING_BUILD_COUNT.incrementAndGet(); 74 | } 75 | 76 | /** {@inheritDoc} */ 77 | @Override 78 | public void onCompleted(AbstractBuild r, TaskListener listener) { 79 | super.onCompleted(r, listener); 80 | 81 | if (DISABLED || !BUILD_COUNTER.isDisplayed()) { 82 | return; 83 | } 84 | if (isMavenModuleBuild(r)) { 85 | return; 86 | } 87 | JdbcWrapper.RUNNING_BUILD_COUNT.decrementAndGet(); 88 | final boolean error = Result.FAILURE.equals(r.getResult()); 89 | BUILD_COUNTER.addRequestForCurrentContext(error); 90 | } 91 | 92 | private boolean isMavenModuleBuild(AbstractBuild r) { 93 | return "hudson.maven.MavenBuild".equals(r.getClass().getName()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/org/jvnet/hudson/plugins/monitoring/NodesManagementLink.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.jvnet.hudson.plugins.monitoring; 19 | 20 | import org.kohsuke.stapler.Stapler; 21 | import org.kohsuke.stapler.StaplerRequest2; 22 | 23 | import hudson.Extension; 24 | import hudson.model.ManagementLink; 25 | import hudson.security.Permission; 26 | import jenkins.model.Jenkins; 27 | 28 | /** 29 | * {@link ManagementLink} of the plugin to add a link in the "/manage" page, for the agents next to the one for the instance. 30 | * @author Emeric Vernat 31 | */ 32 | @Extension(ordinal = Integer.MAX_VALUE - 491) 33 | public class NodesManagementLink extends ManagementLink { 34 | /** 35 | * Mostly works like {@link hudson.model.Action#getIconFileName()}, except 36 | * that the expected icon size is 48x48, not 24x24. So if you give just a 37 | * file name, "/images/48x48" will be assumed. 38 | * @return As a special case, return null to exclude this object from the 39 | * management link. This is useful for defining 40 | * {@link ManagementLink} that only shows up under certain 41 | * circumstances. 42 | */ 43 | @Override 44 | public String getIconFileName() { 45 | return "monitor.gif"; 46 | } 47 | 48 | /** 49 | * Returns a short description of what this link does. This text is the one 50 | * that's displayed in grey. This can include HTML, although the use of 51 | * block tags is highly discouraged. 52 | * Optional. 53 | */ 54 | @Override 55 | public String getDescription() { 56 | return "Monitoring of builds, build queue and Jenkins agents."; 57 | } 58 | 59 | /** 60 | * Gets the string to be displayed. 61 | * The convention is to capitalize the first letter of each word, such as 62 | * "Test Result". 63 | */ 64 | @Override 65 | public String getDisplayName() { 66 | return "Monitoring of Jenkins agents"; 67 | } 68 | 69 | /** {@inheritDoc} */ 70 | @Override 71 | public Permission getRequiredPermission() { 72 | //This link is displayed to any user with permission to access the management menu 73 | return Jenkins.READ; 74 | } 75 | 76 | /** {@inheritDoc} */ 77 | @Override 78 | public String getUrlName() { 79 | final StaplerRequest2 req = Stapler.getCurrentRequest2(); 80 | if (req != null) { 81 | return req.getContextPath() + "/monitoring/nodes"; 82 | } 83 | return "/monitoring/nodes"; 84 | } 85 | 86 | /** 87 | * Name of the category for this management link. Exists so that plugins with core dependency pre-dating the version 88 | * when this was introduced can define a category. 89 | * 90 | * TODO when the core version is >2.226 change this to override {@code getCategory()} instead 91 | * 92 | * @return name of the desired category, one of the enum values of Category, e.g. {@code STATUS}. 93 | * @since 2.226 94 | */ 95 | public String getCategoryName() { 96 | return "STATUS"; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/jvnet/hudson/plugins/monitoring/NodeMonitoringAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.jvnet.hudson.plugins.monitoring; 19 | 20 | import org.kohsuke.stapler.Stapler; 21 | 22 | import hudson.model.Action; 23 | import hudson.model.Computer; 24 | import jenkins.model.Jenkins; 25 | import net.bull.javamelody.SessionListener; 26 | import net.bull.javamelody.internal.web.html.HtmlAbstractReport; 27 | 28 | /** 29 | * Implements a "Monitoring" button for slaves. 30 | * This button will be available for everybody with Administer or SystemRead permissions. 31 | * @author Oleg Nenashev (o.v.nenashev@gmail.com), Emeric Vernat 32 | * @since 1.49 33 | */ 34 | public class NodeMonitoringAction implements Action { 35 | private final Computer computer; 36 | private final String displayName; 37 | private final String iconPath; 38 | 39 | /** 40 | * Constructor. 41 | * @param computer Computer 42 | * @param displayName String 43 | * @param iconPath String 44 | */ 45 | public NodeMonitoringAction(Computer computer, String displayName, String iconPath) { 46 | super(); 47 | this.computer = computer; 48 | this.displayName = displayName; 49 | this.iconPath = iconPath; 50 | } 51 | 52 | /** 53 | * @return Computer 54 | */ 55 | public Computer getComputer() { 56 | return computer; 57 | } 58 | 59 | /** {@inheritDoc} */ 60 | @Override 61 | public final String getDisplayName() { 62 | return hasMonitoringPermissions() && computer.isOnline() ? displayName : null; 63 | } 64 | 65 | /** {@inheritDoc} */ 66 | @Override 67 | public final String getIconFileName() { 68 | return hasMonitoringPermissions() && computer.isOnline() ? iconPath : null; 69 | } 70 | 71 | /** {@inheritDoc} */ 72 | @Override 73 | public String getUrlName() { 74 | return "monitoring"; 75 | } 76 | 77 | /** 78 | * Used in index.jelly 79 | * @return String 80 | */ 81 | public String getMonitoringUrl() { 82 | final String urlSuffix = computer instanceof Jenkins.MasterComputer ? "" 83 | : "/nodes/" + computer.getName(); 84 | return "../../../monitoring" + urlSuffix; 85 | } 86 | 87 | /** 88 | * Si la protection csrf est activée dans Jenkins (ce qui est le cas par défaut), 89 | * retourne la partie de l'url avec le token csrf de javamelody. 90 | * @return String 91 | */ 92 | public String getCsrfTokenUrlPart() { 93 | try { 94 | SessionListener.bindSession(Stapler.getCurrentRequest2().getSession(false)); 95 | return HtmlAbstractReport.getCsrfTokenUrlPart().replace("&", "&"); 96 | } finally { 97 | SessionListener.unbindSession(); 98 | } 99 | } 100 | 101 | /** 102 | * Checks that user has access permissions to the monitoring page. 103 | * By default, requires global Administer or SystemRead permissions. 104 | * @return boolean 105 | */ 106 | protected boolean hasMonitoringPermissions() { 107 | final Jenkins jenkins = Jenkins.get(); 108 | return jenkins.hasPermission(Jenkins.ADMINISTER) || jenkins.hasPermission(Jenkins.SYSTEM_READ); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/resources/net/bull/javamelody/NodesColumn/column.jelly.bak: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | N/A 15 | 16 | 17 | 18 | 19 | 20 | 21 | View threads 22 | 23 | 24 | 25 | Execute the garbage collector 26 | 27 | 28 | 29 | Generate a heap dump 30 | 31 | 32 | 33 | View memory histogram 34 | 35 | 36 | 37 | MBeans 38 | 39 | 40 | 41 | View OS processes 42 | 43 | 44 | 45 | 46 | 47 | View threads 48 | 49 | 50 | 51 | Execute the garbage collector 52 | 53 | 54 | 55 | Generate a heap dump 56 | 57 | 58 | 59 | View memory histogram 60 | 61 | 62 | 63 | MBeans 64 | 65 | 66 | 67 | View OS processes 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/main/resources/org/jvnet/hudson/plugins/monitoring/NodeMonitoringAction/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 27 | 28 | 29 | 30 |

31 | ${it.displayName} 32 | ${%JavaMelody Monitoring} 33 |

34 |

This page provides access to the JavaMelody monitoring of the 35 | ${it.computer.displayName} node. 36 |

37 | 38 | 39 | 40 | 41 | 43 | 46 |
47 | 48 |
49 |
50 |
51 |
52 | 53 | 54 | 63 | 64 |

${%System reports}

65 | 66 | 69 | ${%View threads on the node} 70 | 71 | 74 | ${%View OS processes} 75 | 76 | 79 | ${%View memory usage histogram.} ${%JDK is required} 80 | 81 | 84 | ${%Display data collected by MBeans} 85 | 86 | 87 | 88 | 89 |

${%System actions}

90 | 91 | 94 | ${%Runs the garbage collector on the node} 95 | 96 | 99 | ${%Warning!} ${%This operation may affect performance of the node} 100 | 101 |
102 |
103 |
104 |
105 | 106 |
-------------------------------------------------------------------------------- /src/main/java/org/jvnet/hudson/plugins/monitoring/HudsonMonitoringFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.jvnet.hudson.plugins.monitoring; 19 | 20 | import java.io.IOException; 21 | import java.net.URLDecoder; 22 | import java.util.Enumeration; 23 | 24 | import jakarta.servlet.FilterChain; 25 | import jakarta.servlet.FilterConfig; 26 | import jakarta.servlet.ServletException; 27 | import jakarta.servlet.ServletRequest; 28 | import jakarta.servlet.ServletResponse; 29 | import jakarta.servlet.http.HttpServletRequest; 30 | import jakarta.servlet.http.HttpServletResponse; 31 | import jakarta.servlet.http.HttpSession; 32 | 33 | import jenkins.model.Jenkins; 34 | import net.bull.javamelody.NodesCollector; 35 | import net.bull.javamelody.NodesController; 36 | import net.bull.javamelody.Parameter; 37 | import net.bull.javamelody.PluginMonitoringFilter; 38 | 39 | /** 40 | * Filter of monitoring JavaMelody with security check for Hudson/Jenkins administrator. 41 | * 42 | * @author Emeric Vernat 43 | */ 44 | public class HudsonMonitoringFilter extends PluginMonitoringFilter { 45 | // TODO since Jenkins 2.2, we could almost extend MonitoringFilter instead of PluginMonitoringFilter 46 | // by using extension point: https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/util/HttpSessionListener.java 47 | private static final boolean PLUGIN_AUTHENTICATION_DISABLED = Parameter.PLUGIN_AUTHENTICATION_DISABLED 48 | .getValueAsBoolean(); 49 | 50 | private NodesCollector nodesCollector; 51 | 52 | /** {@inheritDoc} */ 53 | @Override 54 | public String getApplicationType() { 55 | return "Jenkins"; 56 | } 57 | 58 | /** {@inheritDoc} */ 59 | @Override 60 | public void init(FilterConfig config) throws ServletException { 61 | super.init(config); 62 | 63 | nodesCollector = new NodesCollector(this); 64 | // on n'initialize pas nodesCollector tout de suite mais seulement dans 65 | // PluginImpl.postInitialize 66 | } 67 | 68 | /** {@inheritDoc} */ 69 | @Override 70 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 71 | throws IOException, ServletException { 72 | if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse) 73 | || getNodesCollector().isMonitoringDisabled()) { 74 | super.doFilter(request, response, chain); 75 | return; 76 | } 77 | final HttpServletRequest httpRequest = (HttpServletRequest) request; 78 | final HttpServletResponse httpResponse = (HttpServletResponse) response; 79 | 80 | final String requestURI = httpRequest.getRequestURI(); 81 | final String monitoringUrl = getMonitoringUrl(httpRequest); 82 | final String monitoringSlavesUrl = monitoringUrl + "/nodes"; 83 | if (requestURI.equals(monitoringUrl) || requestURI.startsWith(monitoringSlavesUrl)) { 84 | if (isRumMonitoring(httpRequest, httpResponse)) { 85 | return; 86 | } 87 | if (!PLUGIN_AUTHENTICATION_DISABLED) { 88 | final boolean hasSystemReadPermission = Jenkins.get().hasPermission(Jenkins.SYSTEM_READ); 89 | if (!hasSystemReadPermission) { 90 | // only the Jenkins administrators and users with SystemRead permission can view the monitoring report 91 | Jenkins.get().checkPermission(Jenkins.ADMINISTER); 92 | } else if (hasSystemReadPermission && request.getParameter("action") != null) { 93 | // only the Jenkins administrators can run actions such as GC, heap dump, etc 94 | Jenkins.get().checkPermission(Jenkins.ADMINISTER); 95 | } 96 | } 97 | 98 | // this check of parameters is not supposed to be needed, 99 | // but just in case we can check parameters here 100 | if (hasInvalidParameters(request)) { 101 | httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST); 102 | return; 103 | } 104 | } 105 | 106 | if (requestURI.startsWith(monitoringSlavesUrl)) { 107 | final String nodeName; 108 | if (requestURI.equals(monitoringSlavesUrl)) { 109 | nodeName = null; 110 | } else { 111 | nodeName = URLDecoder.decode( 112 | requestURI.substring(monitoringSlavesUrl.length()).replace("/", ""), 113 | "UTF-8"); 114 | } 115 | doMonitoring(httpRequest, httpResponse, nodeName); 116 | return; 117 | } 118 | 119 | try { 120 | super.doFilter(request, response, chain); 121 | } finally { 122 | putUserInfoInSession(httpRequest); 123 | } 124 | } 125 | 126 | private boolean hasInvalidParameters(ServletRequest request) { 127 | final Enumeration parameterNames = request.getParameterNames(); 128 | while (parameterNames.hasMoreElements()) { 129 | final String parameterName = (String) parameterNames.nextElement(); 130 | for (final String value : request.getParameterValues(parameterName)) { 131 | if (value.indexOf('"') != -1 || value.indexOf('\'') != -1 132 | || value.indexOf('<') != -1 || value.indexOf('&') != -1) { 133 | return true; 134 | } 135 | } 136 | } 137 | return false; 138 | } 139 | 140 | private void putUserInfoInSession(HttpServletRequest httpRequest) { 141 | final HttpSession session = httpRequest.getSession(false); 142 | if (session == null) { 143 | // la session n'est pas encore créée (et ne le sera peut-être jamais) 144 | return; 145 | } 146 | if (session.getAttribute(NodesController.SESSION_REMOTE_USER) == null) { 147 | // login utilisateur, peut être null 148 | // dans Jenkins, pas remoteUser = httpRequest.getRemoteUser(); 149 | final String remoteUser = Jenkins.getAuthentication2().getName(); 150 | // !anonymous for https://issues.jenkins-ci.org/browse/JENKINS-42112 151 | if (remoteUser != null && !"anonymous".equals(remoteUser)) { 152 | session.setAttribute(NodesController.SESSION_REMOTE_USER, remoteUser); 153 | } 154 | } 155 | } 156 | 157 | /** 158 | * Generate a report 159 | * 160 | * @param httpRequest Http request 161 | * @param httpResponse Http response 162 | * @param nodeName nom du node (slave ou "") 163 | * @throws IOException e 164 | */ 165 | private void doMonitoring(HttpServletRequest httpRequest, HttpServletResponse httpResponse, 166 | String nodeName) throws IOException { 167 | if (NodesController.isJavaInformationsNeeded(httpRequest)) { 168 | getNodesCollector().collectWithoutErrorsNow(); 169 | } 170 | final NodesController nodesController = new NodesController(getNodesCollector(), nodeName); 171 | nodesController.doMonitoring(httpRequest, httpResponse); 172 | } 173 | 174 | NodesCollector getNodesCollector() { 175 | return nodesCollector; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/org/jvnet/hudson/plugins/monitoring/PluginImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package org.jvnet.hudson.plugins.monitoring; 19 | 20 | import java.io.File; 21 | import java.util.Arrays; 22 | import java.util.logging.LogRecord; 23 | 24 | import jakarta.servlet.ServletContext; 25 | 26 | import hudson.Plugin; 27 | import hudson.init.InitMilestone; 28 | import hudson.util.PluginServletFilter; 29 | import jenkins.model.Jenkins; 30 | import net.bull.javamelody.Parameter; 31 | import net.bull.javamelody.internal.common.Parameters; 32 | 33 | /** 34 | * Entry point of the plugin. 35 | *

36 | * There must be one {@link Plugin} class in each plugin. See javadoc of 37 | * {@link Plugin} for more about what can be done on this class. 38 | * @author Emeric Vernat 39 | */ 40 | @SuppressWarnings("deprecation") 41 | public class PluginImpl extends Plugin { 42 | private ServletContext context; 43 | private HudsonMonitoringFilter filter; 44 | 45 | private static class CsrfThread extends Thread { 46 | CsrfThread() { 47 | super(); 48 | } 49 | 50 | @Override 51 | public void run() { 52 | final Jenkins jenkins = Jenkins.getInstance(); 53 | while (jenkins.getInitLevel() != InitMilestone.COMPLETED) { 54 | try { 55 | Thread.sleep(1000); 56 | } catch (final InterruptedException e) { 57 | // RAS 58 | } 59 | } 60 | if (jenkins.isUseCrumbs()) { 61 | Parameter.CSRF_PROTECTION_ENABLED.setValue("true"); 62 | } 63 | } 64 | } 65 | 66 | /** {@inheritDoc} */ 67 | @Override 68 | public void start() throws Exception { 69 | super.start(); 70 | 71 | // get the servletContext in Jenkins instead of overriding Plugin.setServletContext 72 | final Jenkins jenkins = Jenkins.getInstance(); 73 | this.context = jenkins.getServletContext(); 74 | 75 | // jenkins.isUseCrumbs() is always false here because it's too early 76 | // and we can't use @Initializer(after = InitMilestone.COMPLETED) 77 | // because of https://issues.jenkins-ci.org/browse/JENKINS-37807 78 | // so check when jenkins is initialized 79 | final Thread thread = new CsrfThread(); 80 | thread.setName("javamelody-initializer"); 81 | thread.setDaemon(true); 82 | thread.start(); 83 | 84 | // on active les actions systemes (gc, heap dump, histogramme memoire, 85 | // processus...), sauf si l'administrateur a dit differemment 86 | if (isParameterUndefined(Parameter.SYSTEM_ACTIONS_ENABLED)) { 87 | Parameter.SYSTEM_ACTIONS_ENABLED.setValue("true"); 88 | } 89 | // on desactive les graphiques jdbc et statistiques sql puisqu'il n'y en 90 | // aura pas 91 | if (isParameterUndefined(Parameter.NO_DATABASE)) { 92 | Parameter.NO_DATABASE.setValue("true"); 93 | } 94 | // le repertoire de stockage est dans le repertoire de Hudson/Jenkins au lieu 95 | // d'etre dans le repertoire temporaire 96 | // ("/" initial necessaire sous windows pour javamelody v1.8.1) 97 | if (isParameterUndefined(Parameter.STORAGE_DIRECTORY)) { 98 | Parameter.STORAGE_DIRECTORY 99 | .setValue("/" + new File(jenkins.getRootDir(), "monitoring").getAbsolutePath()); 100 | } 101 | // http-transform-pattern pour agreger les requetes contenant des 102 | // parties "dynamiques" comme des numeros des builds, 103 | // les fichiers dans job//site/, javadoc/, ws/, cobertura/, 104 | // testReport/, violations/file/ 105 | // ou les utilisateurs dans user/ 106 | // ou les fichiers dans /static/abcdef123/ et dans /adjuncts/abcdef123/ 107 | // ou les renders ajax lors de l'ajout de build step dans /$stapler/bound/c285ac3d-39c1-4515-86aa-0b42d75212b3/render 108 | if (isParameterUndefined(Parameter.HTTP_TRANSFORM_PATTERN)) { 109 | Parameter.HTTP_TRANSFORM_PATTERN.setValue( 110 | "/\\d+/|(?<=/static/|/adjuncts/|/bound/)[\\w\\-]+|(?<=/ws/|/user/|/testReport/|/javadoc/|/site/|/violations/file/|/cobertura/).+|(?<=/job/).+(?=/descriptorByName/)"); 111 | } 112 | 113 | // custom reports (v1.50+) 114 | if (isParameterUndefined(Parameter.CUSTOM_REPORTS)) { 115 | Parameter.CUSTOM_REPORTS.setValue("Jenkins Info,About Monitoring"); 116 | System.setProperty("javamelody.Jenkins Info", "/systemInfo"); 117 | System.setProperty("javamelody.About Monitoring", 118 | "https://plugins.jenkins.io/monitoring/"); 119 | } 120 | 121 | // fix for JENKINS-14050: Unreadable HTML response for the monitoring reports 122 | if (isParameterUndefined(Parameter.GZIP_COMPRESSION_DISABLED)) { 123 | Parameter.GZIP_COMPRESSION_DISABLED.setValue("true"); 124 | } 125 | 126 | if (isParameterUndefined(Parameter.MAVEN_REPOSITORIES)) { 127 | // add jenkins maven public repository for jenkins and plugins sources 128 | final String mavenRepositories = System.getProperty("user.home") 129 | + "/.m2/repository,http://repo1.maven.org/maven2,http://repo.jenkins-ci.org/public"; 130 | Parameter.MAVEN_REPOSITORIES.setValue(mavenRepositories); 131 | } 132 | 133 | // we could set "javamelody.admin-emails" with 134 | // ((Mailer.DescriptorImpl) Jenkins.getInstance().getDescriptorByType( 135 | // hudson.tasks.Mailer.DescriptorImpl.class)).getAdminAddress(); 136 | // but the admin-emails property is better next to the mail session 137 | 138 | // try to fix https://issues.jenkins-ci.org/browse/JENKINS-23442 (ClassCircularityError: java/util/logging/LogRecord) 139 | // by preloading the java.util.logging.LogRecord class 140 | Arrays.hashCode(new Class[] { LogRecord.class }); 141 | 142 | this.filter = new HudsonMonitoringFilter(); 143 | PluginServletFilter.addFilter(filter); 144 | } 145 | 146 | private boolean isParameterUndefined(Parameter parameter) { 147 | final String key = Parameters.PARAMETER_SYSTEM_PREFIX + parameter.getCode(); 148 | return isParameterUndefined(key); 149 | } 150 | 151 | private boolean isParameterUndefined(String key) { 152 | return System.getProperty(key) == null && context != null 153 | && context.getInitParameter(key) == null; 154 | } 155 | 156 | HudsonMonitoringFilter getFilter() { 157 | return filter; 158 | } 159 | 160 | /** {@inheritDoc} */ 161 | @Override 162 | public void postInitialize() throws Exception { 163 | super.postInitialize(); 164 | if (filter == null) { 165 | throw new Exception("Post-initialization hook has been called before the plugin start. " 166 | + "Filters are not available"); 167 | } 168 | filter.getNodesCollector().init(); 169 | 170 | // replaced by @Extension in NodesListener: new NodesListener(filter.getNodesCollector()).register(); 171 | 172 | // replaced by @Extension in CounterRunListener: new CounterRunListener().register(); 173 | } 174 | 175 | /** {@inheritDoc} */ 176 | @Override 177 | public void stop() throws Exception { 178 | if (filter != null && filter.getNodesCollector() != null) { 179 | filter.getNodesCollector().stop(); 180 | } 181 | super.stop(); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/main/java/net/bull/javamelody/NodesCollector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package net.bull.javamelody; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Collections; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.Timer; 25 | import java.util.TimerTask; 26 | 27 | import jenkins.model.Jenkins; 28 | import net.bull.javamelody.internal.common.LOG; 29 | import net.bull.javamelody.internal.common.Parameters; 30 | import net.bull.javamelody.internal.model.Collector; 31 | import net.bull.javamelody.internal.model.Counter; 32 | import net.bull.javamelody.internal.model.JavaInformations; 33 | import net.bull.javamelody.internal.model.Period; 34 | import net.bull.javamelody.internal.web.MailReport; 35 | 36 | /** 37 | * Collector of data for Hudson/Jenkins' nodes (slaves in general) 38 | * @author Emeric Vernat 39 | */ 40 | public class NodesCollector { 41 | private final boolean monitoringDisabled; 42 | private final Timer timer; 43 | private final Collector collector; 44 | private Map lastJavaInformationsList; 45 | 46 | private static class RemoteCollector extends Collector { 47 | RemoteCollector(String application, List counters) { 48 | super(application, counters); 49 | } 50 | 51 | /** {@inheritDoc} */ 52 | @Override 53 | public void collectLocalContextWithoutErrors() { 54 | // no local collect 55 | } 56 | } 57 | 58 | /** 59 | * Constructor. 60 | * @param filter Http filter to get the scheduling timer 61 | */ 62 | public NodesCollector(MonitoringFilter filter) { 63 | super(); 64 | this.monitoringDisabled = Parameter.DISABLED.getValueAsBoolean(); 65 | if (!monitoringDisabled) { 66 | this.timer = filter.getFilterContext().getTimer(); 67 | final List counters = Collections 68 | .singletonList(CounterRunListener.getBuildCounter()); 69 | this.collector = new RemoteCollector("nodes", counters); 70 | } else { 71 | this.timer = null; 72 | this.collector = null; 73 | } 74 | } 75 | 76 | /** 77 | * Initialization. 78 | */ 79 | public void init() { 80 | if (monitoringDisabled) { 81 | return; 82 | } 83 | final int periodMillis = Parameters.getResolutionSeconds() * 1000; 84 | // schedule of a background task, with an asynchronous execution now to 85 | // initialize the data 86 | final TimerTask collectTask = new TimerTask() { 87 | /** {@inheritDoc} */ 88 | @Override 89 | public void run() { 90 | // errors must not happen in this task 91 | collectWithoutErrors(); 92 | } 93 | }; 94 | timer.schedule(collectTask, 5000, periodMillis); 95 | 96 | // schedule to send reports by email 97 | if (Parameter.MAIL_SESSION.getValue() != null 98 | && Parameter.ADMIN_EMAILS.getValue() != null) { 99 | scheduleReportMailForSlaves(); 100 | } 101 | } 102 | 103 | /** 104 | * Schedule a collect now (used to collect data on new online nodes) 105 | */ 106 | public void scheduleCollectNow() { 107 | if (monitoringDisabled) { 108 | return; 109 | } 110 | final TimerTask collectTask = new TimerTask() { 111 | /** {@inheritDoc} */ 112 | @Override 113 | public void run() { 114 | // errors must not happen in this task 115 | collectWithoutErrors(); 116 | } 117 | }; 118 | timer.schedule(collectTask, 0); 119 | } 120 | 121 | /** 122 | * Stop the collector. 123 | */ 124 | public void stop() { 125 | if (monitoringDisabled) { 126 | return; 127 | } 128 | timer.cancel(); 129 | collector.stop(); 130 | } 131 | 132 | boolean isNodesMonitoringDisabled() { 133 | // if system property "javamelody.nodes-monitoring-disabled" is true, 134 | // then no periodic monitoring for nodes (only for master and nodes when nodes report requested) 135 | return Boolean.parseBoolean(System.getProperty("javamelody.nodes-monitoring-disabled")); 136 | } 137 | 138 | /** 139 | * Collect the data (and never throws any exception). 140 | */ 141 | public void collectWithoutErrors() { 142 | try { 143 | // reevaluate each time to disable or reenable at runtime 144 | if (isNodesMonitoringDisabled()) { 145 | return; 146 | } 147 | collectWithoutErrorsNow(); 148 | } catch (final Throwable t) { // NOPMD 149 | LOG.warn("exception while collecting data", t); 150 | } 151 | } 152 | 153 | /** 154 | * Collect the data (and never throws any exception). 155 | */ 156 | public void collectWithoutErrorsNow() { 157 | try { 158 | lastJavaInformationsList = new RemoteCallHelper(null) 159 | .collectJavaInformationsListByName(); 160 | 161 | // inspired by https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/model/LoadStatistics.java#L197 162 | // but with blocked items added and so getItems() instead of getBuildableItems() 163 | // (getBlockedItems() is protected and unaccessible, getItems() is about 5 times longer than getBuildableItems()) 164 | final Jenkins jenkins = Jenkins.get(); 165 | final int queueLength = jenkins.getQueue().getItems().length; 166 | // note: this BUILD_QUEUE_LENGTH needs values for buildQueueLength in translations*.properties of javamelody-core 167 | JdbcWrapper.BUILD_QUEUE_LENGTH.set(queueLength); 168 | final long waitingDurationsSum = WaitingDurationQueueListener.getWaitingDurationsSum(); 169 | JdbcWrapper.BUILD_QUEUE_WAITING_DURATIONS_SUM.set(waitingDurationsSum); 170 | 171 | final List javaInformations = new ArrayList<>( 172 | getLastJavaInformationsList().values()); 173 | collector.collectWithoutErrors(javaInformations); 174 | } catch (final Throwable t) { // NOPMD 175 | LOG.warn("exception while collecting data", t); 176 | } 177 | } 178 | 179 | private void scheduleReportMailForSlaves() { 180 | for (final Period period : MailReport.getMailPeriods()) { 181 | scheduleReportMailForSlaves(period); 182 | } 183 | } 184 | 185 | void scheduleReportMailForSlaves(final Period period) { 186 | assert period != null; 187 | final TimerTask task = new TimerTask() { 188 | /** {@inheritDoc} */ 189 | @Override 190 | public void run() { 191 | try { 192 | // send the report 193 | final List javaInformations = new ArrayList<>( 194 | getLastJavaInformationsList().values()); 195 | new MailReport().sendReportMail(getCollector(), true, javaInformations, period); 196 | } catch (final Throwable t) { // NOPMD 197 | // no error in this task 198 | LOG.warn("sending mail report failed", t); 199 | } 200 | // schedule again at the same hour next day or next week without 201 | // using a fixed period, because some days have 23h or 25h and 202 | // we do not want to have a change in the hour for sending the 203 | // report 204 | scheduleReportMailForSlaves(period); 205 | } 206 | }; 207 | 208 | // schedule the task once 209 | timer.schedule(task, MailReport.getNextExecutionDate(period)); 210 | } 211 | 212 | Collector getCollector() { 213 | return collector; 214 | } 215 | 216 | Map getLastJavaInformationsList() { 217 | return lastJavaInformationsList; 218 | } 219 | 220 | /** 221 | * Is the monitoring disabled? 222 | * @return boolean 223 | */ 224 | public boolean isMonitoringDisabled() { 225 | return monitoringDisabled; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/main/java/net/bull/javamelody/RemoteCallHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package net.bull.javamelody; 19 | 20 | import java.io.IOException; 21 | import java.util.ArrayList; 22 | import java.util.LinkedHashMap; 23 | import java.util.List; 24 | import java.util.Locale; 25 | import java.util.Map; 26 | import java.util.concurrent.TimeUnit; 27 | import java.util.concurrent.TimeoutException; 28 | 29 | import hudson.model.Computer; 30 | import hudson.remoting.Callable; 31 | import hudson.remoting.Future; 32 | import jenkins.model.Jenkins; 33 | import jenkins.security.MasterToSlaveCallable; 34 | import net.bull.javamelody.internal.common.I18N; 35 | import net.bull.javamelody.internal.model.Action; 36 | import net.bull.javamelody.internal.model.HeapHistogram; 37 | import net.bull.javamelody.internal.model.JavaInformations; 38 | import net.bull.javamelody.internal.model.MBeanNode; 39 | import net.bull.javamelody.internal.model.MBeans; 40 | import net.bull.javamelody.internal.model.ProcessInformations; 41 | import net.bull.javamelody.internal.model.VirtualMachine; 42 | 43 | final class RemoteCallHelper { 44 | private static final MasterToSlaveCallable JAVA_INFORMATIONS_TASK = new JavaInformationsTask(); 45 | private static final MasterToSlaveCallable HEAP_HISTOGRAM_TASK = new HeapHistogramTask(); 46 | private static final MasterToSlaveCallable, Throwable> PROCESS_INFORMATIONS_TASK = new ProcessInformationsTask(); 47 | private static final MasterToSlaveCallable, Throwable> MBEANS_TASK = new MBeansTask(); 48 | 49 | private static final class MBeansTask 50 | extends MasterToSlaveCallable, Throwable> { 51 | private static final long serialVersionUID = 7010512609895185019L; 52 | 53 | MBeansTask() { 54 | super(); 55 | } 56 | 57 | @Override 58 | public List call() throws Throwable { 59 | return MBeans.getAllMBeanNodes(); 60 | } 61 | } 62 | 63 | private static final class ProcessInformationsTask 64 | extends MasterToSlaveCallable, Throwable> { 65 | private static final long serialVersionUID = -4653173833541398792L; 66 | 67 | ProcessInformationsTask() { 68 | super(); 69 | } 70 | 71 | @Override 72 | public List call() throws Throwable { 73 | return ProcessInformations.buildProcessInformations(); 74 | } 75 | } 76 | 77 | private static final class HeapHistogramTask 78 | extends MasterToSlaveCallable { 79 | private static final long serialVersionUID = -3978979765596110525L; 80 | 81 | HeapHistogramTask() { 82 | super(); 83 | } 84 | 85 | @Override 86 | public HeapHistogram call() throws Throwable { 87 | if (VirtualMachine.isSupported()) { 88 | return VirtualMachine.createHeapHistogram(); 89 | } 90 | return null; 91 | } 92 | } 93 | 94 | private static final class JavaInformationsTask 95 | extends MasterToSlaveCallable { 96 | private static final long serialVersionUID = 4778731836785411552L; 97 | 98 | JavaInformationsTask() { 99 | super(); 100 | } 101 | 102 | @Override 103 | public JavaInformations call() throws Throwable { 104 | // otherwise static values of the Hudson/Jenkins master are used, but web.xml does not exist 105 | // on the slaves (pom.xml exists and will not be displayed without dependencies) 106 | JavaInformations.setWebXmlExistsAndPomXmlExists(false, true); 107 | Parameter.NO_DATABASE.setValue("true"); 108 | return new JavaInformations(null, true); 109 | } 110 | } 111 | 112 | private static final class ActionTask extends MasterToSlaveCallable { 113 | private static final long serialVersionUID = -3978979765596110525L; 114 | private final String actionName; 115 | private final String sessionId; 116 | private final String threadId; 117 | private final String jobId; 118 | private final String cacheId; 119 | 120 | ActionTask(String actionName, String sessionId, String threadId, String jobId, 121 | String cacheId) { 122 | super(); 123 | this.actionName = actionName; 124 | this.sessionId = sessionId; 125 | this.threadId = threadId; 126 | this.jobId = jobId; 127 | this.cacheId = cacheId; 128 | } 129 | 130 | @Override 131 | public String call() throws Throwable { 132 | final Action action = Action.valueOfIgnoreCase(actionName); 133 | return action.execute(null, null, null, sessionId, threadId, jobId, cacheId); 134 | } 135 | } 136 | 137 | private static class JmxValueTask extends MasterToSlaveCallable { 138 | private static final long serialVersionUID = -4654080667819214726L; 139 | private final String jmxValueParameter; 140 | 141 | JmxValueTask(String jmxValueParameter) { 142 | super(); 143 | this.jmxValueParameter = jmxValueParameter; 144 | } 145 | 146 | @Override 147 | public String call() throws Throwable { 148 | return MBeans.getConvertedAttributes(jmxValueParameter); 149 | } 150 | } 151 | 152 | private static class DelegatingTask extends MasterToSlaveCallable { 153 | private static final long serialVersionUID = -8596757920851396797L; 154 | private final Callable delegate; 155 | private final Locale locale; 156 | 157 | DelegatingTask(Callable delegate) { 158 | super(); 159 | this.delegate = delegate; 160 | this.locale = I18N.getCurrentLocale(); 161 | } 162 | 163 | @Override 164 | public T call() throws Throwable { 165 | I18N.bindLocale(locale); 166 | try { 167 | return delegate.call(); 168 | } finally { 169 | I18N.unbindLocale(); 170 | } 171 | } 172 | } 173 | 174 | private final String nodeName; 175 | 176 | RemoteCallHelper(String nodeName) { 177 | super(); 178 | this.nodeName = nodeName; 179 | } 180 | 181 | private Map collectDataByNodeName(Callable task) 182 | throws IOException { 183 | final Jenkins jenkins = Jenkins.get(); 184 | final Computer[] computers = jenkins.getComputers(); 185 | final Map> futuresByNodeName = new LinkedHashMap<>(computers.length); 186 | final DelegatingTask delegatingTask = new DelegatingTask<>(task); 187 | for (final Computer c : computers) { 188 | if (c.isOnline() && (nodeName == null || nodeName.equals(c.getName()))) { 189 | futuresByNodeName.put(c.getName(), c.getChannel().callAsync(delegatingTask)); 190 | } 191 | } 192 | final long now = System.currentTimeMillis(); 193 | // timeout dans 59 secondes 194 | final long end = now + TimeUnit.SECONDS.toMillis(59); 195 | 196 | final Map result = new LinkedHashMap<>(futuresByNodeName.size()); 197 | for (final Map.Entry> entry : futuresByNodeName.entrySet()) { 198 | final String node = entry.getKey(); 199 | final Future future = entry.getValue(); 200 | final long timeout = Math.max(0, end - System.currentTimeMillis()); 201 | try { 202 | result.put(node, future.get(timeout, TimeUnit.MILLISECONDS)); 203 | } catch (final TimeoutException e) { 204 | continue; 205 | } catch (final Throwable e) { 206 | // JENKINS-45963 (FreeBSD): if collect fails for one node, continue with others 207 | continue; 208 | } 209 | } 210 | return result; 211 | } 212 | 213 | Map collectJavaInformationsListByName() throws IOException { 214 | return collectDataByNodeName(JAVA_INFORMATIONS_TASK); 215 | } 216 | 217 | List collectJmxValues(String jmxValueParameter) throws IOException { 218 | return new ArrayList<>(collectDataByNodeName(new JmxValueTask(jmxValueParameter)).values()); 219 | } 220 | 221 | Map> collectMBeanNodesByNodeName() throws IOException { 222 | return collectDataByNodeName(MBEANS_TASK); 223 | } 224 | 225 | Map> collectProcessInformationsByNodeName() 226 | throws IOException { 227 | return collectDataByNodeName(PROCESS_INFORMATIONS_TASK); 228 | } 229 | 230 | HeapHistogram collectGlobalHeapHistogram() throws IOException { 231 | final Map heapHistograms = collectDataByNodeName( 232 | HEAP_HISTOGRAM_TASK); 233 | HeapHistogram heapHistoTotal = null; 234 | for (final HeapHistogram heapHisto : heapHistograms.values()) { 235 | if (heapHistoTotal == null) { 236 | heapHistoTotal = heapHisto; 237 | } else if (heapHisto != null) { 238 | heapHistoTotal.add(heapHisto); 239 | } 240 | } 241 | if (heapHistoTotal == null) { 242 | throw new IllegalStateException(I18N.getString("heap_histo_non_supporte")); 243 | } 244 | return heapHistoTotal; 245 | } 246 | 247 | String forwardAction(String actionName, String sessionId, String threadId, String jobId, 248 | String cacheId) throws IOException { 249 | final ActionTask task = new ActionTask(actionName, sessionId, threadId, jobId, cacheId); 250 | final Map messagesByNodeName = collectDataByNodeName(task); 251 | final StringBuilder sb = new StringBuilder(); 252 | for (final String messageForReport : messagesByNodeName.values()) { 253 | if (messageForReport != null) { 254 | sb.append(messageForReport).append('\n'); 255 | } 256 | } 257 | final String messageForReport; 258 | if (sb.length() == 0) { 259 | messageForReport = null; 260 | } else { 261 | messageForReport = sb.toString(); 262 | } 263 | return messageForReport; 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/MonitoringScripts.md: -------------------------------------------------------------------------------- 1 | Monitoring scripts 2 | ================== 3 | 4 | Several scripts to display data about http sessions, threads, memory, 5 | JVM or MBeans, when using the [Monitoring plugin](https://plugins.jenkins.io/monitoring). 6 | 7 | # Jenkins Script Console 8 | 9 | Jenkins features a nice Groovy script console which allows to run 10 | arbitrary scripts on the Jenkins server (or on slave nodes). This 11 | feature can be accessed from the "manage Jenkins" link, typically at 12 | your . See [more information and scripts](https://wiki.jenkins.io/display/JENKINS/Jenkins+Script+Console). 13 | 14 | # Monitoring Scripts and Alerts for the Jenkins instance 15 | 16 | If the [Monitoring plugin](https://plugins.jenkins.io/monitoring) is installed, you can also use the following 17 | monitoring scripts in the **Jenkins script console**. To run a script 18 | periodically, you could also create and schedule a job to execute a 19 | **system groovy script** with the [groovy plugin](https://wiki.jenkins.io/display/JENKINS/Groovy+plugin). (A system Groovy script 20 | executes insides Jenkins instance's JVM, but see below for specific 21 | scripts for Jenkins slaves.) 22 | 23 | The data printed by the scripts below can be displayed by the reports of 24 | the [Monitoring plugin](https://plugins.jenkins.io/monitoring), but the scripts can be used and customized to 25 | display some particular data or to automate some action. 26 | 27 | #### Execute GC 28 | 29 | ```groovy 30 | import net.bull.javamelody.*; 31 | import net.bull.javamelody.internal.model.*; 32 | import net.bull.javamelody.internal.common.*; 33 | before = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); 34 | System.gc(); 35 | after = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); 36 | println I18N.getFormattedString("ramasse_miette_execute", Math.round((before - after) / 1024)); 37 | ``` 38 | 39 | #### Display HTTP sessions 40 | 41 | ```groovy 42 | import net.bull.javamelody.*; 43 | import net.bull.javamelody.internal.model.*; 44 | import net.bull.javamelody.internal.common.*; 45 | println SessionListener.getSessionCount() + " sessions:"; 46 | sessions = SessionListener.getAllSessionsInformations(); 47 | for (session in sessions) { 48 | println session; 49 | } 50 | ``` 51 | 52 | #### Display a simple threads dump 53 | 54 | ```groovy 55 | import net.bull.javamelody.*; 56 | import net.bull.javamelody.internal.model.*; 57 | import net.bull.javamelody.internal.common.*; 58 | java = new JavaInformations(Parameters.getServletContext(), true); 59 | threads = java.getThreadInformationsList(); 60 | println threads.size() + " threads (" + java.activeThreadCount + " http threads active):"; 61 | for (thread in threads) { 62 | println ""; 63 | println thread; 64 | for (s in thread.getStackTrace()) 65 | println " " + s; 66 | } 67 | ``` 68 | 69 | #### Display deadlocked threads 70 | 71 | ```groovy 72 | import net.bull.javamelody.*; 73 | import net.bull.javamelody.internal.model.*; 74 | import net.bull.javamelody.internal.common.*; 75 | java = new JavaInformations(Parameters.getServletContext(), true); 76 | threads = java.getThreadInformationsList(); 77 | deadlocked = new java.util.ArrayList(); 78 | for (thread in threads) { 79 | if (thread.deadlocked) 80 | deadlocked.add(thread); 81 | } 82 | println deadlocked.size() + " deadlocked threads / " + threads.size() + " threads (" + java.activeThreadCount + " http threads active)"; 83 | for (thread in deadlocked) { 84 | println ""; 85 | println thread; 86 | for (s in thread.getStackTrace()) 87 | println " " + s; 88 | } 89 | ``` 90 | 91 | #### Display some memory data 92 | 93 | ```groovy 94 | import net.bull.javamelody.*; 95 | import net.bull.javamelody.internal.model.*; 96 | import net.bull.javamelody.internal.common.*; 97 | memory = new MemoryInformations(); 98 | println "\nused memory:\n " + Math.round(memory.usedMemory / 1024 / 1024) + " Mb"; 99 | println "\nmax memory:\n " + Math.round(memory.maxMemory / 1024 / 1024) + " Mb"; 100 | println "\nused perm gen:\n " + Math.round(memory.usedPermGen / 1024 / 1024) + " Mb"; 101 | println "\nmax perm gen:\n " + Math.round(memory.maxPermGen / 1024 / 1024) + " Mb"; 102 | println "\nused non heap:\n " + Math.round(memory.usedNonHeapMemory / 1024 / 1024) + " Mb"; 103 | println "\nused physical memory:\n " + Math.round(memory.usedPhysicalMemorySize / 1024 / 1024) + " Mb"; 104 | println "\nused swap space:\n " + Math.round(memory.usedSwapSpaceSize / 1024 / 1024) + " Mb"; 105 | ``` 106 | 107 | #### Display some JVM data 108 | 109 | ```groovy 110 | import net.bull.javamelody.*; 111 | import net.bull.javamelody.internal.model.*; 112 | import net.bull.javamelody.internal.common.*; 113 | java = new JavaInformations(Parameters.getServletContext(), true); 114 | println "\nsessions count:\n " + java.sessionCount; 115 | println "\nactive HTTP threads count:\n " + java.activeThreadCount; 116 | println "\nthreads count:\n " + java.threadCount; 117 | println "\nsystem load average:\n " + java.systemLoadAverage; 118 | println "\nsystem cpu load:\n " + java.systemCpuLoad; 119 | println "\navailable processors:\n " + java.availableProcessors; 120 | println "\nhost:\n " + java.host; 121 | println "\nos:\n " + java.os; 122 | println "\njava version:\n " + java.javaVersion; 123 | println "\njvm version:\n " + java.jvmVersion; 124 | println "\npid:\n " + java.pid; 125 | println "\nserver info:\n " + java.serverInfo; 126 | println "\ncontext path:\n " + java.contextPath; 127 | println "\nstart date:\n " + java.startDate; 128 | println "\nfree disk space in Jenkins directory:\n " + Math.round(java.freeDiskSpaceInTemp / 1024 / 1024) + " Mb"; 129 | ``` 130 | 131 | #### Display heap histogram (object instances per class) 132 | 133 | ```groovy 134 | import net.bull.javamelody.*; 135 | import net.bull.javamelody.internal.model.*; 136 | import net.bull.javamelody.internal.common.*; 137 | classes = VirtualMachine.createHeapHistogram().getHeapHistogram(); 138 | println "class instances bytes source"; 139 | println "====================================="; 140 | for (c in classes) { 141 | println c.name + " " + c.instancesCount + " " + c.bytes + " " + c.source; 142 | } 143 | ``` 144 | 145 | #### Take a heap dump 146 | 147 | ```groovy 148 | import net.bull.javamelody.*; 149 | import net.bull.javamelody.internal.model.*; 150 | import net.bull.javamelody.internal.common.*; 151 | if (System.getProperty("java.vendor").contains("IBM")) { 152 | Action.HEAP_DUMP.ibmHeapDump(); 153 | println I18N.getString("heap_dump_genere_ibm"); 154 | } else { 155 | heapDumpPath = Action.HEAP_DUMP.heapDump().getPath(); 156 | println I18N.getFormattedString("heap_dump_genere", heapDumpPath); 157 | } 158 | ``` 159 | 160 | #### Display some MBean attribute value 161 | 162 | ```groovy 163 | import net.bull.javamelody.*; 164 | import net.bull.javamelody.internal.model.*; 165 | import net.bull.javamelody.internal.common.*; 166 | exampleAttribute = "java.lang:type=OperatingSystem.ProcessCpuTime"; 167 | println exampleAttribute + " = " + MBeans.getConvertedAttributes(exampleAttribute); 168 | ``` 169 | 170 | #### Display stats of builds and build steps having mean time greater than severe threshold 171 | 172 | (By default, severe threshold = 2 x stddev of all durations and warning threshold = 1 x stddev) 173 | 174 | ```groovy 175 | import net.bull.javamelody.*; 176 | import net.bull.javamelody.internal.model.*; 177 | import net.bull.javamelody.internal.common.*; 178 | buildCounter = CounterRunListener.getBuildCounter(); 179 | aggreg = new CounterRequestAggregation(buildCounter); 180 | for (request in aggreg.getRequests()) { 181 | if (request.getMean() >= aggreg.getSevereThreshold() || request.getCpuTimeMean() >= aggreg.getSevereThreshold()) { 182 | println(request.getName() 183 | + ", hits=" + request.getHits() 184 | + ", mean=" + request.getMean() 185 | + ", max=" + request.getMaximum() 186 | + ", stddev=" + request.getStandardDeviation() 187 | + ", cpuTimeMean=" + request.getCpuTimeMean() 188 | + ", systemErrorPercentage=" + request.getSystemErrorPercentage()); 189 | } 190 | } 191 | ``` 192 | 193 | #### Alerts 194 | 195 | You can send alerts with a Jenkins job, using a **system groovy script** with the [groovy plugin](https://plugins.jenkins.io/groovy). 196 | 197 | Suppose that you want to check every 15 minutes on the Jenkins instance, if the system load average is above 50 or if the active HTTP threads 198 | count is above 100 or if there are deadlocked threads or if there are less than 10 Gb free disk space left: 199 | 200 | * Create a freestyle job in Jenkins by clicking "New item". 201 | * Check "Build periodically" and write a schedule, "*/15 * * * *" for example. 202 | * Add a build step "Execute system Groovy script" and write a script: 203 | 204 | ```groovy 205 | import net.bull.javamelody.*; 206 | import net.bull.javamelody.internal.model.*; 207 | import net.bull.javamelody.internal.common.*; 208 | java = new JavaInformations(Parameters.getServletContext(), true); 209 | memory = java.memoryInformations; 210 | println "used memory = " + Math.round(memory.usedMemory / 1024 / 1024) + " Mb"; 211 | println "active HTTP threads count = " + java.activeThreadCount; 212 | println "system load average = " + java.systemLoadAverage; 213 | println "free disk space in Jenkins directory = " + Math.round(java.freeDiskSpaceInTemp / 1024 / 1024) + " Mb"; 214 | threads = java.getThreadInformationsList(); 215 | deadlocked = new java.util.ArrayList(); 216 | for (thread in threads) { 217 | if (thread.deadlocked) 218 | deadlocked.add(thread); 219 | } 220 | println deadlocked.size() + " deadlocked threads / " + threads.size() + " threads"; 221 | for (thread in deadlocked) { 222 | println ""; 223 | println thread; 224 | for (s in thread.getStackTrace()) 225 | println " " + s; 226 | } 227 | if (java.systemLoadAverage > 50) throw new Exception("Alert for Jenkins: systemLoadAverage is " + java.systemLoadAverage); 228 | if (java.activeThreadCount > 100) throw new Exception("Alert for Jenkins: activeThreadCount is " + java.activeThreadCount); 229 | if (deadlocked.size() > 0) throw new Exception("Alert for Jenkins: " + deadlocked.size() + " deadlocked threads"); 230 | if (java.freeDiskSpaceInTemp / 1024 / 1024 < 10000) throw new Exception("Alert for Jenkins: only " + Math.round(java.freeDiskSpaceInTemp / 1024 / 1024) + " Mb free disk space left"); 231 | ``` 232 | 233 | Or any script with monitoring values in this page. 234 | 235 | * Add a post-build action "E-mail Notification" and write your email in "Recipients". 236 | * You can also configure "Discard old builds" and write a description. 237 | * Save. 238 | * Click "Build now" to test it. 239 | 240 | # Monitoring Scripts for Jenkins slaves 241 | 242 | In the following scripts, `new RemoteCallHelper(null)` can be used to get data for all online slaves, or `new RemoteCallHelper("my-slave")` for a particular slave named "my-slave". 243 | 244 | #### Display jvm data, memory data, deadlocked threads by node, stack-traces of threads 245 | 246 | ```groovy 247 | import net.bull.javamelody.*; 248 | import net.bull.javamelody.internal.model.*; 249 | import net.bull.javamelody.internal.common.*; 250 | String nodeName = null; // null for all nodes, not null for a particular node 251 | Map mapByNodeName = new RemoteCallHelper(nodeName).collectJavaInformationsListByName(); 252 | for (node in mapByNodeName.keySet()) { 253 | java = mapByNodeName.get(node); 254 | println "\nNode:\n " + node; 255 | println "\nsessions count:\n " + java.sessionCount; 256 | println "\nactive HTTP threads count:\n " + java.activeThreadCount; 257 | println "\nthreads count:\n " + java.threadCount; 258 | println "\nsystem load average:\n " + java.systemLoadAverage; 259 | println "\nsystem cpu load:\n " + java.systemCpuLoad; 260 | println "\navailable processors:\n " + java.availableProcessors; 261 | println "\nhost:\n " + java.host; 262 | println "\nos:\n " + java.os; 263 | println "\njava version:\n " + java.javaVersion; 264 | println "\njvm version:\n " + java.jvmVersion; 265 | println "\npid:\n " + java.pid; 266 | println "\nserver info:\n " + java.serverInfo; 267 | println "\ncontext path:\n " + java.contextPath; 268 | println "\nstart date:\n " + java.startDate; 269 | println ""; 270 | memory = java.memoryInformations; 271 | println "\nused memory:\n " + Math.round(memory.usedMemory / 1024 / 1024) + " Mb"; 272 | println "\nmax memory:\n " + Math.round(memory.maxMemory / 1024 / 1024) + " Mb"; 273 | println "\nused perm gen:\n " + Math.round(memory.usedPermGen / 1024 / 1024) + " Mb"; 274 | println "\nmax perm gen:\n " + Math.round(memory.maxPermGen / 1024 / 1024) + " Mb"; 275 | println "\nused non heap:\n " + Math.round(memory.usedNonHeapMemory / 1024 / 1024) + " Mb"; 276 | println "\nused physical memory:\n " + Math.round(memory.usedPhysicalMemorySize / 1024 / 1024) + " Mb"; 277 | println "\nused swap space:\n " + Math.round(memory.usedSwapSpaceSize / 1024 / 1024) + " Mb"; 278 | println ""; 279 | threads = java.getThreadInformationsList(); 280 | deadlocked = new java.util.ArrayList(); 281 | for (thread in threads) { 282 | if (thread.deadlocked) 283 | deadlocked.add(thread); 284 | } 285 | println deadlocked.size() + " deadlocked threads / " + threads.size() + " threads (" + java.activeThreadCount + " threads active)"; 286 | for (thread in deadlocked) { 287 | println ""; 288 | println thread; 289 | for (s in thread.getStackTrace()) 290 | println " " + s; 291 | } 292 | println ""; 293 | println "*************************************************************"; 294 | println ""; 295 | } 296 | ``` 297 | 298 | #### Display some MBean attributes values by node 299 | 300 | ```groovy 301 | import net.bull.javamelody.*; 302 | import net.bull.javamelody.internal.model.*; 303 | import net.bull.javamelody.internal.common.*; 304 | String exampleAttributes = "java.lang:type=OperatingSystem.ProcessCpuTime|java.lang:type=Memory.HeapMemoryUsage"; 305 | String nodeName = null; // null for all nodes, not null for a particular node 306 | List values = new RemoteCallHelper(nodeName).collectJmxValues(exampleAttributes); 307 | for (String value in values) { 308 | println exampleAttributes + " = " + value; 309 | } 310 | ``` 311 | -------------------------------------------------------------------------------- /src/main/java/net/bull/javamelody/NodesController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008-2019 by Emeric Vernat 3 | * 4 | * This file is part of the Monitoring plugin. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package net.bull.javamelody; 19 | 20 | import java.io.IOException; 21 | import java.io.PrintWriter; 22 | import java.io.Serializable; 23 | import java.util.ArrayList; 24 | import java.util.Collections; 25 | import java.util.LinkedHashMap; 26 | import java.util.List; 27 | import java.util.Map; 28 | 29 | import jakarta.servlet.ServletException; 30 | import jakarta.servlet.http.HttpServletRequest; 31 | import jakarta.servlet.http.HttpServletResponse; 32 | 33 | import net.bull.javamelody.internal.common.HttpParameter; 34 | import net.bull.javamelody.internal.common.HttpPart; 35 | import net.bull.javamelody.internal.common.I18N; 36 | import net.bull.javamelody.internal.model.Action; 37 | import net.bull.javamelody.internal.model.Collector; 38 | import net.bull.javamelody.internal.model.HeapHistogram; 39 | import net.bull.javamelody.internal.model.JavaInformations; 40 | import net.bull.javamelody.internal.model.MBeanNode; 41 | import net.bull.javamelody.internal.model.Period; 42 | import net.bull.javamelody.internal.model.ProcessInformations; 43 | import net.bull.javamelody.internal.model.Range; 44 | import net.bull.javamelody.internal.model.ThreadInformations; 45 | import net.bull.javamelody.internal.model.TransportFormat; 46 | import net.bull.javamelody.internal.web.HtmlController; 47 | import net.bull.javamelody.internal.web.HttpCookieManager; 48 | import net.bull.javamelody.internal.web.MonitoringController; 49 | import net.bull.javamelody.internal.web.SerializableController; 50 | import net.bull.javamelody.internal.web.html.HtmlReport; 51 | import net.bull.javamelody.internal.web.pdf.PdfOtherReport; 52 | 53 | /** 54 | * Controller between data and presentation for Hudson/Jenkins' nodes (slaves in 55 | * general) 56 | * @author Emeric Vernat 57 | */ 58 | public class NodesController { 59 | /** 60 | * For HudsonMonitoringFilter. 61 | */ 62 | public static final String SESSION_REMOTE_USER = SessionListener.SESSION_REMOTE_USER; 63 | 64 | private final Collector collector; 65 | private final String nodeName; 66 | private final List lastJavaInformationsList; 67 | private final HttpCookieManager httpCookieManager = new HttpCookieManager(); 68 | 69 | /** 70 | * Constructor. 71 | * @param nodesCollector NodesCollector 72 | * @param nodeName Nom du node 73 | */ 74 | public NodesController(NodesCollector nodesCollector, String nodeName) { 75 | super(); 76 | this.collector = nodesCollector.getCollector(); 77 | this.nodeName = nodeName; 78 | if (nodeName == null) { 79 | this.lastJavaInformationsList = new ArrayList<>( 80 | nodesCollector.getLastJavaInformationsList().values()); 81 | } else { 82 | this.lastJavaInformationsList = Collections 83 | .singletonList(nodesCollector.getLastJavaInformationsList().get(nodeName)); 84 | } 85 | } 86 | 87 | /** 88 | * Generate a report 89 | * @param req Http request 90 | * @param resp Http response 91 | * @throws IOException e 92 | */ 93 | public void doMonitoring(HttpServletRequest req, HttpServletResponse resp) throws IOException { 94 | if (lastJavaInformationsList != null && !lastJavaInformationsList.isEmpty()) { 95 | try { 96 | // preferred language of the browser, getLocale can't be null 97 | I18N.bindLocale(req.getLocale()); 98 | 99 | final MonitoringController monitoringController = new MonitoringController( 100 | collector, null); 101 | final String partParameter = HttpParameter.PART.getParameterFrom(req); 102 | final String actionParameter = HttpParameter.ACTION.getParameterFrom(req); 103 | if (actionParameter != null) { 104 | final Action action = Action.valueOfIgnoreCase(actionParameter); 105 | final String messageForReport; 106 | if (action != Action.CLEAR_COUNTER && action != Action.PURGE_OBSOLETE_FILES 107 | && action != Action.LOGOUT) { 108 | // on forwarde l'action (gc ou heap dump) sur le(s) node(s) 109 | // et on recupere les informations a jour (notamment memoire) 110 | final String actionName = HttpParameter.ACTION.getParameterFrom(req); 111 | final String sessionId = HttpParameter.SESSION_ID.getParameterFrom(req); 112 | final String threadId = HttpParameter.THREAD_ID.getParameterFrom(req); 113 | final String jobId = HttpParameter.JOB_ID.getParameterFrom(req); 114 | final String cacheId = HttpParameter.CACHE_ID.getParameterFrom(req); 115 | messageForReport = getRemoteCallHelper().forwardAction(actionName, 116 | sessionId, threadId, jobId, cacheId); 117 | } else { 118 | // necessaire si action clear_counter 119 | messageForReport = monitoringController.executeActionIfNeeded(req); 120 | } 121 | if (TransportFormat 122 | .isATransportFormat(HttpParameter.FORMAT.getParameterFrom(req))) { 123 | final SerializableController serializableController = new SerializableController( 124 | collector); 125 | final Range range = serializableController.getRangeForSerializable(req); 126 | final List javaInformationsList = new ArrayList<>( 127 | getRemoteCallHelper().collectJavaInformationsListByName().values()); 128 | final Serializable serializable = serializableController 129 | .createDefaultSerializable(javaInformationsList, range, 130 | messageForReport); 131 | monitoringController.doCompressedSerializable(req, resp, serializable); 132 | } else { 133 | writeMessage(resp, messageForReport, partParameter); 134 | } 135 | return; 136 | } 137 | 138 | final String formatParameter = HttpParameter.FORMAT.getParameterFrom(req); 139 | if (HttpParameter.JMX_VALUE.getParameterFrom(req) != null) { 140 | final List jmxValues = getRemoteCallHelper() 141 | .collectJmxValues(HttpParameter.JMX_VALUE.getParameterFrom(req)); 142 | doJmxValue(resp, jmxValues); 143 | } else if (TransportFormat 144 | .isATransportFormat(HttpParameter.FORMAT.getParameterFrom(req))) { 145 | doCompressedSerializable(req, resp, monitoringController); 146 | } else if ("pdf".equalsIgnoreCase(formatParameter)) { 147 | doPdf(req, resp, monitoringController); 148 | } else if (partParameter == null) { 149 | monitoringController.doReport(req, resp, lastJavaInformationsList); 150 | } else { 151 | doPart(req, resp, monitoringController); 152 | } 153 | } catch (final Throwable e) { // NOPMD 154 | writeMessage(resp, e.getMessage(), null); 155 | } finally { 156 | I18N.unbindLocale(); 157 | } 158 | } else { 159 | MonitoringController.noCache(resp); 160 | resp.setContentType("text/html; charset=UTF-8"); 161 | final PrintWriter writer = resp.getWriter(); 162 | writer.write(""); 163 | writer.write("Back to Manage Jenkins"); 164 | writer.write("     "); 165 | writer.write("Update"); 166 | writer.write("

No agents online, try again in a minute."); 167 | writer.write(""); 168 | writer.close(); 169 | } 170 | } 171 | 172 | private void writeMessage(HttpServletResponse resp, String message, String partToRedirectTo) 173 | throws IOException { 174 | MonitoringController.noCache(resp); 175 | final PrintWriter writer = createWriterFromOutputStream(resp); 176 | // la periode n'a pas d'importance pour writeMessageIfNotNull 177 | new HtmlReport(collector, null, lastJavaInformationsList, Period.TOUT, writer) 178 | .writeMessageIfNotNull(message, partToRedirectTo); 179 | writer.close(); 180 | } 181 | 182 | private void doPdf(HttpServletRequest req, HttpServletResponse resp, 183 | MonitoringController monitoringController) throws IOException, ServletException { 184 | if (HttpPart.PROCESSES.isPart(req)) { 185 | monitoringController.addPdfContentTypeAndDisposition(req, resp); 186 | final Map> processInformationsByNodeName = getRemoteCallHelper() 187 | .collectProcessInformationsByNodeName(); 188 | try { 189 | doPdfProcesses(resp, processInformationsByNodeName); 190 | } finally { 191 | resp.getOutputStream().flush(); 192 | } 193 | } else if (HttpPart.MBEANS.isPart(req)) { 194 | monitoringController.addPdfContentTypeAndDisposition(req, resp); 195 | final Map> mbeanNodesByNodeName = getRemoteCallHelper() 196 | .collectMBeanNodesByNodeName(); 197 | try { 198 | doPdfMBeans(resp, mbeanNodesByNodeName); 199 | } finally { 200 | resp.getOutputStream().flush(); 201 | } 202 | } else { 203 | monitoringController.doReport(req, resp, lastJavaInformationsList); 204 | } 205 | } 206 | 207 | private void doPdfProcesses(HttpServletResponse resp, 208 | Map> processInformationsByNodeName) 209 | throws IOException { 210 | final String title = I18N.getString("Processus"); 211 | final Map> processInformationsByTitle = convertMapByNodeToMapByTitle( 212 | processInformationsByNodeName, title); 213 | new PdfOtherReport(collector.getApplication(), resp.getOutputStream()) 214 | .writeProcessInformations(processInformationsByTitle); 215 | } 216 | 217 | private void doPdfMBeans(HttpServletResponse resp, 218 | Map> mbeanNodesByNodeName) throws IOException { 219 | final String title = I18N.getString("MBeans"); 220 | final Map> mbeanNodesByTitle = convertMapByNodeToMapByTitle( 221 | mbeanNodesByNodeName, title); 222 | new PdfOtherReport(collector.getApplication(), resp.getOutputStream()) 223 | .writeMBeans(mbeanNodesByTitle); 224 | } 225 | 226 | private void doJmxValue(HttpServletResponse resp, List jmxValues) throws IOException { 227 | MonitoringController.noCache(resp); 228 | resp.setContentType("text/plain"); 229 | final PrintWriter writer = resp.getWriter(); 230 | boolean first = true; 231 | for (final String jmxValue : jmxValues) { 232 | if (first) { 233 | first = false; 234 | } else { 235 | writer.write('|'); 236 | writer.write('|'); 237 | } 238 | writer.write(jmxValue); 239 | } 240 | writer.close(); 241 | } 242 | 243 | private void doPart(HttpServletRequest req, HttpServletResponse resp, 244 | MonitoringController monitoringController) throws IOException, ServletException { 245 | // ici, ni web.xml ni pom.xml 246 | if (HttpPart.MBEANS.isPart(req)) { 247 | final Map> mbeanNodesByNodeName = getRemoteCallHelper() 248 | .collectMBeanNodesByNodeName(); 249 | doMBeans(req, resp, mbeanNodesByNodeName); 250 | } else if (HttpPart.PROCESSES.isPart(req)) { 251 | final Map> processInformationsByNodeName = getRemoteCallHelper() 252 | .collectProcessInformationsByNodeName(); 253 | doProcesses(req, resp, processInformationsByNodeName); 254 | } else if (HttpPart.HEAP_HISTO.isPart(req)) { 255 | final HeapHistogram heapHistoTotal = getRemoteCallHelper().collectGlobalHeapHistogram(); 256 | doHeapHisto(req, resp, heapHistoTotal, monitoringController); 257 | } else { 258 | monitoringController.doReport(req, resp, lastJavaInformationsList); 259 | } 260 | } 261 | 262 | private void doProcesses(HttpServletRequest req, HttpServletResponse resp, 263 | Map> processListByNodeName) throws IOException { 264 | final PrintWriter writer = createWriterFromOutputStream(resp); 265 | final HtmlReport htmlReport = createHtmlReport(req, resp, writer); 266 | final String title = I18N.getString("Processus"); 267 | final Map> processListByTitle = convertMapByNodeToMapByTitle( 268 | processListByNodeName, title); 269 | htmlReport.writeProcesses(processListByTitle); 270 | writer.close(); 271 | } 272 | 273 | private void doMBeans(HttpServletRequest req, HttpServletResponse resp, 274 | Map> mbeanNodesByNodeName) throws IOException { 275 | final PrintWriter writer = createWriterFromOutputStream(resp); 276 | final HtmlReport htmlReport = createHtmlReport(req, resp, writer); 277 | final String title = I18N.getString("MBeans"); 278 | final Map> mbeanNodesByTitle = convertMapByNodeToMapByTitle( 279 | mbeanNodesByNodeName, title); 280 | htmlReport.writeMBeans(mbeanNodesByTitle); 281 | writer.close(); 282 | } 283 | 284 | private Map convertMapByNodeToMapByTitle(Map mapByNodeName, 285 | final String title) { 286 | final Map mapByTitle = new LinkedHashMap<>(mapByNodeName.size()); 287 | for (final Map.Entry entry : mapByNodeName.entrySet()) { 288 | final String name = entry.getKey(); 289 | if (name != null && name.length() != 0) { 290 | mapByTitle.put(title + " (" + entry.getKey() + ")", entry.getValue()); 291 | } else { 292 | mapByTitle.put(title, entry.getValue()); 293 | } 294 | } 295 | return mapByTitle; 296 | } 297 | 298 | private void doHeapHisto(HttpServletRequest req, HttpServletResponse resp, 299 | HeapHistogram heapHistogram, MonitoringController monitoringController) 300 | throws IOException { 301 | if ("pdf".equalsIgnoreCase(HttpParameter.FORMAT.getParameterFrom(req))) { 302 | monitoringController.addPdfContentTypeAndDisposition(req, resp); 303 | try { 304 | final PdfOtherReport pdfOtherReport = new PdfOtherReport(collector.getApplication(), 305 | resp.getOutputStream()); 306 | pdfOtherReport.writeHeapHistogram(heapHistogram); 307 | } finally { 308 | resp.getOutputStream().flush(); 309 | } 310 | } else { 311 | final PrintWriter writer = createWriterFromOutputStream(resp); 312 | final HtmlReport htmlReport = createHtmlReport(req, resp, writer); 313 | htmlReport.writeHtmlHeader(); 314 | htmlReport.writeHeapHistogram(heapHistogram, null, HttpPart.HEAP_HISTO.getName()); 315 | htmlReport.writeHtmlFooter(); 316 | writer.close(); 317 | } 318 | } 319 | 320 | private void doCompressedSerializable(HttpServletRequest httpRequest, 321 | HttpServletResponse httpResponse, MonitoringController monitoringController) 322 | throws IOException { 323 | Serializable serializable; 324 | try { 325 | serializable = createSerializable(httpRequest); 326 | } catch (final Exception e) { 327 | serializable = e; 328 | } 329 | monitoringController.doCompressedSerializable(httpRequest, httpResponse, serializable); 330 | } 331 | 332 | private Serializable createSerializable(HttpServletRequest httpRequest) throws Exception { // NOPMD 333 | if (HttpPart.MBEANS.isPart(httpRequest)) { 334 | return new LinkedHashMap<>(getRemoteCallHelper().collectMBeanNodesByNodeName()); 335 | } else if (HttpPart.PROCESSES.isPart(httpRequest)) { 336 | return new LinkedHashMap<>( 337 | getRemoteCallHelper().collectProcessInformationsByNodeName()); 338 | } else if (HttpPart.HEAP_HISTO.isPart(httpRequest)) { 339 | return getRemoteCallHelper().collectGlobalHeapHistogram(); 340 | } else if (HttpPart.JVM.isPart(httpRequest)) { 341 | return new ArrayList<>(lastJavaInformationsList); 342 | } else if (HttpPart.THREADS.isPart(httpRequest)) { 343 | final ArrayList> result = new ArrayList<>(); 344 | for (final JavaInformations javaInformations : lastJavaInformationsList) { 345 | result.add(new ArrayList<>(javaInformations.getThreadInformationsList())); 346 | } 347 | return result; 348 | } 349 | 350 | // utile pour JROBINS_PART, OTHER_JROBINS_PART, SESSIONS_PART et 351 | // defaultSerializable notamment 352 | final SerializableController serializableController = new SerializableController(collector); 353 | return serializableController.createSerializable(httpRequest, lastJavaInformationsList, 354 | null); 355 | } 356 | 357 | private HtmlReport createHtmlReport(HttpServletRequest req, HttpServletResponse resp, 358 | PrintWriter writer) { 359 | final Range range = httpCookieManager.getRange(req, resp); 360 | return new HtmlReport(collector, null, lastJavaInformationsList, range, writer); 361 | } 362 | 363 | private static PrintWriter createWriterFromOutputStream(HttpServletResponse httpResponse) 364 | throws IOException { 365 | MonitoringController.noCache(httpResponse); 366 | httpResponse.setContentType("text/html; charset=UTF-8"); 367 | return new PrintWriter(HtmlController.getWriter(httpResponse)); 368 | } 369 | 370 | private RemoteCallHelper getRemoteCallHelper() { 371 | return new RemoteCallHelper(nodeName); 372 | } 373 | 374 | /** 375 | * Is it necessary to collect java informations for this monitoring request? 376 | * @param httpRequest HttpServletRequest 377 | * @return boolean 378 | */ 379 | public static boolean isJavaInformationsNeeded(HttpServletRequest httpRequest) { 380 | return MonitoringController.isJavaInformationsNeeded(httpRequest); 381 | } 382 | } 383 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Logo](/docs/images/systemmonitor32.png) Monitoring plugin 2 | ================= 3 | 4 | [![Jenkins Plugin](https://img.shields.io/jenkins/plugin/v/monitoring.svg)](https://plugins.jenkins.io/monitoring) 5 | [![Jenkins Plugin Installs](https://img.shields.io/jenkins/plugin/i/monitoring.svg?color=blue)](https://plugins.jenkins.io/monitoring) 6 | [![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins/monitoring-plugin/master)](https://ci.jenkins.io/job/Plugins/job/monitoring-plugin) 7 | [![JIRA](https://img.shields.io/badge/issue_tracker-JIRA-red.svg)](https://issues.jenkins-ci.org/issues/?jql=component%20%3D%20monitoring-plugin) 8 | 9 | [Monitoring plugin](https://plugins.jenkins.io/monitoring): Monitoring of the performance of Jenkins itself with [JavaMelody](https://github.com/javamelody/javamelody/wiki). 10 | 11 | Open the [report](http://localhost:8080/monitoring) (or ) after installation. 12 | 13 | Author : Emeric Vernat (evernat at free.fr) 14 | 15 | [License ASL](http://www.apache.org/licenses/LICENSE-2.0) 16 | 17 | ## Features summarized 18 | 19 | * Charts of memory, cpu, system load average, http response times by day, week, month, year or custom period 20 | * Statistics of http requests with mean response times, mean cpu times, mean response size by request and by day, week, month, year or custom period 21 | * Errors and logs 22 | * Current http requests 23 | * Threads 24 | * Heap histogram (instances and sizes by class) 25 | * Http sessions 26 | * Process list of OS 27 | * MBeans 28 | * Actions for GC, heap dump and invalidate session(s) 29 | * Report in html or pdf 30 | * In English, German, French, Portuguese, Italian, Czech, Ukrainian or Chinese 31 | * Jenkins security 32 | * For Jenkins slaves: 33 | * The [report](http://localhost:8080/monitoring/nodes) for the 34 | nodes is available at 35 | * Charts aggregated for all nodes of memory, cpu, system load 36 | average, number of running builds, build queue length, build 37 | times by period 38 | * Detailed statistics of the build times and of the build steps by period 39 | * Threads, process list and MBeans for each nodes 40 | * Heap histogram aggregated for all nodes 41 | * For each individual node (each node in ), 42 | reports and actions are available from the "Monitoring" page in the 43 | contextual menu or in the detail of the node: 44 | * Threads, process list, MBeans of that node only 45 | * Heap histogram of that node 46 | * Actions for GC, heap dump 47 | * And more... 48 | 49 | ![Graphics](/docs/images/graphics.png) 50 | ![Statistics](/docs/images/statistics.png) 51 | ![System infos and threads](/docs/images/system_infos_and_threads.png) 52 | 53 | [Online help of JavaMelody](https://github.com/javamelody/javamelody/wiki/resources/Online_help_of_the_monitoring.pdf) 54 | 55 | Some [Monitoring scripts](https://github.com/jenkinsci/monitoring-plugin/blob/master/docs/MonitoringScripts.md) can be executed using the Jenkins Script Console. 56 | The "Monitoring" plugin can be installed by point and click in the plugin manager of a Jenkins server, or it can be downloaded from . 57 | 58 | You can contribute translations on [this website](https://poeditor.com/join/project/QIaCp4bThS). 59 | 60 | ## Release notes 61 | 62 | #### Since 1.85.0 63 | 64 | See [Releases](https://plugins.jenkins.io/monitoring/#releases) 65 | 66 | #### 1.84.0 67 | 68 | Canceled 69 | 70 | #### 1.83.0 (May 5, 2020) 71 | 72 | * improved: The javamelody parameter `http-transform-pattern` is already used in the plugin, in order to limit disk IO and disk space usage for the statistics and RRD graphs of http requests. If that's not enough, some RRD files of graphs for http requests will now be automatically deleted everyday at midnight to limit the disk space used by RRD files under 20 MB. You may configure that limit with the javamelody parameter `max-rrd-disk-usage-mb` (20 by default). And old statistics and graphs are automatically deleted like before. ([553b323](https://github.com/javamelody/javamelody/commit/553b323)) 73 | * added: As an external API, dump of graphs values as XML or as TXT, for the choosen period or for all periods ([d11e6a8](https://github.com/javamelody/javamelody/commit/d11e6a8)). See [doc](https://github.com/javamelody/javamelody/wiki/ExternalAPI#dump-graph-as-xml-or-txt). 74 | * added: Links to Last value, Dump XML, Dump TXT below the zoomed graphics ([3967ea2](https://github.com/javamelody/javamelody/commit/3967ea2)). 75 | * added: if using Tomcat, display sources of Tomcat's classes from stack-traces like for the webapp's dependencies ([9907e93](https://github.com/javamelody/javamelody/commit/9907e93)). 76 | 77 | #### 1.82.0 (Mar 1, 2020) 78 | 79 | * improved: in the http sessions, identify the new MS Edge browser as Edg instead of Chrome ([304819f](https://github.com/javamelody/javamelody/commit/304819f)). 80 | * optimized: when displaying the report, lazy load images in "Other charts" ([cb18db5](https://github.com/javamelody/javamelody/commit/cb18db5)). 81 | * clarify that statistics in reports starts at midnight (in the server's time zone), for example "1 day since midnight" ([#897](https://github.com/javamelody/javamelody/issues/897)). 82 | 83 | #### 1.81.0 (Dec 29, 2019) 84 | 85 | * fix [JENKINS-60433](https://issues.jenkins-ci.org/browse/JENKINS-60433): JEP-200 error on HsErrPid. 86 | * fix [#871](https://github.com/javamelody/javamelody/issues/871), thanks to Vicente Rossello Jaume: In the [optional collect server](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#optional-centralization-server-setup), each current request already displayed once is not displayed anymore after refresh. 87 | * Look further to display the remote user in the current requests. And add sessionId attribute in the current requests for the [External API](https://github.com/javamelody/javamelody/wiki/ExternalAPI). ([PR 873](https://github.com/javamelody/javamelody/pull/873), thanks to Eugene Kortov) 88 | * fix [#884](../issues/884), CircularReferenceException in [External API](ExternalAPI) with JSON for current requests. 89 | * added: graph of Usable disk space next to Free disk space in "Other charts" (the usable disk space may be lower than the free disk space, [#875](https://github.com/javamelody/javamelody/issues/875)). 90 | * added: if the monitoring of a Jenkins server is added in the [optional collect server](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#optional-centralization-server-setup), the monitoring of Jenkins nodes including builds are automatically added at the same time ([ee06c01](https://github.com/javamelody/javamelody/commit/ee06c01)). 91 | 92 | #### 1.80.0 (Nov 3, 2019) 93 | 94 | * After the [JavaMelody real case 1](RealCase1), the [real case 2](RealCase2) is an the investigation of a Java application with some very slow screens, with detailed explanation on monitoring metrics, statistics and found issues. And the [real case 3](RealCase3) on the investigation of why dozen of users are working extra-hours and of other issues. [#JavaMelodyRealCase](https://twitter.com/search?q=%23JavaMelodyRealCase) 95 | * added a graph in /monitoring/nodes of the sum of waiting durations in seconds of the builds in the build queue, next to the graph of the build queue length 96 | ([efa4d03](https://github.com/jenkinsci/monitoring-plugin/commit/efa4d0317122ed629190d7206a32a462a0228b5f)) 97 | * moved documentation from [wiki](https://wiki.jenkins.io/display/JENKINS/Monitoring) to [github](https://github.com/jenkinsci/monitoring-plugin/blob/master/README.md) 98 | * added new Prometheus metrics in .../monitoring?format=prometheus: used non-heap memory, used buffered memory, used physical memory, used swap space, loaded classes count (a704562). 99 | 100 | #### 1.79.0 (Jul 26, 2019) 101 | 102 | * fix [JENKINS-58419](https://issues.jenkins-ci.org/browse/JENKINS-58419): 103 | No redirect after login in the CAS plugin since 1.78.0. 104 | * fix [JENKINS-58388](https://issues.jenkins-ci.org/browse/JENKINS-58388), 105 | broken 'report' link in Available and Updated tabs of plugin manager. 106 | * fix [\#843](https://github.com/javamelody/javamelody/issues/843): 107 | when using Tomcat, Tomcat info is not available anymore since Tomcat 8.5.35 and Tomcat 9.0.13. 108 | * fix [\#847](https://github.com/javamelody/javamelody/issues/847): 109 | When downloading more than 2GB, assertionError may occur. 110 | 111 | #### 1.78.0 (Jul 2, 2019) 112 | 113 | * Improved the rendering of the management links in the Administer page 114 | ([JENKINS-57373](https://issues.jenkins-ci.org/browse/JENKINS-57373)). 115 | Note that the link on "Monitoring of memory, cpu, http requests and 116 | more in Jenkins master." goes to the "/monitoring" page. 117 | And the link on "You can also view the monitoring of builds, build 118 | queue and Jenkins nodes." goes to the "/monitoring/nodes" page. 119 | * added: display an alert at the top of the monitoring page when there 120 | is an exception while collecting data, in order to make easier to 121 | fix basic technical issues in javamelody 122 | ([a7a8b26](https://github.com/javamelody/javamelody/commit/a7a8b26)). 123 | For example, `IOException: No space left on device`. 124 | * fix to still flush the response when no content in 125 | FilterServletResponseWrapper.flushBuffer() 126 | ([\#836](https://github.com/javamelody/javamelody/issues/836)) 127 | * added: Czech translations 128 | ([2d85a88](https://github.com/javamelody/javamelody/commit/2d85a88), 129 | thanks to *Lukáš Karabec*) 130 | * improved: missing German translations 131 | ([c19539b](https://github.com/javamelody/javamelody/commit/c19539b), 132 | thanks to *Michael Dobrovnik*) 133 | * To contribute in your own language, join the translation project at 134 | . 135 | 136 | #### 1.77.0 (Apr 21, 2019) 137 | 138 | * improved: better aggregation of http requests. The javamelody parameter used by default in this plugin is now 139 | `-Djavamelody.http-transform-pattern=/\d+/|(?<=/static/|/adjuncts/|/bound/)[\w\-]+|(?<=/ws/|/user/|/testReport/|/javadoc/|/site/|/violations/file/|/cobertura/).+|(?<=/job/).+(?=/descriptorByName/)`. 140 | * added: Italian translations 141 | ([ffc028f](https://github.com/javamelody/javamelody/commit/ffc028f), 142 | thanks to *Gianluca Maiorino*) 143 | * added: Ukrainian translations 144 | ([073bc6d](https://github.com/javamelody/javamelody/commit/073bc6d), 145 | thanks to *Yevgen Lasman*) 146 | * To contribute in your own language, join the translation project at 147 | . 148 | * added: ability to upload heap dump files to [AWS 149 | S3](https://aws.amazon.com/s3/) ([PR 150 | 810](https://github.com/javamelody/javamelody/pull/810), thanks to 151 | *Salah Qasem*). 152 | To enable the upload of heap dump files to [AWS 153 | S3](https://aws.amazon.com/s3/): 154 | 1. add a parameter `heap-dump-s3-bucketname` with the S3 bucket 155 | name, in system properties. For example 156 | `-Djavamelody.heap-dump-s3-bucketname=mybucket` in your 157 | jenkins.xml file. And restart. 158 | 2. Download this [aws-s3-library 159 | plugin](https://github.com/javamelody/aws-s3-library/releases/download/1.11.136/aws-s3-library.hpi) 160 | and install it with the Advanced tab of the Plugin manager in 161 | Jenkins. 162 | 3. You also need to provide AWS credentials and AWS region as AWS 163 | as environnement variables or system properties or credentials 164 | or config files or Amazon services, see 165 | [doc](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#upload-heap-dumps-to-aws-s3) 166 | (scroll down if the target page does not scroll to the right 167 | chapter). 168 | 169 | #### 1.76.0 (Jan 27, 2019) 170 | 171 | * You can now contribute translations for javamelody by using a 172 | dedicated website at POEditor. You may contribute some 173 | "untranslated" labels for German and Portuguese or you may 174 | contribute new translations for Spanish, Italian or your own 175 | language. Join the translation project at 176 | 177 | * fix for Prometheus integration: exclude metrics which have no sense 178 | (javamelody\_log\_duration\_millis, javamelody\_log\_errors\_count, 179 | javamelody\_error\_errors\_count) and metrics for statistics which 180 | are not displayed in the reports 181 | ([e1db7c5](https://github.com/javamelody/javamelody/commit/e1db7c5), 182 | [c0f34a2](https://github.com/javamelody/javamelody/commit/c0f34a2)) 183 | * fix [\#806](https://github.com/javamelody/javamelody/issues/806) for 184 | Prometheus integration again: it was printed '\' instead of NaN, 185 | for 'lastValue' on Java 8 and before. 186 | 187 | #### 1.75.0 (Dec 9, 2018) 188 | 189 | * Fix [\#794](https://github.com/javamelody/javamelody/issues/794) Compatibility with Google App Engine using Java 8. 190 | * Fix [\#779](https://github.com/javamelody/javamelody/issues/779) When using JSVC to launch Tomcat, InternalError: errno: 13 error: Unable to open directory /proc/self/fd 191 | * Enhanced: added X-Frame-Options: SAMEORIGIN in the reports. 192 | * CSRF protection is automatically enabled in the plugin, if CSRF protection is enabled in Jenkins. (Note that a restart is needed if changed in Jenkins.) 193 | 194 | Added the Offline viewer tool for some degraded cases: 195 | 196 | * If ever you don't have access to the online reports of javamelody on the running server, 197 | * or if you want to view the reports but the server is no longer running, 198 | * then the offline viewer may be for you. See [doc](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#offline-viewer) 199 | 200 | #### 1.74.0 (Sep 4, 2018) 201 | 202 | * It is a **recommended upgrade for security** to fix a [XML External Entity (XXE) processing](https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing) vulnerability. CVE-ID is 203 | [CVE-2018-15531](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15531). 204 | Thanks to *mounsurf & huanying* for reporting the vulnerability. But note that Jenkins uses the Woodstox parser so it is currently safe from this XXE vulnerability. 205 | * Fix warning logs about serializing anonymous classes ([issue 768](https://github.com/javamelody/javamelody/issues/768)). 206 | * fix: do not require Log4J when sending metrics to [InfluxDB](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-influxdb) 207 | or [Datadog](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-datadog). 208 | * added: native calendar widget to choose dates for a custom period 209 | ([84a1d63](https://github.com/javamelody/javamelody/commit/84a1d63321449f71dec6069d3e712ee67e3ef5d6), 210 | with help from my colleague Fabien at [KleeGroup](http://www.kleegroup.com)) 211 | 212 | #### 1.73.1 (Jun 27, 2018) 213 | 214 | * Compatibility with JDK 9: `-Djdk.attach.allowAttachSelf=true` is no 215 | longer required to have heap histogram and fix the display of source 216 | for a JDK class. 217 | 218 | #### 1.73.0 (Jun 20, 2018) 219 | 220 | * Compatibility with JDK 9: fix heap dump and heap histogram, display 221 | again the graphs of cpu, opened files and physical memory. ~~Note: 222 | to have the memory histogram in JDK 9 or later, add 223 | `-Djdk.attach.allowAttachSelf=true` in the java command line.~~ 224 | * Fix "no token found" with Prometheus integration for a Windows 225 | server 226 | ([e47b11b](https://github.com/javamelody/javamelody/commit/e47b11bbaf0772151a7cae8ff97227516cd86b04)) 227 | * Enhancement: After generating a heap dump, zip it to reduce its size 228 | ([98cb8bc](https://github.com/javamelody/javamelody/commit/98cb8bc08103f2ff00a4f5e72be64ddf278f2656)) 229 | * Added: The mean number of allocated Kilobytes per request is now 230 | displayed in the stats, next to the mean cpu per request. It is the 231 | memory used in the heap per request and which will have to be 232 | cleaned by the Garbage Collector later. And when more memory is used 233 | per request, more cpu will be used by the GC. As an example, 1 Gb 234 | allocated in a request, without a good reason, is probably a 235 | problem. 236 | ([33fe61d](https://github.com/javamelody/javamelody/commit/33fe61d5af0dc46a35c1f1a0dc26952651612055)) 237 | * Added: when crash logs (hs\_err\_pid\*.log files) are found, display 238 | them in the system actions 239 | ([5ebb28e](https://github.com/javamelody/javamelody/commit/5ebb28e9bfe98cacef6c95c9d3b5f338a444efc9)) 240 | * Added: in the zoomed charts, display of the [95th 241 | percentile](https://en.wikipedia.org/wiki/Burstable_billing) line. 242 | It shows what would be the maximum on the period if 5% of the 243 | highest values (short peaks) were excluded 244 | ([9f7acba](https://github.com/javamelody/javamelody/commit/9f7acba4e1d21658be9db2f807a7864787c04e78)) 245 | * Fix rare issue: ArithmeticException: / by zero in JRobin RRD files 246 | ([JENKINS-51590](https://issues.jenkins-ci.org/browse/JENKINS-51590)). 247 | * Removed the `prometheus-include-last-value` javamelody parameter and 248 | replaced it by the `includeLastValue` http parameter 249 | ([08aacb2](https://github.com/javamelody/javamelody/commit/08aacb2fdc122a383ad4590c1426b8e129552480), 250 | see 251 | [doc](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#exposing-metrics-to-prometheus)). 252 | So, in the improbable case that you used 253 | `prometheus-include-last-value` for Prometheus integration, change 254 | your scrape\_config to: 255 | 256 | params: 257 | format: ['prometheus'] 258 | includeLastValue: ['true'] 259 | 260 | #### 1.72.0 (Apr 4, 2018) 261 | 262 | * Fix [\#735](https://github.com/javamelody/javamelody/issues/735): NPE when there are no executors. 263 | * Fix [\#737](https://github.com/javamelody/javamelody/issues/737) for StatsD integration. 264 | * Fix [\#731](https://github.com/javamelody/javamelody/issues/731): 265 | When using [CloudWatch](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-aws-cloudwatch), 266 | Cloudwatch metric upload can't handle more then 20 items (with help from *marcrelation*). 267 | * Fix [\#668](https://github.com/javamelody/javamelody/issues/668): 268 | `RrdException: Invalid timestamps specified` in some particular case when using custom period. 269 | 270 | #### 1.71.0 (Feb 5, 2018) 271 | 272 | * Added JEP-200 exclusions when using monitoring with slaves (PR 273 | [\#6](https://github.com/jenkinsci/monitoring-plugin/pull/6) thanks to Jesse Glick) 274 | * Note that Jenkins core includes the monitoring classes in its 275 | whitelist for the monitoring plugin 1.68.0 or later, but Jenkins 276 | servers using the monitoring plugin 1.67 or older need to upgrade 277 | the plugin 278 | ([JENKINS-50280](https://issues.jenkins-ci.org/browse/JENKINS-50280)). 279 | * Fix [\#700](https://github.com/javamelody/javamelody/issues/700) for 280 | Prometheus integration (with help from *Stefan Penndorf*). 281 | * Fix [\#701](https://github.com/javamelody/javamelody/issues/701) for 282 | Datadog integration (PR 283 | [\#702](https://github.com/javamelody/javamelody/pull/702), thanks 284 | to *bluegaspode*). 285 | * Fix [\#718](https://github.com/javamelody/javamelody/issues/718): 286 | NPE when displaying the webapp dependencies in some particular case. 287 | * improved: Warn in the reports if multiple instances use the same 288 | storage directory 289 | ([\#692](https://github.com/javamelody/javamelody/issues/692)) 290 | * improved: If the `application-name` parameter is defined, use it 291 | when publishing metrics to InfluxDB, Graphite, StatsD, CloudWatch or 292 | Datadog instead of the context path 293 | ([\#694](https://github.com/javamelody/javamelody/issues/694)) 294 | * added: When using the [reports by 295 | mail](https://github.com/javamelody/javamelody/wiki/UserGuide#14-weekly-daily-or-monthly-reports-by-mail), 296 | a new javamelody parameter `mail-subject-prefix` can be used to 297 | configure the subject of the mail notification. For example, in a 298 | Tomcat context file: 299 | `` 300 | (PR [\#710](https://github.com/javamelody/javamelody/pull/710), 301 | thanks to *vkpandey82*) 302 | * added: In the [External 303 | API](https://github.com/javamelody/javamelody/wiki/ExternalAPI), the 304 | url `monitoring?part=lastValue&format=json` now returns all the last 305 | values by names. (The url 306 | `monitoring?part=lastValue&graph=usedMemory` already returns the 307 | last value of a single graph by name.) 308 | 309 | #### 1.70.0 (Oct 29, 2017) 310 | 311 | * added: integration with **Prometheus**: Metrics are already 312 | displayed in the monitoring reports. You can also scrape the same 313 | metrics from [Prometheus](https://prometheus.io/) at the frequency 314 | you wish for advanced visualizations, if you have a Prometheus 315 | server installed (PR 316 | [\#682](https://github.com/javamelody/javamelody/pull/682) & PR 317 | [\#684](https://github.com/javamelody/javamelody/pull/684), thanks 318 | to *slynn1324*). See 319 | [doc](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#exposing-metrics-to-prometheus). 320 | Note : If Jenkins security is enabled, the system property 321 | `-Djavamelody.plugin-authentication-disabled=true` can be added to 322 | the Jenkins server in order to disable authentication of the 323 | monitoring page in the Monitoring plugin and to allow Prometheus to 324 | scrape metrics. 325 | * added integration with **StatsD**: Metrics are already displayed in 326 | the charts of the monitoring reports. As an extra, you can also 327 | publish the same metrics to 328 | [StatsD](https://github.com/etsy/statsd), if you have a StatsD 329 | daemon installed. To enable sending the metrics, add a parameter 330 | `statsd-address` with hostname:port of the StatsD daemon, in system 331 | properties. For example 332 | `-Djavamelody.statsd-address=11.22.33.44:8125 `in your jenkins.xml 333 | file, see 334 | [doc](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-statsd). 335 | ([92aeffe](https://github.com/javamelody/javamelody/commit/92aeffe800194544b9c91c1c799b36e74d4b7436)) 336 | * fix [\#681](https://github.com/javamelody/javamelody/issues/681): 337 | upgrade prototype.js, effects.js and slider.js 338 | 339 | #### 1.69.1 (Sep 20, 2017) 340 | 341 | * remove the slf4j-api dependency from the plugin to avoid potential 342 | conflicts with the same dependency in jenkins core. 343 | 344 | #### 1.69.0 (Aug 27, 2017) 345 | 346 | * In the [Jenkins 347 | plugin](https://wiki.jenkins-ci.org/display/JENKINS/Monitoring), fix 348 | NPE when using 349 | [CloudWatch](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-aws-cloudwatch) 350 | or 351 | [Graphite](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-graphite) 352 | ([3e2b872](https://github.com/javamelody/javamelody/commit/3e2b8720f90514c000519055635ad0bb5f426531)). 353 | * In the [Jenkins 354 | plugin](https://wiki.jenkins-ci.org/display/JENKINS/Monitoring) with 355 | FreeBSD, fix 356 | [JENKINS-45963](https://issues.jenkins-ci.org/browse/JENKINS-45963): 357 | if the collect fails for one slave, continue with the others 358 | * added integration with **InfluxDB**: Metrics are already displayed 359 | in the charts of the monitoring reports. Like integrations with 360 | [Graphite](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-graphite) 361 | and [AWS 362 | CloudWatch](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-aws-cloudwatch), 363 | you can also publish the same metrics to 364 | [InfluxDB](https://www.influxdata.com/time-series-platform/) for 365 | advanced visualizations, if you have an InfluxDB server installed. 366 | The parameter is `influxdb-url`, see 367 | [doc](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-influxdb). 368 | ([f7c8503](https://github.com/javamelody/javamelody/commit/f7c850361bec907aaba39861e473092043e75cc4)) 369 | * added integration with **Datadog**: Like for InfluxDB, you can also 370 | publish the same metrics to [Datadog](https://www.datadoghq.com/) 371 | for advanced visualizations. The parameter is `datadog-api-key`, see 372 | [doc](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-datadog). 373 | ([239aa4e](https://github.com/javamelody/javamelody/commit/239aa4e4cdf3c2943caff779a2f5492772f1500f)) 374 | 375 | #### 1.68.0 (Jul 1, 2017) 376 | 377 | * improved (Brazilian) Portuguese translation (PR 378 | [\#642](https://github.com/javamelody/javamelody/pull/642), thanks 379 | to *Sandro Giacomozzi*). 380 | * added a **monitoring script** to display stats of builds and build 381 | steps having a mean time greater than the severe threshold. See [the 382 | script](https://github.com/jenkinsci/monitoring-plugin/blob/master/docs/MonitoringScripts.md#display-some-mbean-attribute-value). 383 | * fix [\#638](https://github.com/javamelody/javamelody/issues/638): 384 | When using [scripts and 385 | alerts](https://github.com/javamelody/javamelody/wiki/ScriptsAndAlerts) 386 | to monitor an application, ClassNotFoundException in Jenkins if the 387 | monitored webapp is using Ehcache or Quartz jobs. 388 | * Internal classes moved: Many internal classes, which were not public 389 | and all in the `net.bull.javamelody` package, are now moved to 390 | `net.bull.javamelody.internal.*` packages. 391 | * added: In the list of threads, add an action to send an interrupt 392 | signal to a thread. The thread can test 393 | Thread.currentThread().isInterrupted() to stop itself. 394 | ([7977f2b](https://github.com/javamelody/javamelody/commit/7977f2b98020aebbc254d1e19138782bed882d73)) 395 | * added: PDF link in the threads page 396 | ([b356132](https://github.com/javamelody/javamelody/commit/b356132e06047fdae09fd63f5212464e7da9efe9)) 397 | * added integration with **Graphite**: Metrics are already displayed 398 | in the charts of the monitoring reports. As an extra, you can also 399 | publish the same metrics to [Graphite](https://graphiteapp.org/) for 400 | advanced visualizations, if you have a Graphite server installed. 401 | Metrics will be sent once per minute (default value of the 402 | resolution-seconds parameter) and Graphite will allow custom 403 | visualizations in itself or in [Grafana](http://grafana.org/). The 404 | names of metrics in Graphite are like 405 | `javamelody.appContext.hostName.metricName`, so you will be able to 406 | aggregate a metric using wildcards. 407 | To enable sending the metrics, add a parameter `graphite-address` 408 | with hostname:port of the Graphite server, in system properties. For 409 | example `-Djavamelody.graphite-address=11.22.33.44:2003` in your 410 | jenkins.xml file. 411 | ([ce94787](https://github.com/javamelody/javamelody/commit/ce947870ed120589c49b2e080ea7be17f8ef07b0)) 412 | * added integration with **AWS CloudWatch**: Like for Graphite, you 413 | can also publish the same metrics to [AWS 414 | CloudWatch](https://aws.amazon.com/cloudwatch/) for custom 415 | visualizations and mail or autoscaling alarms, if you have AWS EC2 416 | server instance(s) with [detailed 417 | monitoring](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-cloudwatch-new.html) 418 | in AWS CloudWatch. Metrics will be sent once per minute (default 419 | value of the resolution-seconds parameter) and CloudWatch will allow 420 | [custom visualizations and mail or auto-scaling 421 | alarms](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch_concepts.html). 422 | The names of metrics in CloudWatch are like `javamelody.metricName`. 423 | Metrics also include `application` and `hostname` as dimensions, so 424 | you will be able to filter metrics based on those dimensions. Note 425 | that there is a 426 | [pricing](https://aws.amazon.com/cloudwatch/pricing/) for CloudWatch 427 | metrics (it is supposed that about 25 custom metrics should mean 428 | about $10 per month per EC2 instance). 429 | ([e65d605](https://github.com/javamelody/javamelody/commit/e65d6054acec4b1126a212b9ec4605c020c7186a)) 430 | To enable sending the metrics: 431 | 1. add a parameter `cloudwatch-namespace` with the CloudWatch 432 | namespace, in system properties. For example 433 | `-Djavamelody.cloudwatch-namespace=MyCompany/MyAppDomain` in 434 | your jenkins.xml file (the namespaces starting with `AWS/` are 435 | reserved for AWS products). And restart. 436 | 2. Ensure that the latest version of the official [aws-java-sdk-cloudwatch 437 | plugin](https://plugins.jenkins.io/aws-java-sdk-cloudwatch/) 438 | is installed. 439 | 3. You also need to provide AWS credentials and AWS region as AWS 440 | as environnement variables or system properties or credentials 441 | or config files or Amazon services, see 442 | [doc](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#sending-metrics-to-aws-cloudwatch). 443 | 444 | #### 1.67.0 (May 12, 2017) 445 | 446 | * fix 447 | [JENKINS-44241](https://issues.jenkins-ci.org/browse/JENKINS-44241): 448 | **[Real User Monitoring 449 | (RUM)](https://en.wikipedia.org/wiki/Real_user_monitoring)** in 450 | v1.66.0 does not work when enabled, for URLs ending with '/'. 451 | 452 | #### 1.66.0 (May 12, 2017) 453 | 454 | * fix [\#617](https://github.com/javamelody/javamelody/issues/617): 455 | Charts of http/sql stats can not be viewed after restarting the 456 | application (with help from *goldyliang*). 457 | * added: Display the number of http sessions and sessions mean size 458 | before the list of sessions, when there are more than 20 (PR 459 | [\#629](https://github.com/javamelody/javamelody/pull/629), thanks 460 | to *Aleksandr Mashchenko*). 461 | * improved: When displaying Java sources from stack-traces, locate 462 | more sources by reading Maven pom.xml of Jenkins and of the other 463 | dependencies. 464 | * added: Display **webapp dependencies** in a new page, accessed by a 465 | link in the System informations details, and include detailed name, 466 | website url, Maven 467 | [groupId:artifactId:version](http://groupIdartifactIdversion) and 468 | license of each dependency, based on Maven pom.xml files. 469 | ([e7607c1](https://github.com/javamelody/javamelody/commit/e7607c19087d6b592c92c38b50b5e2fd1d9fd306)) 470 | * added: The version of Jenkins is displayed at the top of the report 471 | and a drop-down list of versions next to "Customized" period allows 472 | to display the report for the period of each version deployed, to 473 | compare between them for example. 474 | ([d61e65f](https://github.com/javamelody/javamelody/commit/d61e65f82c936e5dc986e4f850d4a5998b9caa2d), 475 | based on an idea by *dhartford*). 476 | * added: **[Real User Monitoring 477 | (RUM)](https://en.wikipedia.org/wiki/Real_user_monitoring)**. It 478 | allows to measure the experience from the end user perspective, by 479 | monitoring times in the browser for each html page until it is 480 | displayed and ready to be used 481 | ([b85652a](https://github.com/javamelody/javamelody/commit/b85652a182d05517ad8151f4101d584ecc007517)). 482 | * The Real User Monitoring works by injecting on the fly a 483 | [Boomerang](https://soasta.github.io/boomerang/doc/) javascript at 484 | the end of html pages, just before the `` end tag, which 485 | sends data back to the monitoring in your server. Then in the 486 | detailed monitoring report of http requests for html pages, times 487 | and percentages are displayed for Network, Server execution, DOM 488 | processing and Page rendering, to compare which ones contribute to a 489 | good or bad end user experience. The Real User Monitoring does not 490 | add a noticeable overhead on the server, but the javascript adds a 491 | simple http(s) call for each html page, which may add a small 492 | overhead on the client browser. 493 | * This Real User Monitoring is **not enabled by default**. To enable 494 | it, add the system property "-Djavamelody.rum-enabled=true" in your 495 | jenkins.xml file. 496 | 497 | #### 1.65.1 (Mar 13, 2017) 498 | 499 | * added: configuration to list Jenkins maven public repository next to 500 | \~/.m2/repository and Maven central, to be able to display Jenkins 501 | and plugins sources from stack-traces. 502 | 503 | #### 1.65.0 (Mar 12, 2017) 504 | 505 | * fix 506 | [JENKINS-42112](https://issues.jenkins-ci.org/browse/JENKINS-42112), 507 | HTTP user session is reported as "anonymous" when using anything but 508 | AbstractPasswordBasedSecurityRealm (like Google login plugin or 509 | Cloudbees Operations Center). 510 | * fix compatibility with Java 9. (PR 511 | [\#609](https://github.com/javamelody/javamelody/pull/609) for issue 512 | [\#556](https://github.com/javamelody/javamelody/issues/556), thanks 513 | to *James Pether Sörling*) 514 | * improved: make easier the selection of the stack-trace text in the 515 | tooltips of the threads list 516 | ([736cf0e](https://github.com/javamelody/javamelody/commit/736cf0ed88f81e8e4c0ef92b6151cfe62119bc17)) 517 | * added: pdf report in the detail page of a request. 518 | ([28e2474](https://github.com/javamelody/javamelody/commit/28e24742c6a2a9838ce1aaf34acb152b031e6497)) 519 | * added: links to view java source from errors and threads 520 | stack-traces. 521 | ([e5263bf](https://github.com/javamelody/javamelody/commit/e5263bf08e36ab7be35c639ba7e2899d4c0ced5d)) 522 | 523 |   524 | 525 | * Source from the JDK and source from artifacts built by Maven and 526 | available in Maven central can be viewed. So if your server uses a 527 | JRE and not a JDK, source from the JDK are not available. And note 528 | that many artifacts available in Maven central were not built by 529 | Maven, for example Tomcat libraries, so sources of those artifacts 530 | can't be located. 531 | * added: if the javamelody parameter 532 | -Djavamelody.jmx-expose-enabled=true is set (in the jenkins.xml 533 | file), then javamelody mbeans are available with aggregated 534 | statistics data about requests. The javamelody mbeans can be read 535 | with the MBeans screen in 'System actions' of the monitoring report 536 | () or using JMX 537 | with the JConsole of the JDK. (PR 538 | [\#591](https://github.com/javamelody/javamelody/pull/591) thanks to 539 | *Alexey Pushkin*) 540 | 541 |   542 | 543 | * doc added: [Summary of javamelody 544 | parameters](https://github.com/javamelody/javamelody/wiki/Parameters) 545 | to extend the [javamelody user's 546 | guide](https://github.com/javamelody/javamelody/wiki/UserGuide). 547 | 548 | ~~1.64.0~~ 549 | 550 | #### 1.63.0 (Jan 16, 2017) 551 | 552 | * added: check for updated version of javamelody. If a new version is 553 | available, a message is now displayed at the top of the report to 554 | notify about the new version. For that, javamelody pings the server 555 | javamelody.org. And to better understand javamelody users, anonymous 556 | data such as java version and OS is sent to that server at the same 557 | time. An example of the data sent is: 558 | `uniqueId="3d117c04b914c78ddbaf14818c404c8e88c6e56f", serverInfo="jetty/9.2.z-SNAPSHOT", javamelodyVersion="1.63.0", applicationType="Jenkins", javaVersion="Java(TM) SE Runtime Environment, 1.8.0_111-b14", jvmVersion="Java HotSpot(TM) 64-Bit Server VM, 25.111-b14, mixed mode", maxMemory="1024", availableProcessors="4", os="Windows 7, Service Pack 1, amd64/64", databases="", countersUsed="http|error|log", parametersUsed="log", featuresUsed="pdf", locale="fr_FR", usersMean=1, collectorApplications=-1`. 559 | * Usage stats based on the anonymous data will be publicly available 560 | at for applications using 561 | JavaMelody v1.63 or later (including Jenkins using the Monitoring 562 | plugin) and able to contact the server. 563 | * You may disable the update check with the javamelody parameter 564 | "update-check-disabled=true" in system properties. If you want to, 565 | add the system property "-Djavamelody.update-check-disabled=true" in 566 | the jenkins.xml file. 567 | * The online demo of javamelody is finally back. To see it, you can 568 | play a bit with [this app](http://javamelody.org/demo/) (written by 569 | Benjamin Durand some years ago) to be sure to have some data in http 570 | and sql statistics, then open the [monitoring 571 | page](http://javamelody.org/demo/monitoring) to explore the reports. 572 | 573 | #### 1.62.0 (Oct 1, 2016) 574 | 575 | * fix XSS (reported by *Omar El Mandour*) 576 | 577 | #### 1.61.0 (Sep 12, 2016) 578 | 579 | * fix XSS (reported by *Dallas Kaman, Praetorian Group*) 580 | 581 | #### 1.60.0 (Jun 14, 2016) 582 | 583 | * Fix XSS in graph page ([PR 584 | 555](https://github.com/javamelody/javamelody/pull/555), thanks to 585 | *Tim Helmstedt*) 586 | * fix 587 | [JENKINS-34794](https://issues.jenkins-ci.org/browse/JENKINS-34794) 588 | Jenkins sometimes doesn't start because of transient NPE (thanks to 589 | *Félix Belzunce Arcos*) 590 | * improved: 591 | [JENKINS-34736](https://issues.jenkins-ci.org/browse/JENKINS-34736) 592 | Migrate to 2.9 parent pom (thanks to *Armando Fernández*) 593 | * added system property "csrf-protection-enabled" to enable protection 594 | against 595 | [CSRF](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)) 596 | on actions such as run GC, invalidate sessions, kill thread by id 597 | ... (Not enabled by default since an attacker would need to know 598 | about javamelody in Jenkins and about its URLs and would need to 599 | force an administrator to access the monitoring and even in this 600 | case, the attacker certainly can't make Jenkins unvailable and can't 601 | steal data or anything.) To enable this protection, add the system 602 | property "-Djavamelody.csrf-protection-enabled=true" in the 603 | jenkins.xml file. 604 | * Limit error messages to 1000 characters and error stack-traces to 605 | 50000 characters, to avoid high memory consumption when log messages 606 | are very long ([PR 607 | 550](https://github.com/javamelody/javamelody/pull/550), thanks to 608 | *Zdenek Henek*) 609 | 610 | #### 1.59.0 (Feb 25, 2016) 611 | 612 | * fix username in the list of http sessions 613 | ([d111126](https://github.com/jenkinsci/monitoring-plugin/commit/d1111261b03f7762e903724599fbf84eaa3a2d48)) 614 | * fix [issue 615 | 533](https://github.com/javamelody/javamelody/issues/533): 616 | IllegalArgumentException during metrics update 617 | ([JENKINS-33050](https://issues.jenkins-ci.org/browse/JENKINS-33050)) 618 | * fix [issue 619 | 532](https://github.com/javamelody/javamelody/issues/532): do not 620 | flush a closed output stream. 621 | * improved: wrap very long http queries without whitespace, in order 622 | to fit into the screen and to avoid horizontal scrollbar 623 | ([3a88a75](https://github.com/javamelody/javamelody/commit/3a88a75a9554b6496ff6b224716c6ed840bd88b1)) 624 | * added: display the client's browser and OS in the list of http 625 | sessions 626 | ([6d89f42](https://github.com/javamelody/javamelody/commit/6d89f428a7a92018089953bb1697ff25b0f66fc1)) 627 | * added: Support Log4J 2 since v2.4.1 like Log4J 628 | ([068139d](https://github.com/javamelody/javamelody/commit/068139d70dd65ff7574c5ec3cb15045af2f33d9f)) 629 | * added: Show used memory in dialog after manual GC ([issue 630 | 522](https://github.com/javamelody/javamelody/issues/522)) 631 | 632 | #### 1.58.0 (Nov 26, 2015) 633 | 634 | * fix 635 | [JENKINS-23442](https://issues.jenkins-ci.org/browse/JENKINS-23442), 636 | ClassCircularityError: java/util/logging/LogRecord 637 | ([0ad60da](https://github.com/jenkinsci/monitoring-plugin/commit/0ad60da0038048ca69672022e54434cb3c5c87a3)) 638 | * **Upgraded mininum Jenkins** version to 1.580.1 639 | * replace use of deprecated Jenkins api 640 | * fix from [PR 505](https://github.com/javamelody/javamelody/pull/505) 641 | and PR [507](https://github.com/javamelody/javamelody/pull/507): 642 | German translations (thanks to *mawulf*) 643 | * fix [issue 644 | 492](https://github.com/javamelody/javamelody/issues/492): 645 | incompatibility of the release v1.57.0 (isAsyncStarted) with servlet 646 | api 2.5 (when using mvn hpi:run in development). 647 | * added: 2 new graphs are displayed in "Other charts", below the main 648 | charts: "% System CPU" and "Used buffered memory" 649 | ([5029404](https://github.com/javamelody/javamelody/commit/5029404eeb24e7b5c657453d06e9fc603fa5eb0d)). 650 | * **% System CPU** is the CPU usage for the whole system (not just 651 | the JVM), between 0 and 100%. 652 | * **Used buffered memory** is the memory used, either by *direct 653 | buffers* allocated outside of the garbage-collected heap, using 654 | [ByteBuffer.allocateDirect](http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#allocateDirect%28int%29), 655 | or by *mapped buffers* created by mapping a region of a file 656 | into memory, using 657 | [FileChannel.map](http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html#map%28java.nio.channels.FileChannel.MapMode,%20long,%20long%29). 658 | 659 | #### 1.57.0 (Aug 31, 2015) 660 | 661 | * fix: check if async before flushing the response 662 | ([ee87b4b](https://github.com/javamelody/javamelody/commit/ee87b4b0be7fb11fd0d81a27923732d674b932d7) 663 | thanks to *Mark Thomas*) 664 | * fix: used/max file descriptor counts are not displayed in oracle 665 | java 8 666 | ([c04ef79](https://github.com/javamelody/javamelody/commit/c04ef7925977f17566581b81909bb62780b947e9) 667 | thanks to *Colin Ingarfield*) 668 | * Jenkins plugin: scripts examples updated to get data from slaves in 669 | [Jenkins Monitoring Scripts](https://github.com/jenkinsci/monitoring-plugin/blob/master/docs/MonitoringScripts.md), below the scripts for Jenkins master. 670 | * improved: An [api 671 | page](https://github.com/javamelody/javamelody/blob/master/javamelody-core/src/main/resources/net/bull/javamelody/resource/help/api.html) 672 | is now available in the monitoring with links to the 673 | [ExternalAPI](https://github.com/javamelody/javamelody/wiki/ExternalAPI). 674 | The path of the page in your Jenkins is 675 | "monitoring?resource=help/api.html". 676 | * added: it's now easy to write scripts to get monitoring data from a 677 | monitored webapp and to send alerts based on thresholds, using 678 | Jenkins for Continuous Monitoring. See the 679 | [documentation](https://github.com/javamelody/javamelody/wiki/ScriptsAndAlerts). 680 | 681 | #### JavaMelody migration to Github 682 | 683 | * The JavaMelody project is migrated from GoogleCode 684 | () to GitHub. The new project 685 | home page is: 686 | * The monitoring plugin for Jenkins does not move and is at 687 | 688 | 689 | #### 1.56.0 (May 2, 2015) 690 | 691 | * fix [issue 692 | 477](https://github.com/javamelody/javamelody/issues/477): In the 693 | processes list, CPU and Command are sometimes in the wrong column 694 | * added: MULTILINE & DOTALL flags for transform-patterns regexps 695 | ([issue 474](https://github.com/javamelody/javamelody/issues/474), 696 | thanks to *Michal Bergmann*). 697 | 698 | #### 1.55.0 (Jan 30, 2015) 699 | 700 | * fix [issue 701 | 453](https://github.com/javamelody/javamelody/issues/453): Chinese 702 | translation for heap dump (thanks to *chuxuebao*) 703 | * fix [issue 704 | 436](https://github.com/javamelody/javamelody/issues/436): implement 705 | Servlet 3.1 new methods (JavaEE 7), in FilterServletOutputStream and 706 | others 707 | * fix [issue 708 | 455](https://github.com/javamelody/javamelody/issues/455): HTTP-401 709 | / WWW-Authenticate wrongly reported as HTTP error 710 | 711 | #### 1.54.0 (Now 30, 2014) 712 | 713 | * fix: Monitoring reports of a slave didn't work if its name contains 714 | a space. 715 | * fix [issue 716 | 440](https://github.com/javamelody/javamelody/issues/440): Not able 717 | to start Desktop version. 718 | 719 | #### 1.53.1 (Oct 3, 2014) 720 | 721 | * fix: in v1.52.0 with Tomcat, graphs of bytes received/sent and of 722 | Tomcat active threads were not displayed anymore in "Other charts" 723 | ([revision 724 | 3908](https://code.google.com/p/javamelody/source/detail?r=3908)). 725 | * fix [issue 726 | 439](https://github.com/javamelody/javamelody/issues/439): Display 727 | Linux version in "System informations", and not "Linux unknown" 728 | * improved: Portuguese translation ([revision 729 | 3885](https://code.google.com/p/javamelody/source/detail?r=3885), 730 | thanks to *Fernando Boaglio*) 731 | * added: new system property "javamelody.sampling-included-packages" 732 | for a white list in [cpu 733 | hotspots](https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#enable-hotspots-detection), 734 | instead of using the "javamelody.sampling-excluded-packages" system 735 | property ([issue 736 | 424](https://github.com/javamelody/javamelody/issues/424), thanks to 737 | *alf.hogemark*) 738 | 739 | #### 1.53.0 (Oct 1, 2014) 740 | 741 | * fix security issues. See [Jenkins security 742 | advisory](https://wiki.jenkins-ci.org/display/SECURITY/Jenkins+Security+Advisory+2014-10-01). 743 | 744 | #### 1.52.1 (Aug 6, 2014) 745 | 746 | * fix: for Maven type jobs on recent Jenkins versions, builds of Maven 747 | modules are displayed as always running in the /monitoring/nodes 748 | page 749 | * fix: the logout action in the menu did not work in the 750 | /monitoring/nodes page 751 | 752 | #### 1.52.0 (Aug 3, 2014) 753 | 754 | * **Upgraded mininum Jenkins** version to 1.509.3 755 | * added: display of **build steps** and their durations, in the detail 756 | of each build statistics in the "/monitoring/nodes" page. Example: 757 | 758 |   759 | 760 | * added: The system property "javamelody.nodes-monitoring-disabled" 761 | can be used to disable the periodic monitoring of slaves. Either at 762 | startup, for example "-Djavamelody.nodes-monitoring-disabled=true" 763 | in the jenkins.xml file, or even at runtime. **Disabling periodic 764 | monitoring of slaves** can help against issues, if there are Jenkins 765 | slaves and if the communication with slaves is too unstable in the 766 | Jenkins remoting. 767 | * improved: reduce the number of RRD files created in some conditions, 768 | by not creating a RRD file of mean times if a request is called only 769 | once ([revision 770 | 3836](https://code.google.com/p/javamelody/source/detail?r=3836)). 771 | Otherwise, obsolete RRD files are automatically deleted after 3 772 | months like before. 773 | * added: links "View in a new page" below the tables of threads and of 774 | current requests ([revision 775 | 3839](https://code.google.com/p/javamelody/source/detail?r=3839)). 776 | For example when Jenkins is under load, the new pages make it easy 777 | to refresh at will the details of threads or of the current requests 778 | to see if states change or not, without refreshing all the main 779 | page. 780 | * added: logout action in the menu on the right of the main report 781 | ([revision 782 | 3859](https://code.google.com/p/javamelody/source/detail?r=3859)) 783 | * fixed 784 | [JENKINS-21357](https://issues.jenkins-ci.org/browse/JENKINS-21357) 785 | Node monitoring action: Use the specific computer's sidepanel 786 | instead of Jenkins default page. But the actions on the left 787 | sidepanel may be broken because of 788 | [JENKINS-23963](https://issues.jenkins-ci.org/browse/JENKINS-23963). 789 | 790 | #### 1.51.0 (Jun 5, 2014) 791 | 792 | * fix: when using java 8, cpu graph was not displayed 793 | * Drop Java 5 support ([revision 794 | 3795](https://code.google.com/p/javamelody/source/detail?r=3795)) 795 | * Optimized desktop UI startup time, by downloading desktop app and 796 | caching locally ([revision 797 | 3762](https://code.google.com/p/javamelody/source/detail?r=3762)) 798 | * improved: in a graph detail, a checkbox can now hide maximum values 799 | in the graph, so that average values are better displayed when much 800 | lower than the maximum ([issue 801 | 368](https://github.com/javamelody/javamelody/issues/368)) 802 | * added: PID in the heap dump file name ([revision 803 | 3773](https://code.google.com/p/javamelody/source/detail?r=3773)) 804 | 805 | #### 1.50.0 (Mar 27, 2014) 806 | 807 | * Fix icons and links on some Jenkins servers in the new Monitoring 808 | page of individual nodes 809 | ([JENKINS-20935](https://issues.jenkins-ci.org/browse/JENKINS-20935)) 810 | * fix issue [issue 811 | 370](https://github.com/javamelody/javamelody/issues/370): work 812 | around ConcurrentModificationException during Tomcat startup (which 813 | is a [Tomcat 814 | bug](https://issues.apache.org/bugzilla/show_bug.cgi?id=56082)) 815 | * fix issue [issue 816 | 386](https://github.com/javamelody/javamelody/issues/386): 817 | IllegalArgumentException: No enum const class ..., in Turkish 818 | * improved: In the US, depending on the browser's language or on the 819 | javamelody parameter "locale", the paper size is now Letter in the 820 | US, instead of A4 like in the other countries. ([revision 821 | 3679](https://code.google.com/p/javamelody/source/detail?r=3679), 822 | thanks to *Dennis*) 823 | * improved css styles: font finally fixed to Arial/Helvetica 824 | ([revision 825 | 3718](https://code.google.com/p/javamelody/source/detail?r=3718)). 826 | * added: **Menu**. A floating button is available on the right of the 827 | main report to drag a menu in or out. The menu displays the list of 828 | chapters in the report and allows to jump easily between them 829 | ([revision 830 | 3705](https://code.google.com/p/javamelody/source/detail?r=3705)). 831 | * added: **Custom reports**. Links to custom reports can be included 832 | in the floating menu described above. 833 | For that, add a system property named "javamelody.custom-reports". 834 | In the value of this system property, put the list of names of the 835 | custom reports separated with commas. Then for each custom report, 836 | add a system property with the same name and its path as value. By 837 | default, the following properties are already defined: 838 | -Djavamelody.custom-reports=JenkinsInfo,AboutMonitoring 839 | -Djavamelody.JenkinsInfo=/systemInfo 840 | -Djavamelody.AboutMonitoring= 841 | 842 | #### 1.49.0 (Jan 12, 2014) 843 | 844 | * added: For each individual node (each slave in 845 | ), reports and actions are available from 846 | the "Monitoring" page in the contextual menu or in the detail of the 847 | node: 848 | * Threads, process list, MBeans of that node only 849 | * Heap histogram of that node 850 | * Actions for GC, heap dump 851 | * ([JENKINS-20935](https://issues.jenkins-ci.org/browse/JENKINS-20935), 852 | with help from Oleg Nenashev) 853 | * improved: When I call the "Invalidate http sessions" action, 854 | invalidate all sessions except mine (I can still invalidate my 855 | session individually after that) 856 | * improved: In the list of http sessions, a bullet shows which one is 857 | my own session, if I have a session 858 | * improved css styles with the come back of shadows in Firefox and 859 | with hovers for images, \~_(see) 860 | _([JavaMelody\ Demo](https://code.google.com/p/javamelody/wiki/Demo))\~ 861 | ([revision 862 | 3614](https://code.google.com/p/javamelody/source/detail?r=3614)) 863 | 864 | #### 1.48.0 (Nov 20, 2013) 865 | 866 | * fix 867 | [JENKINS-20352](https://issues.jenkins-ci.org/browse/JENKINS-20532): 868 | HTTP session count is high, since Jenkins v1.535 ([revision 869 | 3569](https://code.google.com/p/javamelody/source/detail?r=3569)) 870 | * fix [issue 871 | 354](https://github.com/javamelody/javamelody/issues/354): With the 872 | java update 1.7\_u45, the Desktop app does not start 873 | 874 | #### 1.47.0 (Sep 29, 2013) 875 | 876 | * fix [issue 877 | 339](https://github.com/javamelody/javamelody/issues/339): "One day" 878 | memory leak 879 | * fix [issue 880 | 346](https://github.com/javamelody/javamelody/issues/346): XSS 881 | through X-Forwarded-For header spoofing 882 | * fix [issue 883 | 232](https://github.com/javamelody/javamelody/issues/232): Use the 884 | path of -XX:HeapDumpPath=/tmp if defined, for the directory of heap 885 | dump files (otherwise use the temp directory of the server as 886 | before) 887 | * added: detection of cpu hotspots can be enabled ([issue 888 | 149](https://github.com/javamelody/javamelody/issues/149), with some 889 | ideas from Cédric Lime). 890 | * In the monitoring reports, the new Hotspots screen displays CPU 891 | hotspots in executed methods for all the JVM. Like javamelody, 892 | the overhead of hotspots is low: it is based on sampling of 893 | stack-traces of threads, without instrumentation. And like 894 | javamelody, it is made to be always active if enabled. (It is 895 | currently not enabled by default. It may be enabled by default 896 | in the future.) Two parameters can be defined as system 897 | properties in the jenkins.xml file: 898 | * "javamelody.sampling-seconds" to enable the sampling and to 899 | define its period. A period of 10 seconds can be recommended to 900 | have the lowest overhead, but then a few hours may be needed to 901 | have significant results for a webapp under real use. If you 902 | don't mind having a bit more overhead or want a result faster in 903 | test, you can use a value of 1 or 0.1 in second for this 904 | parameter. 905 | * "javamelody.sampling-excluded-packages" to change the list of 906 | the excluded packages 907 | ("java,sun,com.sun,javax,org.apache,org.hibernate,oracle,org.postgresql,org.eclipse" 908 | by default) 909 | 910 | #### 1.46.0 (Aug 4, 2013) 911 | 912 | * fix 913 | [JENKINS-17757](https://issues.jenkins-ci.org/browse/JENKINS-17757) 914 | IllegalStateException: Timer already cancelled from 915 | NodesCollector.scheduleCollectNow 916 | * use a timeout for the monitoring of slaves, when a slave is online 917 | but does not respond 918 | * fix NPE when manually purging the obsolete monitoring files of 919 | slaves 920 | 921 | #### 1.45.0 (Jun 6, 2013) 922 | 923 | * added: button to kill a thread from the current requests (issue 924 | [issue 302](https://github.com/javamelody/javamelody/issues/302)) 925 | * added: button to donate in the html reports, to better inform users 926 | of this possibility 927 | 928 | #### 1.44.0 (Mar 30, 2013) 929 | 930 | * fix: it is currently useless to display the sql hits for the current 931 | requests 932 | * fix: better aggregation of http requests in the statistics, for URLs 933 | /adjuncts/... and /$stapler/bound/... (also reduces the disk space 934 | used to store data) 935 | * fix [issue 936 | 289](https://github.com/javamelody/javamelody/issues/289), 937 | [JENKINS-15529](https://issues.jenkins-ci.org/browse/JENKINS-15529): 938 | NoClassDefFoundError: com/sun/management/OperatingSystemMXBean, in 939 | JBoss AS 7 without configuration of modules 940 | * page added: Some can be executed using the Jenkins Script Console. 941 | 942 | #### 1.43.0 (Jan 27, 2013) 943 | 944 | * fix [issue 945 | 270](https://github.com/javamelody/javamelody/issues/270): French 946 | Canadians can't choose a customized period 947 | * fix: in the current requests, use the chosen period to display the 948 | statistics of mean times, besides the elapsed times 949 | * added: PDF report of the current requests 950 | * added: optional parameter "locale" to fix the locale of the reports, 951 | whatever the language in the browser ([issue 952 | 271](https://github.com/javamelody/javamelody/issues/271), thanks to 953 | *xiukongtiao*). You can add, for example, the system property 954 | -Djavamelody.locale=en\_US 955 | 956 | #### 1.42.0 (Dec 2, 2012) 957 | 958 | * fix [issue 262](https://github.com/javamelody/javamelody/issues/262) 959 | NullPointerException in MonitoringFilter.doFilter(), when the webapp 960 | is undeployed and after a timeout 961 | * added: New alternative User Interface for the monitoring reports 962 | with a **Rich Desktop Application**. Highlights : 963 | * All reports and data like in the web UI 964 | * Exports to PDF, XML and JSON formats, even if the monitored 965 | application does not have the dependencies to do the same in the 966 | web UI 967 | * Tabs to view different reports 968 | * Columns of tables may be sorted, resized and moved 969 | * Exports with right-click for all tabular data to CSV, PDF, RTF, 970 | HTML, XML, JSON formats 971 | * Shortcuts, such as F5 972 | * Started in one-click with the "Desktop" link at the top of the 973 | web UI. The required libraries are downloaded automatically from 974 | \~_(googlecode)\~ github on the first launch. 975 | * Uses JavaWebStart and requires [JRE 1.7](http://java.com) on the 976 | client 977 | * This new UI may be an alternative to the web UI for advanced 978 | users or for exports 979 | 980 | #### 1.41.0 (Sep 30, 2012) 981 | 982 | * fix [issue 252](https://github.com/javamelody/javamelody/issues/252) 983 | Add XSS protection 984 | * fix [issue 255](https://github.com/javamelody/javamelody/issues/255) 985 | exception while collecting data java.io.FileNotFoundException: Could 986 | not open ....rrd existent 987 | 988 | #### 1.40.0 (Aug 26, 2012) 989 | 990 | * fix [issue 991 | 14050](http://issues.jenkins-ci.org/browse/JENKINS-14050), also for 992 | the monitoring reports of Nodes. 993 | * added in the external API: XML and JSON exports of MBeans, and of 994 | JNDI tree given a JNDI context path. Documentation is 995 | [here](https://github.com/javamelody/javamelody/wiki/ExternalAPI#xml). 996 | For example: 997 | [MBeans](http://demo.javamelody.cloudbees.net/monitoring?format=xml&part=mbeans) 998 | and 999 | [JNDI](http://demo.javamelody.cloudbees.net/monitoring?format=json&part=jndi&path=comp). 1000 | 1001 | #### 1.39.0 (Jun 21, 2012) 1002 | 1003 | * fix [issue 1004 | 14050](http://issues.jenkins-ci.org/browse/JENKINS-14050), also when 1005 | security is enabled in Jenkins: Unreadable HTML response for the 1006 | monitoring reports. Compression of the monitoring reports is now 1007 | disabled in the plugin and the reports will be compressed by Jenkins 1008 | starting with v1.470. 1009 | 1010 | #### 1.38.0 (Jun 17, 2012) 1011 | 1012 | * fix [issue 1013 | 14050](http://issues.jenkins-ci.org/browse/JENKINS-14050), but only 1014 | when security is not enabled in Jenkins: Unreadable HTML response 1015 | for the monitoring reports 1016 | 1017 | #### 1.37.0 (Apr 29, 2012) 1018 | 1019 | * fix issue 207: Incompatibility with servlet api 2.4 (Tomcat 5.5) in 1020 | Monitoring plugin 1.36.0 1021 | * added: Reduce the possibility of storage overload by deleting 1022 | automatically the obsolete RRD files (which were not updated for the 1023 | last 3 months), and which were for requests which do not exist 1024 | anymore. Note: the size of existing RRD files is fixed for ever and 1025 | old .ser.gz files are already automatically deleted after a year. 1026 | * added: Display the disk usage of the storage at the bottom of the 1027 | report 1028 | 1029 | #### 1.36.0 (Mar 30, 2012) 1030 | 1031 | * [JavaMelody](https://github.com/javamelody/javamelody/wiki) is used 1032 | inside the Monitoring plugin. Thanks to 1033 | [CloudBees](http://www.cloudbees.com) Jenkins CI, [nightly 1034 | build](https://javamelody.ci.cloudbees.com/job/javamelody/), 1035 | [javadoc](https://javamelody.ci.cloudbees.com/job/javamelody/site/apidocs/index.html) 1036 | and 1037 | [sources](https://javamelody.ci.cloudbees.com/job/javamelody/site/xref/index.html) 1038 | of JavaMelody are available. 1039 | \~_(And\ there\ is\ a\ public\ demo\ of\ JavaMelody.\ It\ is\ based\ on\ the\ latest\ source\ in\ trunk\ and\ is\ continuously\ deployed.\ It\ is\ currently\ not\ a\ demo\ in\ Jenkins,\ but\ instead\ in\ an\ application\ with\ GWT,\ services\ and\ SQL.)\~ 1040 | \~_(First,\ you\ can\ play\ with\ this\ quick\ and\ dirty) 1041 | _([GWT\ application](http://demo.javamelody.cloudbees.net/)) 1042 | _(to\ have\ some\ data\ (thanks\ Benjamin))\~ 1043 | \~_(Then\ you\ can\ view\ the\ charts\ and\ the\ statistics\ in\ the) 1044 | _([monitoring\ reports](http://demo.javamelody.cloudbees.net/monitoring)) 1045 | _((no\ password))\~ 1046 | 1047 |   1048 | 1049 | * Other notes: 1050 | * fix blocking issue 194: The jrobin v1.5.9 artifacts are now 1051 | available in the Maven central repository as you can see 1052 | [here](http://search.maven.org/). The external (and currently 1053 | unreachable) repository in the javamelody pom is now useless and 1054 | removed. 1055 | * fix issue 201: Unable to render MBeans tree when some 1056 | JMX-retrieval exception occurs 1057 | added: if there are deadlocked threads in the JVM, print a 1058 | warning message with the names of the deadlocked threads at the 1059 | top of threads dump, like in the html and pdf reports 1060 | (revision 2678) 1061 | * This version requires a Servlet 2.5 container (fixed in 1.37.0) 1062 | 1063 | #### 1.35.0 (Feb 28, 2012) 1064 | 1065 | * fix issue 178: Since v1.32, "Nb of http sessions" is 0 and "View 1066 | http sessions" is always empty. 1067 | * added: graphic of "Build queue length" in the monitoring of nodes, 1068 | next to the graphic of "Running builds" (done in Jenkins Hackathon, 1069 | with help from Kohsuke Kawaguchi) 1070 | * added: optional parameter (-Djavamelody.dns-lookups-disabled=true) 1071 | to allow disabling of dns lookups with InetAddress.getLocalHost() to 1072 | prevent long hangs on startup/shutdown in some particular 1073 | environments (issue 181, thanks to r6squeegee) 1074 | 1075 | #### 1.34.0 (Jan 28, 2012) 1076 | 1077 | * Minor bugfixes such as fonts in the PDF reports for Chinese people, 1078 | when the first PDF report was made for non Chinese people 1079 | 1080 | #### 1.33.0 (Nov 29, 2011) 1081 | 1082 | * fix [issue 11293](http://issues.jenkins-ci.org/browse/JENKINS-11293) 1083 | Monitoring plugin not installed because of NoClassDefFoundError: 1084 | org.slf4j.ILoggerFactory on IBM J9 JVM ([rev 1085 | 40073](https://svn.jenkins-ci.org/trunk/hudson/plugins/monitoring/pom.xml)) 1086 | 1087 | #### 1.32.1 (Oct 14, 2011) 1088 | 1089 | * fix issue 151: a Java 1.6 dependency was introduced in 1.32.0 1090 | (NoSuchFieldError: ROOT) 1091 | 1092 | #### 1.32.0 (Oct 13, 2011) 1093 | 1094 | * fix issue 141: exception while collecting data java.io.IOException: 1095 | Read failed, file xyz not mapped for I/O (after out of disk space) 1096 | * added: Chinese translation, and fix display of Chinese characters in 1097 | the JRobin graphics and in the PDF reports (issue 150) 1098 | * added: Action "Generate a heap dump" added for IBM JDK like for 1099 | Oracle JDK, patch by David Karlsen in the javamelody users' group 1100 | * added: Add link "Dump threads as text" below the list of threads 1101 | * added: Provide an url (monitoring?action=mail\_test) to test sending 1102 | a pdf report by mail (issue 145). 1103 | 1104 | #### 1.31.0 (Aug 14, 2011) 1105 | 1106 | * fix issue 128: Clean the shutdown process 1107 | * To display the username in the list of http sessions, look at 1108 | ACEGI\_SECURITY\_LAST\_USERNAME if getRemoteUser() was null. 1109 | 1110 | #### 1.30.0 (Jul 15, 2011) 1111 | 1112 | * fix issue 116: MBeans overview does not work with java 1.5 1113 | * fix issue 117: Sorting of numbers is based on String comparison in 1114 | German 1115 | * fix issue 122: Average number of requests per minutes seems to be 1116 | wrong, with a single day in a custom period 1117 | * fix issue 124: Start date removed from the text at the top of the 1118 | monitoring page, except if the "All" period is selected. 1119 | 1120 | #### 1.29.0 1121 | 1122 | * fix issue 106: a few HTTP hits are lost in the statistics for the 1123 | first hit(s) on new requests (no impact on statistics once requests 1124 | are known) 1125 | 1126 | #### 1.28.0 1127 | 1128 | * fix issue 99: NullPointerException when displaying the list of 1129 | process on AIX 1130 | 1131 | #### 1.27.0 1132 | 1133 | * added: pdf report of MBeans 1134 | 1135 | #### 1.26.0 1136 | 1137 | * fix [issue 8344](http://issues.jenkins-ci.org/browse/JENKINS-8344) 1138 | (ClassNotFoundException: net.bull.javamelody.SessionListener) 1139 | * added: **Portuguese Brazil translation**, including the online help, 1140 | thanks to *Luiz Gonzaga da Mata* and *Renan Oliveira da Cunha*. This 1141 | translation is the default for all Portuguese people. The first 1142 | language in the browser settings should be Portuguese (pt) or 1143 | Portuguese/Brazil (pt-br) to use it. The [online help in Portuguese 1144 | Brazil](https://github.com/javamelody/javamelody/blob/master/javamelody-core/src/site/resources/Ajuda_on-line_do_monitoring.pdf) 1145 | is also available. 1146 | * added: in the nodes report, chart of the number of the running 1147 | builds by period 1148 | 1149 | #### 1.25.0 1150 | 1151 | * fix some issues in the monitoring of Jenkins nodes when the 1152 | operating systems of the nodes are heterogeneous 1153 | * fix issue 80: Memory histogram should be supported on Mac OS X 1154 | * added: if JRockit, display the JRockit specific MBeans 1155 | * added: pdf reports of http sessions and of heap histogram 1156 | 1157 | #### 1.24.0 1158 | 1159 | * fix issue 74: "View OS Processes" does not work on MAC OS X Server 1160 | 1161 |   1162 | 1163 | * added: In the system actions, new view "MBeans" with the values and 1164 | the descriptions of the attributes. (MBeans contain configuration 1165 | and low-level data on the application server and on the JVM). The 1166 | values are viewable but not writable and operations can not be 1167 | performed. 1168 | 1169 |   1170 | 1171 | * added: Monitoring of the **Jenkins nodes** (slaves in general) 1172 | similar to the monitoring of the Jenkins master. 1173 | 1174 | If the monitoring of the Jenkins master is available at 1175 | then the monitoring of the 1176 | Jenkins nodes is available at 1177 | . 1178 | 1179 | The monitoring of the Jenkins nodes includes: 1180 | * Aggregated "used memory" chart, aggregated "% cpu" chart 1181 | (between 0 and 100) for day, week, month, year or a custom 1182 | period. 1183 | * Chart of the build times over time for the selected period 1184 | * Other aggregated charts: % GC, threads count, loaded classes 1185 | count, system load average, open file descriptors count and more 1186 | for the selected period 1187 | * Statistics of the build times for the selected period 1188 | * Running builds with time elapsed 1189 | * Threads informations for each node including name, state, 1190 | stack-trace and an action to kill any thread 1191 | * Heap histogram aggregated for all nodes 1192 | * Current system informations for each node 1193 | * MBeans for each node 1194 | * Last values in charts and MBeans values. For example, the 1195 | following URLs can be used: 1 and 2 (the 1196 | plugin-authentication-disabled parameter could be used) 1197 | * Process informations for each node 1198 | * Actions to execute the GC or to generate a heap dump on each 1199 | node 1200 | 1201 |   1202 | 1203 | * Due to the current infrastructure changes for the [maven2-repository 1204 | in java.net](https://maven2-repository.dev.java.net/), the 1205 | "Monitoring" plugin 1.24.0 was not in the plugin manager. 1206 | 1207 | #### 1.23.0 1208 | 1209 | * fix [issue 1210 | 66](http://code.google.com/p/javamelody/issues/detail?id=66): Since 1211 | tomcat 6.0.21 and when tomcat based authentication is used, session 1212 | count is false and there is a possible memory leak for invalidated 1213 | http sessions in v1.22.0. This is because of the changes for tomcat 1214 | enhancement 1215 | [45255](https://issues.apache.org/bugzilla/show_bug.cgi?id=45255). 1216 | To tomcat experts: Isn't an http session supposed to die first 1217 | before being able to born a second time? 1218 | 1219 | #### 1.22.0 1220 | 1221 | * fix: Maximum values in statistics could be incorrect 1222 | * added major feature: graphic of the number of sessions and details 1223 | on http sessions with the link in "System informations" (this is 1224 | emulated without httpsessionlistener, because httpsessionlistener 1225 | can't be used in Jenkins plugins) 1226 | * added: If Jenkins security is enabled, the system property 1227 | -Djavamelody.plugin-authentication-disabled=true can be added to a 1228 | Jenkins server in order to disable authentication of the monitoring 1229 | page in the Monitoring plugin and to be able to add the server to a 1230 | javamelody centralized collect server. (A system property like 1231 | -Djavamelody.allowed-addr-pattern=127\\.0\\.0\\.1 can also be added 1232 | with the ip address of the collect server) 1233 | 1234 | #### 1.21.0 1235 | 1236 | * fix to display the list of http sessions when Tomcat throws an 1237 | exception "Session already invalidated" 1238 | * fix to display the list of process when using Windows in Germany 1239 | * added: If Tomcat or JBoss, new graphics in "Other charts" for the 1240 | number of active http and ajp threads in the server, the number of 1241 | bytes received per minute and the number of bytes sent per minute by 1242 | the server. 1243 | 1244 | #### 1.20.0 1245 | 1246 | * added: German translation thanks to Ewald Arnold. We would like to 1247 | have [feedback 1248 | here](http://groups.google.fr/group/javamelody/browse_thread/thread/5656e63513436b64). 1249 | * fix: In the html display of the current requests, put back the 1250 | complete http request with query parameters and values, like it was 1251 | displayed before v1.17.0 1252 | 1253 | #### 1.19.0 1254 | 1255 | * fix NumberFormatException requesting process information. 1256 | * fix (removed) jndi link in Winstone. 1257 | * added debugging logs. 1258 | 1259 | #### 1.18.0 1260 | 1261 | * other minor bugs fixed. 1262 | 1263 | #### 1.17.0 1264 | 1265 | * some minor bugs fixed. 1266 | 1267 | #### 1.15.1 1268 | 1269 | * change to **reduce disk usage**: Some common http requests are now 1270 | aggregated in statistics, for example on build numbers. 1271 | 1272 | The `javamelody.http-transform-pattern` parameter has now the default 1273 | value of 1274 | 1275 | /\\d+/\|/site/.+\|avadoc/.+\|/ws/.+\|obertura/.+\|estReport/.+\|iolations/file/.+\|/user/.+\|/static/\\w+/ 1276 | 1277 | and all matches in http URLs will be replaced by "$". Note that it is 1278 | possible on each Jenkins server to change the value of this parameter 1279 | with a system property `-Djavamelody.http-transform-pattern=xxx` in the 1280 | java command line. 1281 | 1282 | #### 1.15.0 1283 | 1284 | * change to reduce disk usage: Graphics in http errors and in errors 1285 | logs are no longer displayed 1286 | 1287 | #### 1.14.0 1288 | 1289 | * fix: There was an InternalError on ubuntu or debian using the tomcat 1290 | package with jsvc 1291 | 1292 | #### 1.13.0 1293 | 1294 | * added: remember the last selected period (with a persistent cookie 1295 | in the browser) 1296 | * added: UI option to display graphs and statistics for **custom 1297 | periods**, via fields of start and end dates of period to display 1298 | 1299 | #### 1.12.0 1300 | 1301 | * added: **New charts** "Threads count", "Loaded classes count", "Used 1302 | non heap memory", "Used physical memory", "Used swap space" 1303 | (displayed with the new link "Other charts") 1304 | * added: Button to kill a java thread 1305 | * added: parameters can now be specified in environment variables like 1306 | in system properties or webapp context 1307 | * added: new parameter "monitoring-path" to change the url 1308 | "/monitoring" of the report to "/admin/monitoring" for example 1309 | * added: new parameter "mail-periods" to change the period of mail 1310 | reports from weekly to daily or monthly or a combination of the 3 1311 | * added: display the version of JavaMelody at the bottom of the html 1312 | and pdf reports 1313 | * added: display of "ajax GET" or "ajax POST" in http requests names 1314 | for ajax requests 1315 | 1316 | #### 1.10.0 1317 | 1318 | * English: For people outside US, UK and France, default language is 1319 | now the default locale of the server or English. 1320 | 1321 | #### 1.9.0 1322 | 1323 | * Fix: The "Monitoring" link in "/manage" page did not work when 1324 | Jenkins was in a servlet context (not in the root context of the 1325 | server). 1326 | * JavaMelody fix: someone had an exception in report on Solaris 10 1327 | (getPID) 1328 | 1329 | #### 1.8.2 1330 | 1331 | * Removed jdbc graphs as there is no database in Jenkins, 1332 | * Removed sessions graph, values and links as the javamelody 1333 | SessionListener can't be registered without modifying web.xml 1334 | * Added a link in "/manage" page 1335 | * Added checkPermission to check authentication if configured 1336 | 1337 | #### 1.8.1 1338 | 1339 | * Initial 1340 | 1341 | ## Translations 1342 | 1343 | Translations for other languages such as Spanish are welcomed. 1344 | 1345 | To contribute in your own language, join the translation project at 1346 | . 1347 | 1348 | or see in English: 1349 | 1350 | the same in French: 1351 | 1352 | 1353 | 1354 | 1355 | ## Compiling and testing the plugin: 1356 | 1357 | Use maven commands "mvn hpi:run" or "mvn package" like for all Jenkins plugins 1358 | 1359 | http://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial 1360 | 1361 | [![Build Status](https://ci.jenkins.io/buildStatus/icon?job=Plugins%2Fmonitoring-plugin%2Fmaster)](https://ci.jenkins.io/job/Plugins/job/monitoring-plugin/job/master/) 1362 | --------------------------------------------------------------------------------