From 5bd6e2c60023ea8b78ea27d91d639480c3f9ca6a Mon Sep 17 00:00:00 2001 From: "Christian P. MOMON" Date: Tue, 15 Feb 2022 01:45:39 +0100 Subject: [PATCH] Improved probing of Gitea, PrivateBin and LibreQR. Refactoring. --- .classpath | 1 + lib/json-simple-1.1.1-sources.jar | Bin 0 -> 17445 bytes lib/json-simple-1.1.1.jar | Bin 0 -> 23931 bytes .../devinsy/statoolinfos/metrics/Prober.java | 9 +- .../statoolinfos/metrics/gitea/GiteaAPI.java | 369 ++++++++++++++++++ .../metrics/gitea/GiteaProber.java | 300 ++++++++++++++ .../metrics/libreqr/LibreQRProber.java | 5 +- .../privatebin/PrivatebinDataAnalyzer.java | 91 ----- .../privatebin/PrivatebinHttpLogAnalyzer.java | 215 ---------- .../metrics/privatebin/PrivatebinProber.java | 94 ++++- .../metrics/util/DatabaseProber.java | 83 ++++ .../metrics/util/DatafilesProber.java | 2 +- 12 files changed, 850 insertions(+), 319 deletions(-) create mode 100644 lib/json-simple-1.1.1-sources.jar create mode 100644 lib/json-simple-1.1.1.jar create mode 100644 src/fr/devinsy/statoolinfos/metrics/gitea/GiteaAPI.java create mode 100644 src/fr/devinsy/statoolinfos/metrics/gitea/GiteaProber.java delete mode 100644 src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinDataAnalyzer.java delete mode 100644 src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinHttpLogAnalyzer.java create mode 100644 src/fr/devinsy/statoolinfos/metrics/util/DatabaseProber.java diff --git a/.classpath b/.classpath index 4cb3719..5f9bb89 100644 --- a/.classpath +++ b/.classpath @@ -28,5 +28,6 @@ + diff --git a/lib/json-simple-1.1.1-sources.jar b/lib/json-simple-1.1.1-sources.jar new file mode 100644 index 0000000000000000000000000000000000000000..165e6f94b284f841902715587b0e8e3b11d42fa6 GIT binary patch literal 17445 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 + * + * 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.gitea; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.Charset; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The Class GiteaAPI. + */ +public class GiteaAPI +{ + private static Logger logger = LoggerFactory.getLogger(GiteaAPI.class); + + private String url; + private String token; + private JSONArray users; + private JSONArray organizations; + private JSONArray repositories; + + /** + * Instantiates a new gitea API. + */ + public GiteaAPI(final String url, final String token) throws IOException, ParseException + { + this.url = StringUtils.removeEnd(url, "/"); + this.token = token; + + // + String json = IOUtils.toString(new URL(url + "/api/v1/admin/users?limit=100000&token=" + token), Charset.defaultCharset()); + this.users = (JSONArray) (new JSONParser().parse(json)); + + // + json = IOUtils.toString(new URL(url + "/api/v1/admin/orgs?limit=100000&token=" + token), Charset.defaultCharset()); + this.organizations = (JSONArray) (new JSONParser().parse(json)); + + // + json = IOUtils.toString(new URL(url + "/api/v1/repos/search?limit=100000&token=" + token), Charset.defaultCharset()); + System.out.println(json); + this.repositories = (JSONArray) ((JSONObject) (new JSONParser().parse(json))).get("data"); + } + + /** + * Gets the active user count. + * + * @return the active user count + */ + public long getActiveUserCount() + { + long result; + + result = 0; + LocalDateTime limit = LocalDateTime.now().minusDays(31); + for (Object user : this.users) + { + String lastLogin = getJSONString(user, "last_login"); + + if (!StringUtils.isBlank(lastLogin)) + { + try + { + LocalDateTime date = LocalDateTime.parse(lastLogin, DateTimeFormatter.ISO_DATE_TIME); + if (date.isAfter(limit)) + { + result += 1; + } + } + catch (DateTimeParseException exception) + { + System.out.println("OUPS"); + } + } + } + + // + return result; + } + + /** + * Gets the fork repository count. + * + * @return the fork repository count + */ + public long getForkRepositoryCount() + { + long result; + + result = 0; + for (Object repository : this.repositories) + { + if (getJSONBoolean(repository, "fork")) + { + result += 1; + } + } + + // + return result; + } + + /** + * Gets the mirror repository count. + * + * @return the mirror repository count + */ + public long getMirrorRepositoryCount() + { + long result; + + result = 0; + for (Object repository : this.repositories) + { + if (getJSONBoolean(repository, "mirror")) + { + result += 1; + } + } + + // + return result; + } + + /** + * Gets the organization count. + * + * @return the organization count + */ + public long getOrganizationCount() + { + long result; + + result = this.organizations.size(); + + // + return result; + } + + /** + * Gets the private organization count. + * + * @return the private organization count + */ + public long getPrivateOrganizationCount() + { + long result; + + result = 0; + for (Object organization : this.organizations) + { + String visibility = getJSONString(organization, "visibility"); + + if (StringUtils.equals(visibility, "private")) + { + result += 1; + } + } + + // + return result; + } + + /** + * Gets the private repository count. + * + * @return the private repository count + */ + public long getPrivateRepositoryCount() + { + long result; + + result = 0; + for (Object repository : this.repositories) + { + if (getJSONBoolean(repository, "private")) + { + result += 1; + } + } + + // + return result; + } + + /** + * Gets the public organization count. + * + * @return the public organization count + */ + public long getPublicOrganizationCount() + { + long result; + + result = 0; + for (Object organization : this.organizations) + { + String visibility = getJSONString(organization, "visibility"); + + if (StringUtils.equals(visibility, "public")) + { + result += 1; + } + } + + // + return result; + } + + /** + * Gets the public repository count. + * + * @return the public repository count + */ + public long getPublicRepositoryCount() + { + long result; + + result = 0; + for (Object repository : this.repositories) + { + if (!getJSONBoolean(repository, "private")) + { + result += 1; + } + } + + // + return result; + } + + /** + * Gets the repository count. + * + * @return the repository count + */ + public long getRepositoryCount() + { + long result; + + result = this.repositories.size(); + + // + return result; + } + + /** + * Gets the user count. + * + * @return the user count + */ + public long getUserCount() + { + long result; + + result = this.users.size(); + + // + return result; + } + + /** + * Gets the boolean. + * + * @param object + * the object + * @param key + * the key + * @return the boolean + */ + private static boolean getJSONBoolean(final Object object, final String key) + { + Boolean result; + + Object value = ((JSONObject) object).get(key); + if (value == null) + { + result = false; + } + else + { + result = (Boolean) value; + } + + // + return result; + } + + /** + * Gets the long. + * + * @param object + * the object + * @param key + * the key + * @return the long + */ + public static long getJSONLong(final Object object, final String key) + { + long result; + + Object value = ((JSONObject) object).get(key); + if (value == null) + { + result = 0; + } + else + { + result = (Long) value; + } + + // + return result; + } + + /** + * Gets the as string. + * + * @param object + * the object + * @param key + * the key + * @return the as string + */ + public static String getJSONString(final Object object, final String key) + { + String result; + + Object value = ((JSONObject) object).get(key); + if (value == null) + { + result = ""; + } + else + { + result = (String) value; + } + + // + return result; + } +} diff --git a/src/fr/devinsy/statoolinfos/metrics/gitea/GiteaProber.java b/src/fr/devinsy/statoolinfos/metrics/gitea/GiteaProber.java new file mode 100644 index 0000000..8eba63b --- /dev/null +++ b/src/fr/devinsy/statoolinfos/metrics/gitea/GiteaProber.java @@ -0,0 +1,300 @@ +/* + * 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.gitea; + +import java.io.File; +import java.io.IOException; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.json.simple.parser.ParseException; +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.HttpAccessLogs; +import fr.devinsy.statoolinfos.metrics.util.DatabaseProber; +import fr.devinsy.statoolinfos.metrics.util.DatafilesProber; +import fr.devinsy.statoolinfos.util.Files; +import fr.devinsy.strings.StringList; + +/** + * The Class GiteaProber. + */ +public class GiteaProber +{ + private static Logger logger = LoggerFactory.getLogger(GiteaProber.class); + + /** + * Instantiates a new nextcloud prober. + */ + public GiteaProber() + { + } + + /** + * 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 Files httpLogs, final String httpLogRegex, final String apiURL, final String apiToken, final File dataPath) throws IOException, StatoolInfosException + { + PathCounters result; + + // metrics.service.users + // metrics.service.users.ipv4 + // metrics.service.users.ipv6 + result = probeHttpAccessLog(httpLogs, httpLogRegex); + + // metrics.service.database.bytes + result.putAll(DatabaseProber.probe(null)); + + // metrics.service.files.bytes + // metrics.service.files.count + result.putAll(DatafilesProber.probe(dataPath)); + + if (!StringUtils.isBlank(apiURL) && (!StringUtils.isBlank(apiToken))) + { + try + { + GiteaAPI gitea = new GiteaAPI("https://forge.devinsy.fr/", "6fd97c63c25cabf67ff90731ee79ab4568be89b0"); + + // metrics.service.accounts + // metrics.service.accounts.active + result.set(gitea.getUserCount(), "metrics.service.accounts"); + result.set(gitea.getActiveUserCount(), "metrics.service.accounts.active"); + + // metrics.forge.groups.* = + // metrics.forge.groups.private.* = + // metrics.forge.groups.public.* = + result.set(gitea.getOrganizationCount(), "metrics.forge.groups"); + result.set(gitea.getPublicOrganizationCount(), "metrics.forge.groups.public"); + result.set(gitea.getPrivateOrganizationCount(), "metrics.forge.groups.private"); + + // metrics.forge.projects.* = + // metrics.forge.repositories.* = + // metrics.forge.repositories.private.* = + // metrics.forge.repositories.public.* = + result.set(gitea.getRepositoryCount(), "metrics.forge.projects"); + result.set(gitea.getRepositoryCount(), "metrics.forge.repositories"); + result.set(gitea.getPublicRepositoryCount(), "metrics.forge.repositories.public"); + result.set(gitea.getPrivateRepositoryCount(), "metrics.forge.repositories.private"); + result.set(gitea.getForkRepositoryCount(), "metrics.forge.repositories.forks"); + result.set(gitea.getMirrorRepositoryCount(), "metrics.forge.repositories.mirrors"); + } + catch (IOException | ParseException exception) + { + exception.printStackTrace(); + } + } + + // /////////////////////////////////////// + + // # [Metrics spécifiques aux services de forges logicielles]. + // + // + // metrics.forge.commits.* = + // metrics.forge.mergerequests.* = + // metrics.forge.committers.* = + // metrics.forge.mergerequesters.* = + // metrics.forge.files.* = + + // + return result; + } + + /** + * Probe http access log. + * + * @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 + */ + private static PathCounters probeHttpAccessLog(final Files httpAccessLogFiles, final String httpRegex) throws IOException, StatoolInfosException + { + PathCounters result; + + result = new PathCounters(); + + // metrics.service.users + // metrics.service.users.ipv4 + // metrics.service.users.ipv6 + UserCounters users = new UserCounters(); + UserCounters ipv4Users = new UserCounters(); + UserCounters ipv6Users = new UserCounters(); + + StringList regexList = new StringList(); + + /* + GET /admin + GET /admin/auths + GET /admin/config + GET /admin/emails + GET /admin/hooks + GET /admin/monitor + GET /admin/notices + GET /admin/orgs + GET /admin/repos + GET /admin/users + */ + regexList.add("GET /admin(/auths|/config|/emails|/hooks|/monitor|/notices|/orgs|/repos|/users)? .*"); + + /* + GET /cpm + GET /devinsy + */ + + /* + GET /devinsy/bacasable + GET /devinsy/bacasable/activity + GET /devinsy/bacasable/commits/branch/master + GET /devinsy/bacasable/compare/master...master + GET /devinsy/bacasable/graph + GET /devinsy/bacasable/issues + GET /devinsy/bacasable/issues/new?project=1 + GET /devinsy/bacasable/projects + GET /devinsy/bacasable/projects/1 + GET /devinsy/bacasable/projects/1/edit + GET /devinsy/bacasable/pulls + GET /devinsy/bacasable/pulls/1 + GET /devinsy/bacasable/releases + GET /devinsy/bacasable/releases/tag/0.5.0 + GET /devinsy/bacasable/tags + GET /devinsy/bacasable/wiki + GET /devinsy/bacasable/wiki/Home + */ + regexList.add("GET /\\S+/\\S+(/activity|/commits/branch/master|/compare/\\S+|/graph|/issues|/projects(/\\d+)|/pulls(/\\d+)|/releases(/tag/\\S+|/tags|/wiki|/wiki/\\S+)) .*"); + + /* + GET /devinsy/bacasable/settings + GET /devinsy/bacasable/settings/branches + GET /devinsy/bacasable/settings/collaboration + GET /devinsy/bacasable/settings/hooks + GET /devinsy/bacasable/settings/keys + GET /devinsy/bacasable/settings/lfs + GET /devinsy/bacasable/settings/lfs/locks + GET /devinsy/bacasable/settings/lfs/pointers + GET /devinsy/bacasable/settings/tags + */ + regexList.add("GET /\\S+/\\S+/settings(/branches|/collaboration|/hooks|/keys|/lfs|/lfs/locks|/lfs/pointers|/tags)? .*"); + + /* + GET /org/create + GET /org/devinsy/members + GET /org/devinsy/settings + GET /org/devinsy/teams + GET /org/devinsy/teams/new + */ + regexList.add("GET /org/(create|/\\S+/members|/\\S+/settings|/\\S+/teams|/\\S+/teams/new) .*"); + + /* + GET /explore/organizations + GET /explore/repos + GET /explore/users + */ + regexList.add("GET (/explore/organizations|/explore/repos|/explore/users) .*"); + + /* + GET /issues + GET /milestones + GET /pulls + */ + regexList.add("GET /(issues|milestones|pulls) .*"); + + /* + GET /repo/create + GET /repo/fork/7 + GET /repo/migrate + */ + regexList.add("GET /repo/(create|fork/\\d+|migrate) .*"); + + /* + GET /user/settings + GET /user/settings/account + GET /user/settings/appearance + GET /user/settings/applications + GET /user/settings/keys + GET /user/settings/organization + GET /user/settings/repos + GET /user/settings/security + */ + regexList.add("GET /user/settings(/account|/appearance|/applications|/keys|/organizations|/repos|/security)? .*"); + + String regex = regexList.toString("(", "|", ")"); + + Pattern USE_PATTERN = Pattern.compile(regex); + + // + for (HttpAccessLog log : new HttpAccessLogs(httpAccessLogFiles, httpRegex)) + { + // 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())) + { + System.out.println(log.toStringLog()); + String key = String.format("%s---%s", log.getIp(), log.getUserAgent()); + + users.put(key, year, yearMonth, yearWeek, date); + + if (log.isIPv4()) + { + ipv4Users.put(key, year, yearMonth, yearWeek, date); + } + else + { + ipv6Users.put(key, year, yearMonth, yearWeek, date); + } + } + } + + // + result.putAll(users.getCounters("metrics.service.users")); + result.putAll(ipv4Users.getCounters("metrics.service.users.ipv4")); + result.putAll(ipv6Users.getCounters("metrics.service.users.ipv6")); + + // + return result; + } +} diff --git a/src/fr/devinsy/statoolinfos/metrics/libreqr/LibreQRProber.java b/src/fr/devinsy/statoolinfos/metrics/libreqr/LibreQRProber.java index 0d8d954..76dc661 100644 --- a/src/fr/devinsy/statoolinfos/metrics/libreqr/LibreQRProber.java +++ b/src/fr/devinsy/statoolinfos/metrics/libreqr/LibreQRProber.java @@ -32,7 +32,6 @@ import fr.devinsy.statoolinfos.metrics.http.HttpAccessLog; import fr.devinsy.statoolinfos.metrics.http.HttpAccessLogs; import fr.devinsy.statoolinfos.metrics.util.DatafilesProber; import fr.devinsy.statoolinfos.util.Files; -import fr.devinsy.statoolinfos.util.FilesUtils; /** * The Class LibreQRProber. @@ -63,7 +62,7 @@ public class LibreQRProber * @throws StatoolInfosException * the statool infos exception */ - public static PathCounters probe(final String httpLogs, final String httpLogRegex, final File dataPath) throws IOException, StatoolInfosException + public static PathCounters probe(final Files httpLogs, final String httpLogRegex, final File dataPath) throws IOException, StatoolInfosException { PathCounters result; @@ -72,7 +71,7 @@ public class LibreQRProber // metrics.service.users.ipv6 // metrics.barcodes.count // metrics.libreqr.barcodes.downloads - result = probeHttpAccessLog(FilesUtils.searchByWildcard(httpLogs), httpLogRegex); + result = probeHttpAccessLog(httpLogs, httpLogRegex); // metrics.service.files.bytes, metrics.libreqr.cache.bytes // metrics.service.files.count, metrics.libreqr.cache.count diff --git a/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinDataAnalyzer.java b/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinDataAnalyzer.java deleted file mode 100644 index 65710cb..0000000 --- a/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinDataAnalyzer.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2021 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.privatebin; - -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; - -/** - * The Class PrivatebinDataAnalyzer. - */ -public class PrivatebinDataAnalyzer -{ - private static Logger logger = LoggerFactory.getLogger(PrivatebinDataAnalyzer.class); - - /** - * Instantiates a new http access log prober. - */ - private PrivatebinDataAnalyzer() - { - } - - /** - * 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.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.pastebins.count", year, yearMonth, yearWeek, date); - } - else - { - System.out.println("WARNING: Privatebin data path is not valid."); - } - - // - return result; - } -} diff --git a/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinHttpLogAnalyzer.java b/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinHttpLogAnalyzer.java deleted file mode 100644 index 33e7df6..0000000 --- a/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinHttpLogAnalyzer.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2021-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.privatebin; - -import java.io.File; -import java.io.IOException; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; -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.HttpAccessLogParser; -import fr.devinsy.statoolinfos.util.FilesUtils; -import fr.devinsy.statoolinfos.util.LineIterator; - -/** - * The Class HttpAccessLogProber. - */ -public class PrivatebinHttpLogAnalyzer -{ - private static Logger logger = LoggerFactory.getLogger(PrivatebinHttpLogAnalyzer.class); - - private PathCounters counters; - private UserCounters users; - private UserCounters ipv4Users; - private UserCounters ipv6Users; - - /** - * Instantiates a new http access log prober. - */ - public PrivatebinHttpLogAnalyzer() - { - 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. - * - * @param file - * the file - * @throws IOException - * Signals that an I/O exception has occurred. - * @throws StatoolInfosException - * the statool infos exception - */ - public void probe(final File file, final String patternRegex) throws IOException - { - System.out.println("Probing file [" + file.getAbsolutePath() + "]"); - - // - Pattern pattern; - if (patternRegex == null) - { - pattern = HttpAccessLogParser.COMBINED_PATTERN; - } - else - { - pattern = Pattern.compile(patternRegex); - } - - // - LineIterator iterator = new LineIterator(file); - while (iterator.hasNext()) - { - String line = iterator.next(); - - try - { - HttpAccessLog log = HttpAccessLogParser.parseLog(line, pattern); - if (log == null) - { - logger.warn("LINE IS NOT MATCHING [{}]", line); - } - else - { - probeLog(log); - } - } - catch (Exception exception) - { - logger.warn("Error parsing line [{}][{}]", line, exception.getMessage()); - exception.printStackTrace(); - } - } - } - - /** - * Probe log. - * - * @param log - * the log - */ - public void probeLog(final HttpAccessLog log) - { - if (log != null) - { - // logger.info("LINE IS MATCHING [{}]", log); - // logger.info(log.getHttpUserAgent().toString()); - - // 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 (StringUtils.startsWithAny(log.getRequest(), "POST ", "GET /?pasteid=")) - { - 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.pastebins.created - // metrics.pastebins.read - // metrics.pastebins.deleted - if (StringUtils.startsWith(log.getRequest(), "POST ")) - { - this.counters.inc("metrics.pastebins.created", year, yearMonth, yearWeek, date); - } - else if (StringUtils.startsWith(log.getRequest(), "GET /?pasteid=")) - { - if (StringUtils.contains(log.getRequest(), "&deletetoken=")) - { - this.counters.inc("metrics.pastebins.deleted", year, yearMonth, yearWeek, date); - } - else - { - this.counters.inc("metrics.pastebins.read", year, yearMonth, yearWeek, date); - } - } - } - } - - /** - * Probe. - * - * @param httpAccessLogs - * the source - * @throws IOException - * Signals that an I/O exception has occurred. - * @throws StatoolInfosException - * the statool infos exception - */ - public static PathCounters probe(final String httpAccessLogs, final String httpRegex) throws IOException, StatoolInfosException - { - PathCounters result; - - PrivatebinHttpLogAnalyzer analyzer = new PrivatebinHttpLogAnalyzer(); - - for (File file : FilesUtils.searchByWildcard(httpAccessLogs)) - { - analyzer.probe(file, httpRegex); - } - - result = analyzer.getCounters(); - - // - return result; - } -} diff --git a/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinProber.java b/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinProber.java index ff0c488..8629e74 100644 --- a/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinProber.java +++ b/src/fr/devinsy/statoolinfos/metrics/privatebin/PrivatebinProber.java @@ -21,11 +21,18 @@ package fr.devinsy.statoolinfos.metrics.privatebin; import java.io.File; import java.io.IOException; +import org.apache.commons.lang3.StringUtils; 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.HttpAccessLogs; +import fr.devinsy.statoolinfos.metrics.util.DatafilesProber; +import fr.devinsy.statoolinfos.util.Files; +import fr.devinsy.statoolinfos.util.FilesUtils; /** * The Class PrivatebinProber. @@ -37,10 +44,80 @@ public class PrivatebinProber /** * Instantiates a new privatebin prober. */ - public PrivatebinProber() + private PrivatebinProber() { } + private static PathCounters probe(final Files httpAccessLogs, final String httpRegex) throws IOException, StatoolInfosException + { + PathCounters result; + + result = new PathCounters(); + + // + UserCounters users = new UserCounters(); + UserCounters ipv4Users = new UserCounters(); + UserCounters ipv6Users = new UserCounters(); + + // + for (HttpAccessLog log : new HttpAccessLogs(httpAccessLogs, httpRegex)) + { + // logger.info("LINE IS MATCHING [{}]", log); + // logger.info(log.getHttpUserAgent().toString()); + + // 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 (StringUtils.startsWithAny(log.getRequest(), "POST ", "GET /?pasteid=")) + { + String key = String.format("%s---%s", log.getIp(), log.getUserAgent()); + users.put(key, year, yearMonth, yearWeek, date); + + if (log.isIPv4()) + { + ipv4Users.put(key, year, yearMonth, yearWeek, date); + } + else + { + ipv6Users.put(key, year, yearMonth, yearWeek, date); + } + } + + // metrics.pastebins.created + // metrics.pastebins.read + // metrics.pastebins.deleted + if (StringUtils.startsWith(log.getRequest(), "POST ")) + { + result.inc("metrics.pastebins.created", year, yearMonth, yearWeek, date); + } + else if (StringUtils.startsWith(log.getRequest(), "GET /?pasteid=")) + { + if (StringUtils.contains(log.getRequest(), "&deletetoken=")) + { + result.inc("metrics.pastebins.deleted", year, yearMonth, yearWeek, date); + } + else + { + result.inc("metrics.pastebins.read", year, yearMonth, yearWeek, date); + } + } + } + + // + result.putAll(users.getCounters("metrics.service.users")); + result.putAll(ipv4Users.getCounters("metrics.service.users.ipv4")); + result.putAll(ipv6Users.getCounters("metrics.service.users.ipv6")); + + // + return result; + } + /** * Probe. * @@ -48,7 +125,7 @@ public class PrivatebinProber * the http logs * @param httpLogRegex * the http log regex - * @param dataPath + * @param datafileDirectory * the data path * @return the path counters * @throws IOException @@ -56,7 +133,7 @@ public class PrivatebinProber * @throws StatoolInfosException * the statool infos exception */ - public static PathCounters probe(final String httpLogs, final String httpLogRegex, final File dataPath) throws IOException, StatoolInfosException + public static PathCounters probe(final Files httpLogs, final String httpLogRegex, final File datafileDirectory) throws IOException, StatoolInfosException { PathCounters result; @@ -66,11 +143,18 @@ public class PrivatebinProber // metrics.pastebins.created // metrics.pastebins.read // metrics.pastebins.deleted - result = PrivatebinHttpLogAnalyzer.probe(httpLogs, httpLogRegex); + result = probe(httpLogs, httpLogRegex); // metrics.service.files.bytes + // metrics.service.files.count + result.putAll(DatafilesProber.probe(datafileDirectory)); + // metrics.pastebins.count - result.putAll(PrivatebinDataAnalyzer.probe(dataPath)); + if ((datafileDirectory != null) && (datafileDirectory.exists()) && (datafileDirectory.isDirectory())) + { + long count = FilesUtils.searchByWildcard(datafileDirectory.getAbsolutePath() + "/??/*").size(); + result.set(count, "metrics.pastebins.count"); + } // metrics.pastebins.purged // purged = count(n-1) - count(n) + created - delete diff --git a/src/fr/devinsy/statoolinfos/metrics/util/DatabaseProber.java b/src/fr/devinsy/statoolinfos/metrics/util/DatabaseProber.java new file mode 100644 index 0000000..8997728 --- /dev/null +++ b/src/fr/devinsy/statoolinfos/metrics/util/DatabaseProber.java @@ -0,0 +1,83 @@ +/* + * 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.util; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fr.devinsy.statoolinfos.core.DatabaseConfig; +import fr.devinsy.statoolinfos.core.StatoolInfosException; +import fr.devinsy.statoolinfos.metrics.PathCounters; + +/** + * The Class DatabaseProber. + */ +public class DatabaseProber +{ + private static Logger logger = LoggerFactory.getLogger(DatabaseProber.class); + + /** + * Instantiates a new database prober. + */ + private DatabaseProber() + { + } + + /** + * Probe. + * + * @param directory + * the 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 DatabaseConfig config) throws IOException + { + PathCounters result; + + result = new PathCounters(); + + if (config != null) + { + System.out.println("Probing directory [" + config.getName() + "]"); + } + + // if ((directory != null) && (directory.exists()) && + // (directory.isDirectory())) + // { + // StringList timemarks = result.getNowTimeMarks(); + // + // // metrics.service.database.bytes + // long size = FileUtils.sizeOfDirectory(directory); + // result.set(size, prefix + ".files.bytes", timemarks); + // } + // else + // { + // System.out.println("WARNING: datafile path not valid."); + // } + + // + return result; + } +} diff --git a/src/fr/devinsy/statoolinfos/metrics/util/DatafilesProber.java b/src/fr/devinsy/statoolinfos/metrics/util/DatafilesProber.java index 8c95386..0d5d231 100644 --- a/src/fr/devinsy/statoolinfos/metrics/util/DatafilesProber.java +++ b/src/fr/devinsy/statoolinfos/metrics/util/DatafilesProber.java @@ -59,7 +59,7 @@ public class DatafilesProber { PathCounters result; - result = probe(directory, "metrics.files"); + result = probe(directory, "metrics.service"); // return result;