Is it possible to get a server heap dump on a running process on linux (CentOS) using JMX from command line ?
can't open VisualVM,
can't install jmap
It can be done with this simple code:
import com.sun.management.HotSpotDiagnosticMXBean;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
#SuppressWarnings("restriction")
public class CreateHeapDump
{
public static void main(String[] args) throws Exception
{
String host = args[0];
String port = args[1];
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + host + ":" + port + "/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName("com.sun.management:type=HotSpotDiagnostic");
HotSpotDiagnosticMXBean bean = JMX.newMBeanProxy(mbsc, mbeanName, HotSpotDiagnosticMXBean.class, true);
String fileName = "heap_dump_" + new SimpleDateFormat("dd.MM.yyyy HH.mm").format(new Date()) + ".hprof";
boolean onlyLiveObjects = true;
bean.dumpHeap(fileName, onlyLiveObjects);
}
}
Compile it:
javac CreateHeapDump.java
Call it from command line:
java CreateHeapDump localhost 9010
This won't be pretty, but it works. Having said that, you might want to consider scripting this in Groovy or Jython, or even JavaScript....
I added a quickie add-on to jmxlocal, a project which implements standard JMX remoting for local JVMs. It now supports a command line invocation of one command against the connected MBeanServer, and the command must be specified in Java code.
Clone the repo and build with mvn clean install.
Copy the jar (jmxlocal-1.0-SNAPSHOT.jar) to your target server.
Execute the dump JMX command using the PID of the target java process as follows:
java -jar target/jmxlocal-1.0-SNAPSHOT.jar -j service:jmx:attach:///<PID> -c "conn.invoke(on(\"com.sun.management:type=HotSpotDiagnostic\"), \"dumpHeap\", new Object[]{\"/tmp/heap.dump\", true}, new String[]{String.class.getName(), boolean.class.getName()})"
The output will be
Command Executed. Result [null]
and you should find your dump file at /tmp/heap.dump.
If you need to, you can supply credentials using the -u [username] and -p [password] arguments.
Related
I finally found the motivation to work with Docker : I tried to deploy a basic "hello-world" servlet, on a tomcat running on a docker container.
This servlet works perfectly when I run it on the Tomcat started by intelliJ.
But when I use it with Docker, using this Dockerfile
FROM tomcat:latest
ADD example.war /usr/local/tomcat/webapps/
EXPOSE 8080
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]
And I build/start the image/container:
docker build -t example .
docker run -p 8090:8080 example
The index.jsp is displayed correctly at localhost:8090/example/, but I get a 404 when trying to access the servlet at localhost:8090/example/hello-servlet
At the same time, I can access localhost:8080/example/hello-servlet, when my non dockerized tomcat runs, and it works well.
Here is the servlet code :
package io.bananahammock.bananahammock_backend;
import java.io.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
#WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
private String message;
public void init() {
message = "Hello World!";
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + message + "</h1>");
out.println("</body></html>");
}
public void destroy() {
}
}
What am I missing?
Since August 31, 2021 (this commit) the Docker image tomcat:latest uses Tomcat 10 (see the list of available tags).
As you are probably aware, software which uses the javax.* namespace does not work on Jakarta EE 9 servers such as Tomcat 10 (see e.g. this question). Therefore:
if it is a new project, migrate to the jakarta.* namespace and test everything on Tomcat 10 or higher,
if it is a legacy project, use another Docker image, e.g. the tomcat:9 tag.
I'm trying to run a "Hello, world" Spring Cloud Data Flow stream based on the very simple example explained at http://cloud.spring.io/spring-cloud-dataflow/. I'm able to create a simple source and sink and run it on my local SCDF server using Kafka, so until here everything is correct and messages are produced and consumed in the topic specified by SCDF.
Now, I'm trying to deploy it in my private cloud based on the instructions listed at http://docs.spring.io/spring-cloud-dataflow-server-kubernetes/docs/current-SNAPSHOT/reference/htmlsingle/#_getting_started. Using this deployment I'm able to deploy a simple "time | log" out-of-the-box stream with no problems, but my example fails since the producer is not writing in the topic specified when the pod is created (for instance, spring.cloud.stream.bindings.output.destination=ntest33.nites-source9) but in the topic "output". I have a similar problem with the sink component, which creates and expect messages in the topic "input".
I created the stream definition using the dashboard:
nsource1 | log
And container args for the source are:
--spring.cloud.stream.bindings.output.producer.requiredGroups=ntest34
--spring.cloud.stream.bindings.output.destination=ntest34.nsource1
Code snippet for source component is
package xxxx;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.core.MessageSource;
import org.springframework.messaging.support.GenericMessage;
#SpringBootApplication
#EnableBinding(Source.class)
public class HelloNitesApplication
{
public static void main(String[] args)
{
SpringApplication.run(HelloNitesApplication.class, args);
}
#Bean
#InboundChannelAdapter(value = Source.OUTPUT)
public MessageSource<String> timerMessageSource()
{
return () -> new GenericMessage<>("Hello " + new SimpleDateFormat().format(new Date()));
}
And in the logs I can see clearly
2017-04-07T09:44:34.596842965Z 2017-04-07 09:44:34,593 INFO main o.s.i.c.DirectChannel:81 - Channel 'application.output' has 1 subscriber(s).
Question is, how to override properly the topic where messages must be produced/consumed or what attribute and values to use to make this work on k8s?
UPDATE: I have the similar problem using RabbitMQ
2017-04-07T12:56:40.435405177Z 2017-04-07 12:56:40.435 INFO 7 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.output' has 1 subscriber(s).
The problem was with my docker image. I still don't know the details but using the Dockerfile indicated at https://spring.io/guides/gs/spring-boot-docker/ instantiated 2 processes in the docker container, one with the parameters, and other without, which was the one with uptime and therefore being used.
The solution was to replace
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
With
ENTRYPOINT [ "java", "-jar", "/app.jar" ]
And it started working. There must be a good reason why the example indicated the first entrypoint and why 2 processes were created, but the reason is still beyond my understanding.
Can you provide more details on how you set that configuration property? That feature is pretty basic, so this should work. If you are using a stream definition to set it, please update your question with the stream definition.
The channel name remains 'output' because that's what the application uses internally.
I am running my selenium tests via Jenkins on Headless Firefox browser on Cent OS.
I have written a code to capture screenshots on failure which works absolutley fine on my local windows environment but when I run the same script using Jenkins on CentOS the screenshot captured is of 0 bytes
Below is the Java code to capture Screenshot:
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
public class Screen_Capture {
public static void takeDesktopScreenshot(WebDriver driver,String dateFormat,String fileFormat,String screenPath){
File src=((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
try{
SimpleDateFormat s=new SimpleDateFormat(dateFormat);
String d=s.format(new Date());
FileUtils.copyFile(src, new File(screenPath+d+"."+fileFormat));
}
catch (Exception e) {}
}
}
The Screenshots are captured on Test Failure:
#Override
public void onTestFailure(ITestResult arg0) {
Screen_Capture.takeDesktopScreenshot(driver,dateFormat,fileFormat,screenPath);
log.error("Test Case Failed");
}
The Images saved on Jenkins Workspace is blank(0 bytes)
[Screen File Size is 0 Bytes][1]
Please help me to overcome this issue.
I am also attaching my Build Environment Configuration on Jenkins:
[Build Environment Configuration on Jenkins][2]
[1]: https://i.stack.imgur.com/NBNUD.png
[2]: https://i.stack.imgur.com/qMxPq.png
Hi Sometimes there may be permission issue with jenkins , try giving chmod -R 777 * and also try using chown the folder which download , first try manually and try using jenkins you will know the issue easily.
I am writing a package that loads additional data from the lib directory and would like to provide an easy way to load this data with something like this:
const dataPath = 'mypackage/data/data.json';
initializeMyLibrary(dataPath).then((_) {
// library is ready
});
I've made two separate libraries browser.dart and standalone.dart, similar to how it is done in the Intl package.
It is quite easy to load this data from the "browser" environment, but when it comes to the "standalone" environment, it is not so easy, because of the pub run command.
When the script is running with simple $ dart myscript.dart, I can find a package path using dart:io.Platform Platform.script and Platform.packageRoot properties.
But when the script is running with $ pub run tool/mytool, the correct way to load data should be:
detect that the script is running from the pub run command
find the pub server host
load data from this server, because there could be pub transformers and we can't load data directly from the file system.
And even if I want to load data directly from the file system, when the script is running with pub run, Platform.script returns /mytool path.
So, the question is there any way to find that the script is running from pub run and how to find server host for the pub server?
I am not sure that this is the right way, but when I am running script with pub run, Package.script actually returns http://localhost:<port>/myscript.dart. So, when the scheme is http, I can download using http client, and when it is a file, load from the file system.
Something like this:
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as ospath;
Future<List<int>> loadAsBytes(String path) {
final script = Platform.script;
final scheme = Platform.script.scheme;
if (scheme.startsWith('http')) {
return new HttpClient().getUrl(
new Uri(
scheme: script.scheme,
host: script.host,
port: script.port,
path: 'packages/' + path)).then((req) {
return req.close();
}).then((response) {
return response.fold(
new BytesBuilder(),
(b, d) => b..add(d)).then((builder) {
return builder.takeBytes();
});
});
} else if (scheme == 'file') {
return new File(
ospath.join(ospath.dirname(script.path), 'packages', path)).readAsBytes();
}
throw new Exception('...');
}
This Code is working fine with simple application so the drivers are fine.
so why the connection object is not able to initialise with drivers.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import com.opensymphony.xwork2.ActionSupport;
public class Insert extends ActionSupport {
public String execute() throws Exception, SQLException {
String sql = "";
String url = "jdbc:mysql://localhost:3306/test";
//String dbName = "test";
String driverName = "org.gjt.mm.mysql.Driver";
String userName = "root";
String password = "root";
Connection con=null;
Statement stmt=null;
try {
Class.forName(driverName).newInstance();
con = DriverManager.getConnection(url, userName, password);
stmt = con.createStatement();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
What does the exception say? A NullPointerException on createStatement?
In any case, has the class been loaded; is the class on the classpath (i.e. the MySQL jar on the classpath?)
Check the object returned from Class.forName() to check whether the class has been found.
After your comment it is clear that you have a classpath problem. The mysql jar is not on the classpath. I assume you are talking about a web app deliverable (war file), as changing the build path in eclipse is trivial.
In a web application deployed in, for example, tomcat you can look into <webapp-name>/WEB-INF/lib. The file WEB-INF/lib/mysql-connector-java-5.0.5.jar, or something similar, should be there.
If you have a war file (not yet deployed) you can extract it using the command line tool "jar", or get a file listing from it. If you do (on a command line) jar tf | grep mysql the jarfile should be visible. If you use windows; WinRAR (and probably WinZip) can also open warfiles. In WEB-INF/lib a MySQL jar should be visible.
If you use maven to build your web app; don't forget to add a dependency to the mysql jar. If you use ant to build; don't forget to copy the mysql jar file into WEB-INF/lib before creating the war file.
Please note that currently the recommended driver to ask for is 'com.mysql.driver.Driver', and not 'org.gjt.mm.mysql.Driver'. You can try to load that Driver class in stead of the older driver; further; check whether this driver is actually in the mysql jar (jar tf mysq.jar | grep Driver or so). If the Driver is in the mysql jar and the mysql jar is on the classpath of the webapp (in WEB-INF/lib) and there is only one mysql jar there (version conflicts are no fun), and it still does not work I really don't know what could be wrong. I think I'd download the driver jar again from MySQL and try again.