Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'semeru'
java-version: 11
java-version: 17
- run: unset _JAVA_OPTIONS

- name: Run tests
Expand Down
229 changes: 153 additions & 76 deletions README.adoc

Large diffs are not rendered by default.

Binary file removed assets/inventory_default_spans.png
Binary file not shown.
Binary file removed assets/inventory_node_graph.png
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/inventory_systems_localhost_spans.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/inventory_systems_localhost_trace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/log_logger_exception.png
Binary file not shown.
Binary file added assets/log_logger_info.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/log_logger_ok.png
Binary file not shown.
Binary file added assets/log_logger_warning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/log_system_err.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/log_system_out.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/log_system_out_println_exception.png
Binary file not shown.
Binary file removed assets/log_system_out_println_ok.png
Binary file not shown.
Binary file added assets/logs_overview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/logs_server_startup.png
Binary file not shown.
10 changes: 5 additions & 5 deletions finish/inventory/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>

<!-- OpenLiberty runtime -->
<liberty.var.system.http.port>9080</liberty.var.system.http.port>
Expand All @@ -40,19 +40,19 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.14.0</version>
<version>6.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>6.2.14.Final</version>
<version>7.0.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-json-binding-provider</artifactId>
<version>6.2.14.Final</version>
<version>7.0.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@
// end::copyright[]
package io.openliberty.guides.inventory;

import java.net.URI;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.json.JsonObject;

import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.rest.client.RestClientBuilder;

import io.openliberty.guides.inventory.client.SystemClient;
import io.openliberty.guides.inventory.model.InventoryList;
Expand All @@ -28,63 +32,67 @@
@ApplicationScoped
public class InventoryManager {

// tag::getLogger[]
private static final Logger LOGGER =
Logger.getLogger(InventoryManager.class.getName());
// end::getLogger[]

@Inject
@ConfigProperty(name = "system.http.port")
private int SYSTEM_PORT;

private Map<String, SystemData> systems = new ConcurrentHashMap<>();

public boolean contains(String host) {
return systems.containsKey(host);
}

public Properties getProperties(String hostname) {
try (SystemClient client = new SystemClient()) {
client.init(hostname, SYSTEM_PORT);
return client.getProperties();
}
}

public String getHealth(String hostname) {
try (SystemClient client = new SystemClient()) {
client.init(hostname, SYSTEM_PORT);
return client.getHealth();
public JsonObject getSystemLoad(String hostname) {
String uriString = "http://" + hostname + ":" + SYSTEM_PORT + "/system";
try (SystemClient client = RestClientBuilder.newBuilder()
.baseUri(URI.create(uriString))
.build(SystemClient.class)) {

JsonObject obj = client.getSystemLoad();
// tag::log1[]
LOGGER.log(Level.INFO,
"Retrieved system load from {0}", hostname);
// end::log1[]
return obj;
} catch (RuntimeException e) {
// tag::log2[]
LOGGER.log(Level.WARNING,
"Runtime exception while invoking system service", e);
// end::log2[]
} catch (Exception e) {
// tag::log3[]
LOGGER.log(Level.WARNING,
"Unexpected exception while processing system service request", e);
// end::log3[]
}
return null;
}

public InventoryList list() {
return new InventoryList(new ArrayList<>(systems.values()));
}

public void add(String host, Properties systemProps, String health) {
Properties props = new Properties();
props.setProperty("os.name", systemProps.getProperty("os.name"));
props.setProperty("user.name", systemProps.getProperty("user.name"));

systems.put(host, new SystemData(host, props, health));
}

public void update(String host, String health) {
public void set(String host, JsonObject systemLoad) {
SystemData system = systems.get(host);
system.setHealth(health);
if (system != null) {
system.setSystemLoad(systemLoad);
} else {
systems.put(host, new SystemData(host, systemLoad));
}
}

public int refreshAllSystemsHealth() {
int updated = 0;
public void refreshSystemsLoads() {
for (SystemData system : systems.values()) {
String hostname = system.getHostname();
String newHealth = getHealth(hostname);
if (!newHealth.equals(system.getHealth())) {
system.setHealth(newHealth);
updated++;
}
JsonObject systemLoad = getSystemLoad(hostname);
system.setSystemLoad(systemLoad);
}
return updated;
}

int clear() {
int propertiesClearedCount = systems.size();
public int clear() {
int systemsClearedCount = systems.size();
systems.clear();
return propertiesClearedCount;
return systemsClearedCount;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@
// end::copyright[]
package io.openliberty.guides.inventory;

import java.util.Properties;

import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.json.JsonObject;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
Expand All @@ -38,35 +36,16 @@ public class InventoryResource {
@GET
@Path("/{hostname}")
@Produces(MediaType.APPLICATION_JSON)
public Response getPropertiesForHost(@PathParam("hostname") String hostname) {
Properties props = null;
String health = manager.getHealth(hostname);
if (health.equals("ERROR")) {
public Response getSystemLoadForHost(@PathParam("hostname") String hostname) {
JsonObject systemLoad = manager.getSystemLoad(hostname);
if (systemLoad == null) {
return Response.status(Response.Status.NOT_FOUND)
.entity("{ \"error\" : \"Unknown hostname or the system "
+ "service may not be running on " + hostname + "\" }")
.build();
}
props = manager.getProperties(hostname);
if (!manager.contains(hostname)) {
manager.add(hostname, props, health);
} else {
manager.update(hostname, health);
}
return Response.ok(props).build();
}

@POST
@Path("/health/refresh")
@Produces(MediaType.APPLICATION_JSON)
public Response refreshAllSystemsHealth() {
int updated = manager.refreshAllSystemsHealth();
if (updated == 0) {
return Response.ok("{\"ok\": \"No systems needed refresh\"}")
.build();
}
return Response.ok("{\"ok\": \"Health refresh completed for all systems\", \"updated\": " + updated + "}")
.build();
manager.set(hostname, systemLoad);
return Response.ok(systemLoad).build();
}

@GET
Expand All @@ -83,7 +62,8 @@ public Response clearContents() {
return Response.ok("{\"ok\": \"No systems to clear\"}")
.build();
}
return Response.ok("{\"ok\": \"Cleared all systems\", \"cleared\": " + cleared + "}")
return Response.ok("{\"ok\": \"Cleared all systems\", \"cleared\": "
+ cleared + "}")
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@

@Singleton
@Startup
public class HealthCheckScheduler {
public class SystemLoadRefreshScheduler {

@Inject
private InventoryManager inventoryManager;

@Schedule(hour = "*", minute = "*", second = "*/30", persistent = false)
public void performHealthChecks() {
inventoryManager.refreshAllSystemsHealth();
@Schedule(hour = "*", minute = "*", second = "*/15", persistent = false)
public void refreshSystemLoads() {
inventoryManager.refreshSystemsLoads();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,130 +11,19 @@
// end::copyright[]
package io.openliberty.guides.inventory.client;

import java.net.URI;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Invocation.Builder;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.json.JsonObject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;

public class SystemClient implements AutoCloseable {

// tag::getLogger[]
private static final Logger LOGGER = Logger.getLogger(SystemClient.class.getName());
// end::getLogger[]

private static final String PROTOCOL = "http";
private static final String SYSTEM_PROPERTIES = "/system/properties";
private static final String SYSTEM_HEALTH = "/health";

private String hostname;
private int port;
private Client client;

public void init(String hostname, int port) {
this.hostname = hostname;
this.port = port;
}

private String buildUrl(String path) {
try {
URI uri = new URI(PROTOCOL, null, hostname, port, path, null, null);
return uri.toString();
} catch (Exception e) {
// tag::log1[]
LOGGER.log(Level.WARNING,
"URISyntaxException while building system service URL", e);
// end::log1[]
return null;
}
}

private Builder buildClientBuilder(String urlString) {
try {
this.client = ClientBuilder.newClient();
Builder builder = client.target(urlString).request();
return builder.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
} catch (Exception e) {
// tag::log2[]
LOGGER.log(Level.WARNING,
"Exception while creating REST client builder", e);
// end::log2[]
return null;
}
}

public Properties getProperties() {
String url = buildUrl(SYSTEM_PROPERTIES);
Builder builder = buildClientBuilder(url);
if (builder == null) {
return null;
}

try {
Response response = builder.get();
// tag::log3[]
LOGGER.log(Level.INFO,
"Received response with status: {0}", response.getStatus());
// end::log3[]
if (response.getStatus() == Status.OK.getStatusCode()) {
return response.readEntity(Properties.class);
} else {
// tag::log4[]
LOGGER.log(Level.WARNING,
"Response Status is not OK: {0}", response.getStatus());
// end::log4[]
}
} catch (RuntimeException e) {
// tag::log5[]
LOGGER.log(Level.WARNING,
"Runtime exception while invoking system service", e);
// end::log5[]
} catch (Exception e) {
// tag::log6[]
LOGGER.log(Level.WARNING,
"Unexpected exception while processing system service request", e);
// end::log6[]
}
return null;
}

public String getHealth() {
String url = buildUrl(SYSTEM_HEALTH);
Builder builder = buildClientBuilder(url);
if (builder == null) {
return "ERROR";
}
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

try {
Response response = builder.get();
int statusCode = response.getStatus();
if (statusCode == Status.OK.getStatusCode()) {
return "UP";
} else if (statusCode == Status.SERVICE_UNAVAILABLE.getStatusCode()) {
return "DOWN";
} else {
return "ERROR";
}
} catch (Exception e) {
// tag::log7[]
LOGGER.log(Level.WARNING,
"Unexpected exception while invoking system health endpoint", e);
// end::log7[]
}
return "ERROR";
}
@RegisterRestClient
@Path("/systemLoad")
public interface SystemClient extends AutoCloseable {

@Override
public void close() {
if (client != null) {
client.close();
}
}
@GET
@Produces(MediaType.APPLICATION_JSON)
JsonObject getSystemLoad() throws RuntimeException, Exception;
}
Loading