Introduce systemd support
[gpl/argeo-slc.git] / lib / linux / org.argeo.slc.systemd / src / org / argeo / slc / systemd / dbus / ServiceStatistics.java
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();
+               }
+       }
+
+}