diff --git a/src/fr/devinsy/statoolinfos/htmlize/stuff/circle-icons/folder-mono.svg b/src/fr/devinsy/statoolinfos/htmlize/stuff/circle-icons/folder-mono.svg
new file mode 100644
index 0000000..94ed789
--- /dev/null
+++ b/src/fr/devinsy/statoolinfos/htmlize/stuff/circle-icons/folder-mono.svg
@@ -0,0 +1,72 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/fr/devinsy/statoolinfos/htmlize/stuff/circle-icons/folder.svg b/src/fr/devinsy/statoolinfos/htmlize/stuff/circle-icons/folder.svg
new file mode 100644
index 0000000..7780f63
--- /dev/null
+++ b/src/fr/devinsy/statoolinfos/htmlize/stuff/circle-icons/folder.svg
@@ -0,0 +1,89 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/fr/devinsy/statoolinfos/metrics/nextcloud/NextcloudDataAnalyzer.java b/src/fr/devinsy/statoolinfos/metrics/nextcloud/NextcloudDataAnalyzer.java
new file mode 100644
index 0000000..76a33c2
--- /dev/null
+++ b/src/fr/devinsy/statoolinfos/metrics/nextcloud/NextcloudDataAnalyzer.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 Christian Pierre MOMON
+ *
+ * This file is part of StatoolInfos, simple service statistics tool.
+ *
+ * StatoolInfos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * StatoolInfos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with StatoolInfos. If not, see .
+ */
+package fr.devinsy.statoolinfos.metrics.nextcloud;
+
+import java.io.File;
+import java.io.IOException;
+import java.time.LocalDate;
+
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import fr.devinsy.statoolinfos.core.StatoolInfosException;
+import fr.devinsy.statoolinfos.metrics.PathCounters;
+import fr.devinsy.statoolinfos.metrics.TimeMark;
+import fr.devinsy.statoolinfos.util.FilesUtils;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class LibreQRDataAnalyzer.
+ */
+public class NextcloudDataAnalyzer
+{
+ private static Logger logger = LoggerFactory.getLogger(NextcloudDataAnalyzer.class);
+
+ /**
+ * Instantiates a new http access log prober.
+ */
+ private NextcloudDataAnalyzer()
+ {
+ }
+
+ /**
+ * Probe.
+ *
+ * @param dataDirectory
+ * the data directory
+ * @return the path counters
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ * @throws StatoolInfosException
+ * the statool infos exception
+ */
+ public static PathCounters probe(final File dataDirectory) throws IOException, StatoolInfosException
+ {
+ PathCounters result;
+
+ System.out.println("Probing directory [" + dataDirectory + "]");
+
+ result = new PathCounters();
+
+ if (dataDirectory != null)
+ {
+ if ((dataDirectory.exists()) && (dataDirectory.isDirectory()))
+ {
+ LocalDate now = LocalDate.now();
+ String year = TimeMark.yearOf(now).toString();
+ String yearMonth = TimeMark.yearMonthOf(now).toString();
+ String yearWeek = TimeMark.yearWeekOf(now).toString();
+ String date = TimeMark.dayOf(now).toString();
+
+ // metrics.service.files.bytes
+ long size = FileUtils.sizeOfDirectory(dataDirectory);
+ result.set(size, "metrics.service.files.bytes", year, yearMonth, yearWeek, date);
+
+ // metrics.pastebins.count
+ long count = FilesUtils.searchByWildcard(dataDirectory.getAbsolutePath() + "/??/*").size();
+ result.set(count, "metrics.libreqr.files.count", year, yearMonth, yearWeek, date);
+ }
+ else
+ {
+ System.out.println("WARNING: LibreQR data path is not valid.");
+ }
+ }
+
+ //
+ return result;
+ }
+}
diff --git a/src/fr/devinsy/statoolinfos/metrics/nextcloud/NextcloudHttpLogAnalyzer.java b/src/fr/devinsy/statoolinfos/metrics/nextcloud/NextcloudHttpLogAnalyzer.java
new file mode 100644
index 0000000..586092a
--- /dev/null
+++ b/src/fr/devinsy/statoolinfos/metrics/nextcloud/NextcloudHttpLogAnalyzer.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2022 Christian Pierre MOMON
+ *
+ * This file is part of StatoolInfos, simple service statistics tool.
+ *
+ * StatoolInfos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * StatoolInfos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with StatoolInfos. If not, see .
+ */
+package fr.devinsy.statoolinfos.metrics.nextcloud;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import fr.devinsy.statoolinfos.core.StatoolInfosException;
+import fr.devinsy.statoolinfos.metrics.PathCounters;
+import fr.devinsy.statoolinfos.metrics.UserCounters;
+import fr.devinsy.statoolinfos.metrics.http.HttpAccessLog;
+import fr.devinsy.statoolinfos.metrics.http.HttpAccessLogIterator;
+import fr.devinsy.statoolinfos.util.Files;
+
+/**
+ * The Class NextcloudHttpLogAnalyzer.
+ */
+public class NextcloudHttpLogAnalyzer
+{
+ private static Logger logger = LoggerFactory.getLogger(NextcloudHttpLogAnalyzer.class);
+
+ public static final Pattern USE_PATTERN = Pattern.compile("GET /temp/\\w+\\.png.*");
+ public static final Pattern CREATE_PATTERN = Pattern.compile("POST / .*");
+
+ private PathCounters counters;
+ private UserCounters users;
+ private UserCounters ipv4Users;
+ private UserCounters ipv6Users;
+
+ /**
+ * Instantiates a new nextcloud http log analyzer.
+ */
+ public NextcloudHttpLogAnalyzer()
+ {
+ this.counters = new PathCounters();
+ this.users = new UserCounters();
+ this.ipv4Users = new UserCounters();
+ this.ipv6Users = new UserCounters();
+ }
+
+ /**
+ * Gets the counters.
+ *
+ * @return the counters
+ */
+ public PathCounters getCounters()
+ {
+ PathCounters result;
+
+ result = new PathCounters();
+ result.putAll(this.counters);
+
+ result.putAll(this.users.getCounters("metrics.service.users"));
+ result.putAll(this.ipv4Users.getCounters("metrics.service.users.ipv4"));
+ result.putAll(this.ipv6Users.getCounters("metrics.service.users.ipv6"));
+
+ //
+ return result;
+ }
+
+ /**
+ * Probe log.
+ *
+ * @param log
+ * the log
+ */
+ public void probeLog(final HttpAccessLog log)
+ {
+ if (log != null)
+ {
+ // General HTTP access logs.
+ String year = log.getYear();
+ String yearMonth = log.getYearMonth();
+ String yearWeek = log.getYearWeek();
+ String date = log.getDate();
+
+ // metrics.service.users
+ // metrics.service.users.ipv4
+ // metrics.service.users.ipv6
+ if ((!log.isBot()) && (USE_PATTERN.matcher(log.getRequest()).matches()))
+ {
+ String key = String.format("%s---%s", log.getIp(), log.getUserAgent());
+
+ this.users.put(key, year, yearMonth, yearWeek, date);
+
+ if (log.isIPv4())
+ {
+ this.ipv4Users.put(key, year, yearMonth, yearWeek, date);
+ }
+ else
+ {
+ this.ipv6Users.put(key, year, yearMonth, yearWeek, date);
+ }
+ }
+
+ // metrics.barcodes.count
+ if ((log.getStatus().getCode() == 200) && (CREATE_PATTERN.matcher(log.getRequest()).matches()))
+ {
+ this.counters.inc("metrics.barcodes.count", year, yearMonth, yearWeek, date);
+ }
+ }
+ }
+
+ /**
+ * Probe.
+ *
+ * @param httpAccessLogFiles
+ * the http access log files
+ * @param httpRegex
+ * the http regex
+ * @return the path counters
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ * @throws StatoolInfosException
+ * the statool infos exception
+ */
+ public static PathCounters probe(final Files httpAccessLogFiles, final String httpRegex) throws IOException, StatoolInfosException
+ {
+ PathCounters result;
+
+ NextcloudHttpLogAnalyzer analyzer = new NextcloudHttpLogAnalyzer();
+
+ HttpAccessLogIterator logs = new HttpAccessLogIterator(httpAccessLogFiles, httpRegex);
+ while (logs.hasNext())
+ {
+ analyzer.probeLog(logs.next());
+ }
+
+ result = analyzer.getCounters();
+
+ //
+ return result;
+ }
+}
diff --git a/src/fr/devinsy/statoolinfos/metrics/nextcloud/NextcloudProber.java b/src/fr/devinsy/statoolinfos/metrics/nextcloud/NextcloudProber.java
new file mode 100644
index 0000000..e4f6bf7
--- /dev/null
+++ b/src/fr/devinsy/statoolinfos/metrics/nextcloud/NextcloudProber.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 Christian Pierre MOMON
+ *
+ * This file is part of StatoolInfos, simple service statistics tool.
+ *
+ * StatoolInfos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * StatoolInfos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with StatoolInfos. If not, see .
+ */
+package fr.devinsy.statoolinfos.metrics.nextcloud;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import fr.devinsy.statoolinfos.core.StatoolInfosException;
+import fr.devinsy.statoolinfos.metrics.PathCounters;
+import fr.devinsy.statoolinfos.util.FilesUtils;
+
+/**
+ * The Class NextcloudProber.
+ */
+public class NextcloudProber
+{
+ private static Logger logger = LoggerFactory.getLogger(NextcloudProber.class);
+
+ /**
+ * Instantiates a new nextcloud prober.
+ */
+ public NextcloudProber()
+ {
+ }
+
+ /**
+ * Probe.
+ *
+ * @param httpLogs
+ * the http logs
+ * @param httpLogRegex
+ * the http log regex
+ * @param dataPath
+ * the data path
+ * @return the path counters
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ * @throws StatoolInfosException
+ * the statool infos exception
+ */
+ public static PathCounters probe(final String httpLogs, final String httpLogRegex, final File dataPath) throws IOException, StatoolInfosException
+ {
+ PathCounters result;
+
+ // metrics.service.users
+ // metrics.service.users.ipv4
+ // metrics.service.users.ipv6
+ result = NextcloudHttpLogAnalyzer.probe(FilesUtils.searchByWildcard(httpLogs), httpLogRegex);
+
+ // metrics.service.files.bytes
+ result.putAll(NextcloudDataAnalyzer.probe(dataPath));
+
+ //
+ return result;
+ }
+}
diff --git a/src/fr/devinsy/statoolinfos/metrics/xmpp/XmppDataAnalyzer.java b/src/fr/devinsy/statoolinfos/metrics/xmpp/XmppDataAnalyzer.java
new file mode 100644
index 0000000..b8b4b5e
--- /dev/null
+++ b/src/fr/devinsy/statoolinfos/metrics/xmpp/XmppDataAnalyzer.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 Christian Pierre MOMON
+ *
+ * This file is part of StatoolInfos, simple service statistics tool.
+ *
+ * StatoolInfos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * StatoolInfos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with StatoolInfos. If not, see .
+ */
+package fr.devinsy.statoolinfos.metrics.xmpp;
+
+import java.io.File;
+import java.io.IOException;
+import java.time.LocalDate;
+
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import fr.devinsy.statoolinfos.core.StatoolInfosException;
+import fr.devinsy.statoolinfos.metrics.PathCounters;
+import fr.devinsy.statoolinfos.metrics.TimeMark;
+import fr.devinsy.statoolinfos.util.FilesUtils;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class LibreQRDataAnalyzer.
+ */
+public class XmppDataAnalyzer
+{
+ private static Logger logger = LoggerFactory.getLogger(XmppDataAnalyzer.class);
+
+ /**
+ * Instantiates a new http access log prober.
+ */
+ private XmppDataAnalyzer()
+ {
+ }
+
+ /**
+ * Probe.
+ *
+ * @param dataDirectory
+ * the data directory
+ * @return the path counters
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ * @throws StatoolInfosException
+ * the statool infos exception
+ */
+ public static PathCounters probe(final File dataDirectory) throws IOException, StatoolInfosException
+ {
+ PathCounters result;
+
+ System.out.println("Probing directory [" + dataDirectory + "]");
+
+ result = new PathCounters();
+
+ if (dataDirectory != null)
+ {
+ if ((dataDirectory.exists()) && (dataDirectory.isDirectory()))
+ {
+ LocalDate now = LocalDate.now();
+ String year = TimeMark.yearOf(now).toString();
+ String yearMonth = TimeMark.yearMonthOf(now).toString();
+ String yearWeek = TimeMark.yearWeekOf(now).toString();
+ String date = TimeMark.dayOf(now).toString();
+
+ // metrics.service.files.bytes
+ long size = FileUtils.sizeOfDirectory(dataDirectory);
+ result.set(size, "metrics.service.files.bytes", year, yearMonth, yearWeek, date);
+
+ // metrics.pastebins.count
+ long count = FilesUtils.searchByWildcard(dataDirectory.getAbsolutePath() + "/??/*").size();
+ result.set(count, "metrics.libreqr.files.count", year, yearMonth, yearWeek, date);
+ }
+ else
+ {
+ System.out.println("WARNING: LibreQR data path is not valid.");
+ }
+ }
+
+ //
+ return result;
+ }
+}
diff --git a/src/fr/devinsy/statoolinfos/metrics/xmpp/XmppHttpLogAnalyzer.java b/src/fr/devinsy/statoolinfos/metrics/xmpp/XmppHttpLogAnalyzer.java
new file mode 100644
index 0000000..2391350
--- /dev/null
+++ b/src/fr/devinsy/statoolinfos/metrics/xmpp/XmppHttpLogAnalyzer.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2022 Christian Pierre MOMON
+ *
+ * This file is part of StatoolInfos, simple service statistics tool.
+ *
+ * StatoolInfos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * StatoolInfos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with StatoolInfos. If not, see .
+ */
+package fr.devinsy.statoolinfos.metrics.xmpp;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import fr.devinsy.statoolinfos.core.StatoolInfosException;
+import fr.devinsy.statoolinfos.metrics.PathCounters;
+import fr.devinsy.statoolinfos.metrics.UserCounters;
+import fr.devinsy.statoolinfos.metrics.http.HttpAccessLog;
+import fr.devinsy.statoolinfos.metrics.http.HttpAccessLogIterator;
+import fr.devinsy.statoolinfos.util.Files;
+
+/**
+ * The Class LibreQRHttpLogAnalyzer.
+ */
+public class XmppHttpLogAnalyzer
+{
+ private static Logger logger = LoggerFactory.getLogger(XmppHttpLogAnalyzer.class);
+
+ public static final Pattern USE_PATTERN = Pattern.compile("GET /temp/\\w+\\.png.*");
+ public static final Pattern CREATE_PATTERN = Pattern.compile("POST / .*");
+
+ private PathCounters counters;
+ private UserCounters users;
+ private UserCounters ipv4Users;
+ private UserCounters ipv6Users;
+
+ /**
+ * Instantiates a new http access log prober.
+ */
+ public XmppHttpLogAnalyzer()
+ {
+ this.counters = new PathCounters();
+ this.users = new UserCounters();
+ this.ipv4Users = new UserCounters();
+ this.ipv6Users = new UserCounters();
+ }
+
+ /**
+ * Gets the counters.
+ *
+ * @return the counters
+ */
+ public PathCounters getCounters()
+ {
+ PathCounters result;
+
+ result = new PathCounters();
+ result.putAll(this.counters);
+
+ result.putAll(this.users.getCounters("metrics.service.users"));
+ result.putAll(this.ipv4Users.getCounters("metrics.service.users.ipv4"));
+ result.putAll(this.ipv6Users.getCounters("metrics.service.users.ipv6"));
+
+ //
+ return result;
+ }
+
+ /**
+ * Probe log.
+ *
+ * @param log
+ * the log
+ */
+ public void probeLog(final HttpAccessLog log)
+ {
+ if (log != null)
+ {
+ // General HTTP access logs.
+ String year = log.getYear();
+ String yearMonth = log.getYearMonth();
+ String yearWeek = log.getYearWeek();
+ String date = log.getDate();
+
+ // metrics.service.users
+ // metrics.service.users.ipv4
+ // metrics.service.users.ipv6
+ if ((!log.isBot()) && (USE_PATTERN.matcher(log.getRequest()).matches()))
+ {
+ String key = String.format("%s---%s", log.getIp(), log.getUserAgent());
+
+ this.users.put(key, year, yearMonth, yearWeek, date);
+
+ if (log.isIPv4())
+ {
+ this.ipv4Users.put(key, year, yearMonth, yearWeek, date);
+ }
+ else
+ {
+ this.ipv6Users.put(key, year, yearMonth, yearWeek, date);
+ }
+ }
+
+ // metrics.barcodes.count
+ if ((log.getStatus().getCode() == 200) && (CREATE_PATTERN.matcher(log.getRequest()).matches()))
+ {
+ this.counters.inc("metrics.barcodes.count", year, yearMonth, yearWeek, date);
+ }
+ }
+ }
+
+ /**
+ * Probe.
+ *
+ * @param httpAccessLogFiles
+ * the http access log files
+ * @param httpRegex
+ * the http regex
+ * @return the path counters
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ * @throws StatoolInfosException
+ * the statool infos exception
+ */
+ public static PathCounters probe(final Files httpAccessLogFiles, final String httpRegex) throws IOException, StatoolInfosException
+ {
+ PathCounters result;
+
+ XmppHttpLogAnalyzer analyzer = new XmppHttpLogAnalyzer();
+
+ HttpAccessLogIterator logs = new HttpAccessLogIterator(httpAccessLogFiles, httpRegex);
+ while (logs.hasNext())
+ {
+ analyzer.probeLog(logs.next());
+ }
+
+ result = analyzer.getCounters();
+
+ //
+ return result;
+ }
+}
diff --git a/src/fr/devinsy/statoolinfos/metrics/xmpp/XmppProber.java b/src/fr/devinsy/statoolinfos/metrics/xmpp/XmppProber.java
new file mode 100644
index 0000000..f6f2251
--- /dev/null
+++ b/src/fr/devinsy/statoolinfos/metrics/xmpp/XmppProber.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 Christian Pierre MOMON
+ *
+ * This file is part of StatoolInfos, simple service statistics tool.
+ *
+ * StatoolInfos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * StatoolInfos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with StatoolInfos. If not, see .
+ */
+package fr.devinsy.statoolinfos.metrics.xmpp;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import fr.devinsy.statoolinfos.core.StatoolInfosException;
+import fr.devinsy.statoolinfos.metrics.PathCounters;
+import fr.devinsy.statoolinfos.util.FilesUtils;
+
+/**
+ * The Class XmppProber.
+ */
+public class XmppProber
+{
+ private static Logger logger = LoggerFactory.getLogger(XmppProber.class);
+
+ /**
+ * Instantiates a new xmpp prober.
+ */
+ public XmppProber()
+ {
+ }
+
+ /**
+ * Probe.
+ *
+ * @param httpLogs
+ * the http logs
+ * @param httpLogRegex
+ * the http log regex
+ * @param dataPath
+ * the data path
+ * @return the path counters
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ * @throws StatoolInfosException
+ * the statool infos exception
+ */
+ public static PathCounters probe(final String httpLogs, final String httpLogRegex, final File dataPath) throws IOException, StatoolInfosException
+ {
+ PathCounters result;
+
+ // metrics.service.users
+ // metrics.service.users.ipv4
+ // metrics.service.users.ipv6
+ result = XmppHttpLogAnalyzer.probe(FilesUtils.searchByWildcard(httpLogs), httpLogRegex);
+
+ // metrics.service.files.bytes
+ result.putAll(XmppDataAnalyzer.probe(dataPath));
+
+ //
+ return result;
+ }
+}