I have Java Struts application deployed on tomcat application.
- Java version - 8
- Struts version - 2.5.30
- Tomcat version - 9
I need to add monitoring on that application I need metrics for:
Each Action/API wise response time.
Total hits count for each Action/API.
After scraping its metrics in Prometheus I want to visualize it in Grafana so also suggest me what dashboard I can use?
How I can achieve this?
@Namespace("/api")
public class LoginController extends ActionSupport {
private static final long serialVersionUID = 1L;
private User userBean;
private static final Logger logger = LogManager.getLogger(LoginController.class);
private static Connection connection;
private static final Tracer tracer = GlobalTracer.get();
public User getUserBean() {
return userBean;
}
public void setUserBean(User user) {
userBean = user;
}
public LoginController() {
super();
userBean = new User();
initializeConnection();
createUser();
}
public void initializeConnection() {
System.out.println("1. After connection tracer" + tracer);
Span span = tracer.buildSpan("initializeConnection").start();
System.out.println("2. to see the spans" + span);
String jdbcURL = "jdbc:postgresql://localhost:5437/struts_demo";
String dbUser = "postgres";
String dbPassword = "redhat";
try {
logger.log(Level.INFO, "Connecting to the database...");
Class.forName("org.postgresql.Driver");
connection = DriverManager.getConnection(jdbcURL, dbUser, dbPassword);
if (connection != null && !connection.isClosed()) {
logger.log(Level.INFO, "Database connection is ready.");
}
} catch (ClassNotFoundException | SQLException e) {
logger.log(Level.ERROR, "Error connecting to the database", e);
} finally {
span.finish();
}
}
public String createUser() {
Span span = tracer.buildSpan("createUser").start();
try {
HttpServletRequest request = (HttpServletRequest) ServletActionContext.getRequest();
logger.log(Level.INFO, "Request Method: " + request.getMethod());
logger.log(Level.INFO, "Request Headers:");
Collections.list(request.getHeaderNames())
.forEach(headerName -> logger.log(Level.INFO, headerName + ": " + request.getHeader(headerName)));
// Ensure that the request content type is JSON
String contentType = request.getContentType();
if (contentType != null && contentType.startsWith("application/json")) {
String json = request.getReader().lines().reduce("", (accumulator, actual) -> accumulator + actual);
logger.log(Level.INFO, "Request Body: " + json);
setUserFromJson(json);
saveUserToDatabase();
return SUCCESS;
} else {
logger.log(Level.WARN, "Invalid content type. Expected application/json.");
addActionError("Invalid content type. Expected application/json.");
return ERROR;
}
} catch (IOException e) {
logger.log(Level.ERROR, "Error reading request body", e);
return ERROR;
} finally {
span.finish();
counter.labelValues("200").inc();
histogram.labelValues("200").observe(nanosToSeconds(System.nanoTime() - start));
}
}
private void setUserFromJson(String json) {
Span span = tracer.buildSpan("setUserFromJson").start();
try {
ObjectMapper objectMapper = new ObjectMapper();
User user = objectMapper.readValue(json, User.class);
if (user.getUsername() != null && !user.getUsername().isEmpty() &&
user.getPassword() != null && !user.getPassword().isEmpty()) {
userBean.setUsername(user.getUsername());
userBean.setPassword(user.getPassword());
validate();
} else {
addActionError("Username or password is missing in the JSON data.");
logger.log(Level.WARN, "Username or password is missing in the JSON data.");
}
} catch (IOException e) {
logger.log(Level.ERROR, "Error parsing JSON: " + e.getMessage(), e);
} finally {
span.finish();
}
}
private void saveUserToDatabase() {
Span span = tracer.buildSpan("saveUserToDatabase").start();
try {
logger.log(Level.INFO, "Save method call--------------------->");
String sql = "INSERT INTO users (username, password) VALUES (?, ?)";
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
preparedStatement.setString(1, userBean.getUsername());
preparedStatement.setString(2, userBean.getPassword());
int rowsAffected = preparedStatement.executeUpdate();
if (rowsAffected > 0) {
logger.log(Level.INFO, "User data inserted successfully.");
} else {
logger.log(Level.WARN, "User data not inserted.");
}
}
} catch (SQLException e) {
logger.log(Level.ERROR, "Error saving user data to the database", e);
e.printStackTrace();
span.log(e.getMessage());
} finally {
span.finish();
}
}
public void validate() {
if (userBean == null) {
addActionError("Invalid user data.");
return;
}
if (userBean.getUsername() == null || userBean.getUsername().trim().isEmpty()) {
addFieldError("userBean.username", "Username is required.");
}
if (userBean.getPassword() == null || userBean.getPassword().trim().isEmpty()) {
addFieldError("userBean.password", "Password is required.");
}
}
}
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!-- <constant name="struts.devMode" value="false" /> -->
<constant name="struts.url.http.port" value="82" />
<package name="rest" abstract="true" />
<package name="api" extends="json-default" namespace="/api">
<!-- Define action -->
<action name="createUser" class="Controller.LoginController" method="initializeConnection">
<interceptor-ref name="defaultStack"/>
<result name="success" type="json"/>
<result name="input" type="json"/>
<result name="error" type="json">
<!-- Define error message here -->
<param name="statusCode">400</param> <!-- HTTP status code for bad request -->
<param name="errorMessage">Invalid content type. Expected application/json.</param>
</result>
</action>
</package>
</struts>
I am trying JMX exporter to scrape its metrics but I am only getting following metrics there is nothing rearding response time and hits count:
# HELP jvm_memory_pool_allocated_bytes_total Total bytes allocated in a given JVM memory pool. Only updated after GC, not continuously.
# TYPE jvm_memory_pool_allocated_bytes_total counter
jvm_memory_pool_allocated_bytes_total{pool="Code Cache",} 3.4667776E7
jvm_memory_pool_allocated_bytes_total{pool="PS Eden Space",} 4.2735865772E11
jvm_memory_pool_allocated_bytes_total{pool="PS Old Gen",} 3.03343352E8
jvm_memory_pool_allocated_bytes_total{pool="PS Survivor Space",} 2.20935736E8
jvm_memory_pool_allocated_bytes_total{pool="Compressed Class Space",} 1.9232824E7
jvm_memory_pool_allocated_bytes_total{pool="Metaspace",} 4.02679504E8
# HELP jmx_exporter_build_info A metric with a constant '1' value labeled with the version of the JMX exporter.
# TYPE jmx_exporter_build_info gauge
jmx_exporter_build_info{version="0.19.0",name="jmx_prometheus_javaagent",} 1.0
# HELP jvm_memory_objects_pending_finalization The number of objects waiting in the finalizer queue.
# TYPE jvm_memory_objects_pending_finalization gauge
jvm_memory_objects_pending_finalization 0.0
# HELP jvm_memory_bytes_used Used bytes of a given JVM memory area.
# TYPE jvm_memory_bytes_used gauge
jvm_memory_bytes_used{area="heap",} 1.27170384E8
jvm_memory_bytes_used{area="nonheap",} 1.42056968E8
# HELP jvm_memory_bytes_committed Committed (bytes) of a given JVM memory area.
# TYPE jvm_memory_bytes_committed gauge
jvm_memory_bytes_committed{area="heap",} 1.384644608E9
jvm_memory_bytes_committed{area="nonheap",} 3.3517568E8
# HELP jvm_memory_bytes_max Max (bytes) of a given JVM memory area.
# TYPE jvm_memory_bytes_max gauge
jvm_memory_bytes_max{area="heap",} 1.4943256576E10
jvm_memory_bytes_max{area="nonheap",} -1.0
# HELP jvm_memory_bytes_init Initial bytes of a given JVM memory area.
# TYPE jvm_memory_bytes_init gauge
jvm_memory_bytes_init{area="heap",} 1.050673152E9
jvm_memory_bytes_init{area="nonheap",} 2555904.0
# HELP jvm_memory_pool_bytes_used Used bytes of a given JVM memory pool.
# TYPE jvm_memory_pool_bytes_used gauge
jvm_memory_pool_bytes_used{pool="Code Cache",} 3.071968E7
jvm_memory_pool_bytes_used{pool="Metaspace",} 1.03536176E8
jvm_memory_pool_bytes_used{pool="Compressed Class Space",} 7801112.0
jvm_memory_pool_bytes_used{pool="PS Eden Space",} 5.9292384E7
jvm_memory_pool_bytes_used{pool="PS Survivor Space",} 1064976.0
jvm_memory_pool_bytes_used{pool="PS Old Gen",} 6.6813024E7
# HELP jvm_memory_pool_bytes_committed Committed bytes of a given JVM memory pool.
# TYPE jvm_memory_pool_bytes_committed gauge
jvm_memory_pool_bytes_committed{pool="Code Cache",} 3.2702464E7
jvm_memory_pool_bytes_committed{pool="Metaspace",} 2.0445184E8
jvm_memory_pool_bytes_committed{pool="Compressed Class Space",} 9.8021376E7
jvm_memory_pool_bytes_committed{pool="PS Eden Space",} 1.19013376E8
jvm_memory_pool_bytes_committed{pool="PS Survivor Space",} 1572864.0
jvm_memory_pool_bytes_committed{pool="PS Old Gen",} 1.264058368E9
# HELP jvm_memory_pool_bytes_max Max bytes of a given JVM memory pool.
# TYPE jvm_memory_pool_bytes_max gauge
jvm_memory_pool_bytes_max{pool="Code Cache",} 2.5165824E8
jvm_memory_pool_bytes_max{pool="Metaspace",} -1.0
jvm_memory_pool_bytes_max{pool="Compressed Class Space",} 1.073741824E9
jvm_memory_pool_bytes_max{pool="PS Eden Space",} 5.600968704E9
jvm_memory_pool_bytes_max{pool="PS Survivor Space",} 1572864.0
jvm_memory_pool_bytes_max{pool="PS Old Gen",} 1.1207180288E10
# HELP jvm_memory_pool_bytes_init Initial bytes of a given JVM memory pool.
# TYPE jvm_memory_pool_bytes_init gauge
jvm_memory_pool_bytes_init{pool="Code Cache",} 2555904.0
jvm_memory_pool_bytes_init{pool="Metaspace",} 0.0
jvm_memory_pool_bytes_init{pool="Compressed Class Space",} 0.0
jvm_memory_pool_bytes_init{pool="PS Eden Space",} 2.63192576E8
jvm_memory_pool_bytes_init{pool="PS Survivor Space",} 4.3515904E7
jvm_memory_pool_bytes_init{pool="PS Old Gen",} 7.00448768E8
# HELP jvm_memory_pool_collection_used_bytes Used bytes after last collection of a given JVM memory pool.
# TYPE jvm_memory_pool_collection_used_bytes gauge
jvm_memory_pool_collection_used_bytes{pool="PS Eden Space",} 0.0
jvm_memory_pool_collection_used_bytes{pool="PS Survivor Space",} 1064976.0
jvm_memory_pool_collection_used_bytes{pool="PS Old Gen",} 2.0530536E7
# HELP jvm_memory_pool_collection_committed_bytes Committed after last collection bytes of a given JVM memory pool.
# TYPE jvm_memory_pool_collection_committed_bytes gauge
jvm_memory_pool_collection_committed_bytes{pool="PS Eden Space",} 1.19013376E8
jvm_memory_pool_collection_committed_bytes{pool="PS Survivor Space",} 1572864.0
jvm_memory_pool_collection_committed_bytes{pool="PS Old Gen",} 1.264058368E9
# HELP jvm_memory_pool_collection_max_bytes Max bytes after last collection of a given JVM memory pool.
# TYPE jvm_memory_pool_collection_max_bytes gauge
jvm_memory_pool_collection_max_bytes{pool="PS Eden Space",} 5.600968704E9
jvm_memory_pool_collection_max_bytes{pool="PS Survivor Space",} 1572864.0
jvm_memory_pool_collection_max_bytes{pool="PS Old Gen",} 1.1207180288E10
# HELP jvm_memory_pool_collection_init_bytes Initial after last collection bytes of a given JVM memory pool.
# TYPE jvm_memory_pool_collection_init_bytes gauge
jvm_memory_pool_collection_init_bytes{pool="PS Eden Space",} 2.63192576E8
jvm_memory_pool_collection_init_bytes{pool="PS Survivor Space",} 4.3515904E7
jvm_memory_pool_collection_init_bytes{pool="PS Old Gen",} 7.00448768E8
# HELP jvm_buffer_pool_used_bytes Used bytes of a given JVM buffer pool.
# TYPE jvm_buffer_pool_used_bytes gauge
jvm_buffer_pool_used_bytes{pool="direct",} 32767.0
jvm_buffer_pool_used_bytes{pool="mapped",} 0.0
# HELP jvm_buffer_pool_capacity_bytes Bytes capacity of a given JVM buffer pool.
# TYPE jvm_buffer_pool_capacity_bytes gauge
jvm_buffer_pool_capacity_bytes{pool="direct",} 32767.0
jvm_buffer_pool_capacity_bytes{pool="mapped",} 0.0
# HELP jvm_buffer_pool_used_buffers Used buffers of a given JVM buffer pool.
# TYPE jvm_buffer_pool_used_buffers gauge
jvm_buffer_pool_used_buffers{pool="direct",} 3.0
jvm_buffer_pool_used_buffers{pool="mapped",} 0.0
# HELP jvm_classes_currently_loaded The number of classes that are currently loaded in the JVM
# TYPE jvm_classes_currently_loaded gauge
jvm_classes_currently_loaded 8798.0
# HELP jvm_classes_loaded_total The total number of classes that have been loaded since the JVM has started execution
# TYPE jvm_classes_loaded_total counter
jvm_classes_loaded_total 8903.0
# HELP jvm_classes_unloaded_total The total number of classes that have been unloaded since the JVM has started execution
# TYPE jvm_classes_unloaded_total counter
jvm_classes_unloaded_total 105.0
# HELP jmx_config_reload_failure_total Number of times configuration have failed to be reloaded.
# TYPE jmx_config_reload_failure_total counter
jmx_config_reload_failure_total 0.0
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 791.07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.709208319509E9
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 83.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 262144.0
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 2.2867992576E10
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 1.661423616E9
# HELP jvm_gc_collection_seconds Time spent in a given JVM garbage collector in seconds.
# TYPE jvm_gc_collection_seconds summary
jvm_gc_collection_seconds_count{gc="PS Scavenge",} 1681.0
jvm_gc_collection_seconds_sum{gc="PS Scavenge",} 14.407
jvm_gc_collection_seconds_count{gc="PS MarkSweep",} 8.0
jvm_gc_collection_seconds_sum{gc="PS MarkSweep",} 0.789
# HELP jmx_scrape_duration_seconds Time this JMX scrape took, in seconds.
# TYPE jmx_scrape_duration_seconds gauge
jmx_scrape_duration_seconds 0.03731016
# HELP jmx_scrape_error Non-zero if this scrape failed.
# TYPE jmx_scrape_error gauge
jmx_scrape_error 0.0
# HELP jmx_scrape_cached_beans Number of beans with their matching rule cached
# TYPE jmx_scrape_cached_beans gauge
jmx_scrape_cached_beans 0.0
# HELP jvm_threads_current Current thread count of a JVM
# TYPE jvm_threads_current gauge
jvm_threads_current 26.0
# HELP jvm_threads_daemon Daemon thread count of a JVM
# TYPE jvm_threads_daemon gauge
jvm_threads_daemon 23.0
# HELP jvm_threads_peak Peak thread count of a JVM
# TYPE jvm_threads_peak gauge
jvm_threads_peak 29.0
# HELP jvm_threads_started_total Started thread count of a JVM
# TYPE jvm_threads_started_total counter
jvm_threads_started_total 1180.0
# HELP jvm_threads_deadlocked Cycles of JVM-threads that are in deadlock waiting to acquire object monitors or ownable synchronizers
# TYPE jvm_threads_deadlocked gauge
jvm_threads_deadlocked 0.0
# HELP jvm_threads_deadlocked_monitor Cycles of JVM-threads that are in deadlock waiting to acquire object monitors
# TYPE jvm_threads_deadlocked_monitor gauge
jvm_threads_deadlocked_monitor 0.0
# HELP jvm_threads_state Current count of threads by state
# TYPE jvm_threads_state gauge
jvm_threads_state{state="NEW",} 0.0
jvm_threads_state{state="TERMINATED",} 0.0
jvm_threads_state{state="RUNNABLE",} 6.0
jvm_threads_state{state="BLOCKED",} 0.0
jvm_threads_state{state="WAITING",} 16.0
jvm_threads_state{state="TIMED_WAITING",} 4.0
jvm_threads_state{state="UNKNOWN",} 0.0
# HELP jmx_config_reload_success_total Number of times configuration have successfully been reloaded.
# TYPE jmx_config_reload_success_total counter
jmx_config_reload_success_total 0.0
# HELP jvm_info VM version info
# TYPE jvm_info gauge
jvm_info{runtime="OpenJDK Runtime Environment",vendor="Red Hat, Inc.",version="1.8.0_402-b06",} 1.0
# HELP jmx_config_reload_failure_created Number of times configuration have failed to be reloaded.
# TYPE jmx_config_reload_failure_created gauge
jmx_config_reload_failure_created 1.709208319547E9
# HELP jmx_config_reload_success_created Number of times configuration have successfully been reloaded.
# TYPE jmx_config_reload_success_created gauge
jmx_config_reload_success_created 1.709208319546E9
# HELP jvm_memory_pool_allocated_bytes_created Total bytes allocated in a given JVM memory pool. Only updated after GC, not continuously.
# TYPE jvm_memory_pool_allocated_bytes_created gauge
jvm_memory_pool_allocated_bytes_created{pool="Code Cache",} 1.709208320572E9
jvm_memory_pool_allocated_bytes_created{pool="PS Eden Space",} 1.709208320571E9
jvm_memory_pool_allocated_bytes_created{pool="PS Old Gen",} 1.709208320572E9
jvm_memory_pool_allocated_bytes_created{pool="PS Survivor Space",} 1.709208320572E9
jvm_memory_pool_allocated_bytes_created{pool="Compressed Class Space",} 1.709208320572E9
jvm_memory_pool_allocated_bytes_created{pool="Metaspace",} 1.709208320572E9
[sriya@hd83p-kysweb2-001 ~]$ client_loop: send disconnect: Broken pipe