From: Mathieu Date: Wed, 30 Nov 2022 05:42:44 +0000 (+0100) Subject: Introduce systemd support X-Git-Tag: v2.3.7~3 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=3ecf8cf48d400f3f7c8389b435d473bf9c374919;p=gpl%2Fargeo-slc.git Introduce systemd support --- diff --git a/Makefile b/Makefile index 125c81eb3..4c8c0f9d6 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,12 @@ A2_CATEGORY = org.argeo.slc BUNDLES = \ org.argeo.slc.api \ -org.argeo.slc.factory \ org.argeo.slc.runtime \ org.argeo.slc.cms \ org.argeo.slc.repo \ org.argeo.slc.rpmfactory \ org.argeo.slc.jcr \ +lib/linux/org.argeo.slc.systemd \ swt/org.argeo.tool.swt \ swt/org.argeo.tool.devops.e4 \ swt/rap/org.argeo.tool.rap.cli \ diff --git a/lib/linux/org.argeo.slc.systemd/.classpath b/lib/linux/org.argeo.slc.systemd/.classpath new file mode 100644 index 000000000..81fe078c2 --- /dev/null +++ b/lib/linux/org.argeo.slc.systemd/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/linux/org.argeo.slc.systemd/.project b/lib/linux/org.argeo.slc.systemd/.project new file mode 100644 index 000000000..1590750e3 --- /dev/null +++ b/lib/linux/org.argeo.slc.systemd/.project @@ -0,0 +1,33 @@ + + + org.argeo.slc.systemd + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/lib/linux/org.argeo.slc.systemd/OSGI-INF/systemdServiceStatistics.xml b/lib/linux/org.argeo.slc.systemd/OSGI-INF/systemdServiceStatistics.xml new file mode 100644 index 000000000..c689af18e --- /dev/null +++ b/lib/linux/org.argeo.slc.systemd/OSGI-INF/systemdServiceStatistics.xml @@ -0,0 +1,4 @@ + + + + diff --git a/lib/linux/org.argeo.slc.systemd/bnd.bnd b/lib/linux/org.argeo.slc.systemd/bnd.bnd new file mode 100644 index 000000000..0b58d79f7 --- /dev/null +++ b/lib/linux/org.argeo.slc.systemd/bnd.bnd @@ -0,0 +1,6 @@ +Service-Component: OSGI-INF/systemdServiceStatistics.xml + + +Import-Package:\ +de.thjom.java.systemd.features,\ +* \ No newline at end of file diff --git a/lib/linux/org.argeo.slc.systemd/build.properties b/lib/linux/org.argeo.slc.systemd/build.properties new file mode 100644 index 000000000..cb0d657cb --- /dev/null +++ b/lib/linux/org.argeo.slc.systemd/build.properties @@ -0,0 +1,7 @@ +bin.includes = META-INF/,\ + .,\ + OSGI-INF/systemdServiceStatistics.xml +additional.bundles = org.argeo.ext.slf4j,\ + org.slf4j.api +source.. = src/ +output.. = bin/ diff --git a/lib/linux/org.argeo.slc.systemd/src/org/argeo/slc/systemd/dbus/PlainDBusTest.java b/lib/linux/org.argeo.slc.systemd/src/org/argeo/slc/systemd/dbus/PlainDBusTest.java new file mode 100644 index 000000000..b43a033ee --- /dev/null +++ b/lib/linux/org.argeo.slc.systemd/src/org/argeo/slc/systemd/dbus/PlainDBusTest.java @@ -0,0 +1,41 @@ +package org.argeo.slc.systemd.dbus; + +import java.util.Map; + +import org.freedesktop.dbus.connections.impl.DBusConnection; +import org.freedesktop.dbus.interfaces.DBusInterface; +import org.freedesktop.dbus.interfaces.Introspectable; +import org.freedesktop.dbus.interfaces.Properties; +import org.freedesktop.dbus.types.Variant; + +public class PlainDBusTest { + final static String SYSTEMD_SERVICE = "org.freedesktop.systemd1.Service"; + + public static void main(String[] args) throws Exception { +// try (DBusConnection dBusConnection = DBusConnectionBuilder.forSystemBus().build()) { + + try (DBusConnection dBusConnection = DBusConnection.getConnection(DBusConnection.DBusBusType.SYSTEM)) { + + String source = "org.freedesktop.systemd1"; + String objectPath = "/org/freedesktop/systemd1/unit/ipsec_2eservice"; +// String objectPath = "/org/freedesktop/systemd1"; + DBusInterface object = dBusConnection.getExportedObject(source, objectPath); + System.out.println(object); +// +// Introspectable introspectable = dBusConnection.getExportedObject(source, objectPath, Introspectable.class); +// System.out.println(introspectable.Introspect()); +// + Properties props = dBusConnection.getExportedObject(source, objectPath, Properties.class); +// System.out.println(props); + + System.out.println(props.Get(SYSTEMD_SERVICE, "CPUUsageNSec").toString()); + + Map> values = props.GetAll(SYSTEMD_SERVICE); + for (String key : values.keySet()) { + Variant value = values.get(key); + System.out.println(key + "=" + value.getValue() + " (" + value.getType() + ") " + value.getSig()); + } + } + } + +} diff --git a/lib/linux/org.argeo.slc.systemd/src/org/argeo/slc/systemd/dbus/ServiceStatistics.java b/lib/linux/org.argeo.slc.systemd/src/org/argeo/slc/systemd/dbus/ServiceStatistics.java new file mode 100644 index 000000000..d19f55386 --- /dev/null +++ b/lib/linux/org.argeo.slc.systemd/src/org/argeo/slc/systemd/dbus/ServiceStatistics.java @@ -0,0 +1,132 @@ +package org.argeo.slc.systemd.dbus; + +import static java.lang.System.Logger.Level.DEBUG; +import static java.lang.System.Logger.Level.INFO; +import static java.lang.System.Logger.Level.WARNING; + +import java.io.IOException; +import java.io.Writer; +import java.lang.System.Logger; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; + +import org.argeo.cms.util.CsvWriter; +import org.freedesktop.dbus.exceptions.DBusException; + +import de.thjom.java.systemd.Manager; +import de.thjom.java.systemd.Service; +import de.thjom.java.systemd.Systemd; +import de.thjom.java.systemd.types.UnitType; + +/** Gathers statistics about the runnign process, if it is a systemd unit. */ +public class ServiceStatistics { + private final static Logger logger = System.getLogger(ServiceStatistics.class.getName()); + + private Manager manager; + + private String unitName; + private Service service; + + private long frequency = 60 * 1000; + + public void start() { + final long pid = ProcessHandle.current().pid(); + try { + manager = Systemd.get().getManager(); + // find own service + for (UnitType unitType : manager.listUnits()) { + if (unitType.isService()) { + Service s = manager.getService(unitType.getUnitName()); + if (s.getMainPID() == pid) { + service = s; + unitName = unitType.getUnitName(); + logger.log(INFO, "Systemd service found for pid " + pid + ": " + unitName); + } + } + } + + } catch (DBusException e) { + logger.log(WARNING, "Cannot connect to systemd", e); + } + + if (service == null) { + logger.log(DEBUG, () -> "No systemd service found for pid " + pid + ", disconnecting from DBus..."); + manager = null; + Systemd.disconnect(); + } else { + // start collecting + collectStatistics(); + } + } + + public void stop() { + if (manager != null) { + Systemd.disconnect(); + manager = null; + notifyAll(); + } + } + + protected void collectStatistics() { + // standard systemd property + String logsDirectory = System.getenv("LOGS_DIRECTORY"); + if (logsDirectory == null) { + logsDirectory = System.getProperty("user.dir"); + } + // MainPID,CPUUsageNSec,MemoryCurrent,IPIngressBytes,IPEgressBytes,IOReadBytes,IOWriteBytes,TasksCurrent + Path basePath = Paths.get(logsDirectory); + + logger.log(DEBUG, () -> "Writing statistics for " + unitName + " to " + basePath); + try { + while (manager != null) { + String dateSuffix = Instant.now().atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE); + + Path csvPath = basePath.resolve("statistics-" + unitName + "-" + dateSuffix + ".csv"); + boolean writeHeader = !Files.exists(csvPath); + try (Writer writer = Files.newBufferedWriter(csvPath, StandardCharsets.UTF_8, + StandardOpenOption.APPEND)) { + CsvWriter csvWriter = new CsvWriter(writer); + + if (writeHeader)// header + csvWriter.writeLine("CurrentTimeMillis", "CPUUsageNSec", "MemoryCurrent", "IPIngressBytes", + "IPEgressBytes", "IOReadBytes", "IOWriteBytes", "TasksCurrent"); + + // TODO better synchronise with stop + csvWriter.writeLine(System.currentTimeMillis(), service.getCPUUsageNSec(), + service.getMemoryCurrent(), service.getIPIngressBytes(), service.getIPEgressBytes(), + service.getIOReadBytes(), service.getIOWriteBytes(), service.getTasksCurrent()); + } + Thread.sleep(frequency); + } + } catch (IOException e) { + throw new IllegalStateException("Cannot collect statistics", e); + } catch (InterruptedException e) { + logger.log(WARNING, "Statistics collection interrupted for " + unitName); + } + + } + + public static void main(String[] args) throws Exception { + try { + Systemd systemd = Systemd.get(); + Service service = systemd.getManager().getService("ipsec.service"); + System.out.println(service.getCPUUsageNSec()); + + for (UnitType unitType : systemd.getManager().listUnits()) { + if (unitType.isService()) { + System.out.println(unitType.getUnitName()); + } + } + + } finally { + Systemd.disconnect(); + } + } + +}