Introduce systemd support
authorMathieu <mbaudier@argeo.org>
Wed, 30 Nov 2022 05:42:44 +0000 (06:42 +0100)
committerMathieu <mbaudier@argeo.org>
Wed, 30 Nov 2022 05:42:44 +0000 (06:42 +0100)
Makefile
lib/linux/org.argeo.slc.systemd/.classpath [new file with mode: 0644]
lib/linux/org.argeo.slc.systemd/.project [new file with mode: 0644]
lib/linux/org.argeo.slc.systemd/OSGI-INF/systemdServiceStatistics.xml [new file with mode: 0644]
lib/linux/org.argeo.slc.systemd/bnd.bnd [new file with mode: 0644]
lib/linux/org.argeo.slc.systemd/build.properties [new file with mode: 0644]
lib/linux/org.argeo.slc.systemd/src/org/argeo/slc/systemd/dbus/PlainDBusTest.java [new file with mode: 0644]
lib/linux/org.argeo.slc.systemd/src/org/argeo/slc/systemd/dbus/ServiceStatistics.java [new file with mode: 0644]

index 125c81eb3097315d020decdf6d7593c6e12d9bf3..4c8c0f9d63a8270f1b9a724b8ba1dfe139ec1cc1 100644 (file)
--- 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 (file)
index 0000000..81fe078
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/lib/linux/org.argeo.slc.systemd/.project b/lib/linux/org.argeo.slc.systemd/.project
new file mode 100644 (file)
index 0000000..1590750
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.slc.systemd</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ds.core.builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
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 (file)
index 0000000..c689af1
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" immediate="true" name="org.argeo.slc.systemd.serviceStatistics">
+   <implementation class="org.argeo.slc.systemd.dbus.ServiceStatistics"/>
+</scr:component>
diff --git a/lib/linux/org.argeo.slc.systemd/bnd.bnd b/lib/linux/org.argeo.slc.systemd/bnd.bnd
new file mode 100644 (file)
index 0000000..0b58d79
--- /dev/null
@@ -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 (file)
index 0000000..cb0d657
--- /dev/null
@@ -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 (file)
index 0000000..b43a033
--- /dev/null
@@ -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<String, Variant<?>> 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 (file)
index 0000000..d19f553
--- /dev/null
@@ -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();
+               }
+       }
+
+}