Skip to content

Commit

Permalink
use structured logging in SystemMonitor
Browse files Browse the repository at this point in the history
  • Loading branch information
ar committed Jul 8, 2024
1 parent faed8c6 commit 79251fd
Show file tree
Hide file tree
Showing 13 changed files with 359 additions and 146 deletions.
5 changes: 3 additions & 2 deletions jpos/src/main/java/org/jpos/log/AuditLogEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
@JsonSubTypes.Type(value = Shutdown.class, name = "shutdown"),
@JsonSubTypes.Type(value = DeployActivity.class, name = "deploy-activity"),
@JsonSubTypes.Type(value = ThrowableAuditLogEvent.class, name = "throwable"),
@JsonSubTypes.Type(value = License.class, name = "license")
@JsonSubTypes.Type(value = License.class, name = "license"),
@JsonSubTypes.Type(value = SysInfo.class, name = "sysinfo"),
})

public sealed interface AuditLogEvent permits Deploy, DeployActivity, ThrowableAuditLogEvent, License, LogMessage, Shutdown, Start, Stop, UnDeploy { }
public sealed interface AuditLogEvent permits Deploy, DeployActivity, License, LogMessage, Shutdown, Start, Stop, SysInfo, ThrowableAuditLogEvent, UnDeploy { }
10 changes: 10 additions & 0 deletions jpos/src/main/java/org/jpos/log/evt/KV.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.jpos.log.evt;

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;

@JacksonXmlRootElement(localName = "entry")
public record KV(
@JacksonXmlProperty(isAttribute = true, localName = "key") String key,
@JacksonXmlText String value) { }
1 change: 0 additions & 1 deletion jpos/src/main/java/org/jpos/log/evt/LogEvt.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.jpos.log.AuditLogEvent;
import java.time.Instant;
import java.util.List;
import java.util.UUID;

@JacksonXmlRootElement(localName = "log")
public record LogEvt(
Expand Down
25 changes: 25 additions & 0 deletions jpos/src/main/java/org/jpos/log/evt/ProcessOutput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.jpos.log.evt;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;

/**
* Record representing the output of a process, encapsulating the process name,
* standard output, and optionally standard error.
*
* <p>This record makes use of Jackson annotations to control the serialization
* and deserialization process. The {@code name} field is serialized as an
* attribute with the local name "name". The {@code stdout} field is serialized
* as XML text. The {@code stderr} field is included in the JSON output only if
* it is non-null.
*
* @param name the name of the process, serialized as an XML attribute with the local name "name"
* @param stdout the standard output of the process, serialized as XML text
* @param stderr the standard error of the process, included in JSON output only if non-null
*/
public record ProcessOutput(
@JacksonXmlProperty(isAttribute = true, localName = "name") String name,
@JacksonXmlText String stdout,
@JsonInclude(JsonInclude.Include.NON_NULL) String stderr)
{ }
1 change: 0 additions & 1 deletion jpos/src/main/java/org/jpos/log/evt/Start.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import org.jpos.log.AuditLogEvent;

import java.time.Instant;
import java.util.UUID;

/**
Expand Down
53 changes: 53 additions & 0 deletions jpos/src/main/java/org/jpos/log/evt/SysInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.jpos.log.evt;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import org.jpos.log.AuditLogEvent;
import java.nio.charset.Charset;
import java.time.Duration;
import java.util.List;
import java.util.UUID;

@JsonPropertyOrder({
"osName", "osVersion", "javaVersion", "javaVendor", "aes", "host", "userName", "cwd", "watch-service", "environment",
"args", "encoding", "zone-info", "processName", "freeSpace", "usableSpace", "version", "revision", "instance",
"uptime", "loadAverage", "processors", "drift", "maxMemory", "totalMemory", "freeMemory", "inUseMemory",
"gcTotalCnt", "gcTotalTime", "threadCount", "threadPeak", "nameRegistrar"
})
public record SysInfo (
@JsonProperty("os-name") String osName,
@JsonProperty("os-version") String osVersion,
@JsonProperty("java-version") String javaVersion,
@JsonProperty("java-vendor") String javaVendor,
@JsonProperty("AES") String aes,
String host,
@JsonProperty("user-name") String userName,
@JsonProperty("cwd") String cwd,
@JsonProperty("watch-service") String watchService,
String environment,
String args,
Charset encoding,
@JsonProperty("zone-info") String zoneInfo,
@JsonProperty("process-name") String processName,
@JsonProperty("free-space") String freeSpace,
@JsonProperty("usable-space") String usableSpace,
String version,
String revision,
UUID instance,
Duration uptime,
@JsonProperty("load-average") double loadAverage,
int processors,
long drift,
@JsonProperty("max-memory") long maxMemory,
@JsonProperty("total-memory") long totalMemory,
@JsonProperty("free-memory") long freeMemory,
@JsonProperty("in-use-memory") long inUseMemory,
@JsonProperty("gc-total-cnt") long gcTotalCnt,
@JsonProperty("gc-total-time") long gcTotalTime,
@JsonProperty("thread-count") int threadCount,
@JsonProperty("thread-peak") int threadPeak,
@JsonProperty("name-registrar") @JacksonXmlProperty(localName = "name-registrar") List<KV> nameRegistrarEntries,
@JsonProperty("threads") @JacksonXmlProperty(localName = "threads") List<KV> threads,
@JsonProperty("scripts") @JacksonXmlProperty(localName = "scripts") List<ProcessOutput> scripts
) implements AuditLogEvent { }
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.jpos.log.AuditLogEvent;
import org.jpos.log.LogRenderer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.jdom2.JDOMException;
import org.jpos.log.AuditLogEvent;

import org.jpos.log.LogRenderer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.jpos.log.render.markdown;

import org.jpos.log.LogRenderer;
import org.jpos.log.evt.KV;
import org.jpos.log.evt.ProcessOutput;
import org.jpos.log.evt.SysInfo;
import org.jpos.util.Profiler;

import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.RecordComponent;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.lang.StringTemplate.STR;

public final class SysInfoMarkdownRenderer implements LogRenderer<SysInfo> {

@Override
public void render(SysInfo sysinfo, PrintStream ps, String indent) {
Map<String,Object> entries = extractEntriesToMap(sysinfo);
int width = maxLength(entries);
final String fmt = STR."| %-\{width}s | %s |%n";
ps.println ("## SystemMonitor");
ps.print (row(fmt, "id", "value"));
ps.print (row(fmt, "-".repeat(width), "-----"));
entries.forEach((k, v) -> {
switch (k) {
case "nameRegistrarEntries":
case "threads":
case "scripts":
break;
default:
ps.print(
row(fmt, k, v.toString())
);
}
});
renderNameRegistrar(sysinfo.nameRegistrarEntries(), ps, fmt, width);
renderThreads(sysinfo.threads(), ps, fmt, width);
renderScripts(sysinfo.scripts(), ps);
}
public Class<?> clazz() {
return SysInfo.class;
}
public Type type() {
return Type.MARKDOWN;
}

private void renderNameRegistrar(List<KV> entries, PrintStream ps, String fmt, int width) {
ps.println ("### NameRegistrar");
ps.print (row(fmt, "id", "component"));
ps.print (row(fmt, "-".repeat(width), "---------"));
entries.forEach(kv -> {
ps.print(
row(fmt, kv.key(), kv.value()));
});
}

private void renderThreads(List<KV> entries, PrintStream ps, String fmt, int width) {
ps.println ("### Threads");
ps.print (row(fmt, "thread", "info"));
ps.print (row(fmt, "-".repeat(width), "----"));
entries.forEach(kv -> {
ps.print(
row(fmt, kv.key(), kv.value()));
});
}

private void renderScripts(List<ProcessOutput> entries, PrintStream ps) {
entries.forEach (processOutput -> {
ps.printf ("### %s%n", processOutput.name());
if (!processOutput.stdout().isEmpty()) {
ps.println ("```");
ps.println (processOutput.stdout());
ps.println ("```");
}
if (processOutput.stderr() != null) {
ps.println ("```");
ps.println (processOutput.stderr());
ps.println ("```");
}
});
}


private String row (String fmt, String c1, String c2) {
return fmt.formatted(c1, c2);
}

private int maxLength(Map<String, Object> map) {
return map.keySet().stream()
.map(String::length)
.max(Integer::compareTo).orElse(0);
}

private Map<String, Object> extractEntriesToMap(SysInfo record) {
return Stream.of(record.getClass().getRecordComponents())
.collect(Collectors.toMap(
RecordComponent::getName,
component -> {
try {
Method accessor = component.getAccessor();
return accessor.invoke(record);
} catch (IllegalAccessException | InvocationTargetException e) {
return "%s:%s".formatted(e.getClass().getSimpleName(), e.getMessage());
}
}
));
}
}
4 changes: 2 additions & 2 deletions jpos/src/main/java/org/jpos/q2/Q2.java
Original file line number Diff line number Diff line change
Expand Up @@ -673,8 +673,8 @@ public Log getLog () {
public MBeanServer getMBeanServer () {
return server;
}
public long getUptime() {
return Duration.between(startTime, Instant.now()).toMillis();
public Duration getUptime() {
return Duration.between(startTime, Instant.now());
}
public void displayVersion () {
System.out.println(getVersionString());
Expand Down
2 changes: 1 addition & 1 deletion jpos/src/main/java/org/jpos/q2/cli/UPTIME.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
@SuppressWarnings("unused")
public class UPTIME implements CLICommand {
public void exec(CLIContext ctx, String[] args) throws Exception {
ctx.println(ISOUtil.millisToString(ctx.getCLI().getQ2().getUptime()));
ctx.println(ISOUtil.millisToString(ctx.getCLI().getQ2().getUptime().toMillis()));
}
}
Loading

0 comments on commit 79251fd

Please sign in to comment.