Added Minetest log analyze.

This commit is contained in:
Christian P. MOMON 2021-12-18 18:14:36 +01:00
parent 0bed68260a
commit 8b87eed546
11 changed files with 1025 additions and 8 deletions

View file

@ -253,6 +253,29 @@ public class Configuration extends PathPropertyList
return result;
}
/**
* Gets the database config.
*
* @param prefix
* the prefix
* @return the database config
*/
public DatabaseConfig getDatabaseConfig(final String prefix)
{
DatabaseConfig result;
result = new DatabaseConfig();
result.setHost(get(prefix + ".db.host"));
result.setPort(get(prefix + ".db.port"));
result.setName(get(prefix + ".db.name"));
result.setUser(get(prefix + ".db.user"));
result.setPassword(get(prefix + ".db.password"));
//
return result;
}
/**
* Gets the edito directory.
*

View file

@ -0,0 +1,93 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.statoolinfos.core;
/**
* The Class DatabaseConfig.
*/
public class DatabaseConfig
{
private String host;
private String port;
private String name;
private String user;
private String password;
/**
* Instantiates a new database config.
*/
public DatabaseConfig()
{
this.host = null;
this.port = null;
this.name = null;
this.user = null;
this.password = null;
}
public String getHost()
{
return this.host;
}
public String getName()
{
return this.name;
}
public String getPassword()
{
return this.password;
}
public String getPort()
{
return this.port;
}
public String getUser()
{
return this.user;
}
public void setHost(final String host)
{
this.host = host;
}
public void setName(final String name)
{
this.name = name;
}
public void setPassword(final String password)
{
this.password = password;
}
public void setPort(final String port)
{
this.port = port;
}
public void setUser(final String user)
{
this.user = user;
}
}

View file

@ -34,11 +34,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.statoolinfos.core.Configuration;
import fr.devinsy.statoolinfos.core.DatabaseConfig;
import fr.devinsy.statoolinfos.core.Factory;
import fr.devinsy.statoolinfos.core.StatoolInfosException;
import fr.devinsy.statoolinfos.core.StatoolInfosUtils;
import fr.devinsy.statoolinfos.metrics.http.HttpAccessLogAnalyzer;
import fr.devinsy.statoolinfos.metrics.http.HttpErrorLogAnalyzer;
import fr.devinsy.statoolinfos.metrics.minetest.MinetestProber;
import fr.devinsy.statoolinfos.properties.PathProperties;
import fr.devinsy.statoolinfos.properties.PathProperty;
import fr.devinsy.statoolinfos.properties.PathPropertyUtils;
@ -138,6 +140,17 @@ public class Prober
// counters.putAll(data);
}
//
if (types.containsAnyIgnoreCase("Minetest"))
{
logger.info("== Processing Minetest.");
String source = configuration.get("conf.probe.minetest.logs");
DatabaseConfig database = configuration.getDatabaseConfig("conf.probe.minetest.players");
PathCounters data = MinetestProber.probe(source, database);
counters.putAll(data);
}
//
if (types.containsAnyIgnoreCase("Mumble"))
{

View file

@ -204,6 +204,7 @@ public class HttpAccessLog
{
result = this.ip.contains(".");
}
//
return result;
}
@ -225,6 +226,7 @@ public class HttpAccessLog
{
result = this.ip.contains(":");
}
//
return result;
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.statoolinfos.metrics.minetest;
import java.util.HashMap;
import fr.devinsy.statoolinfos.metrics.PathCounters;
import fr.devinsy.strings.StringSet;
/**
* The Class ActivePlayerCounters.
*/
public class ActivePlayerCounters extends HashMap<String, StringSet>
{
private static final long serialVersionUID = 8340304752282908677L;
/**
* Instantiates a new active player counters.
*/
public ActivePlayerCounters()
{
super();
}
/**
* Gets the.
*
* @param timeMark
* the time mark
* @return the string set
*/
public StringSet get(final String timeMark)
{
StringSet result;
result = super.get(timeMark);
//
return result;
}
/**
* Gets the counters.
*
* @return the counters
*/
public PathCounters getCounters(final String prefix)
{
PathCounters result;
result = new PathCounters();
for (String timeMark : keySet())
{
StringSet set = get(timeMark);
result.inc(set.size(), prefix, timeMark);
}
//
return result;
}
/**
* Put.
*
* @param timemark
* the timemark
* @param nickname
* the nick name
*/
public void put(final String nickname, final String timemark)
{
StringSet set = super.get(timemark);
if (set == null)
{
set = new StringSet();
put(timemark, set);
}
set.put(nickname);
}
/**
* Put.
*
* @param nickname
* the nickname
* @param timeMarks
* the time marks
*/
public void put(final String nickname, final String... timeMarks)
{
for (String timeMark : timeMarks)
{
put(nickname, timeMark);
}
}
}

View file

@ -0,0 +1,240 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.statoolinfos.metrics.minetest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.statoolinfos.metrics.TimeMarkUtils;
import fr.devinsy.strings.StringList;
/**
* The Class MinetestLog.
*/
public class MinetestLog
{
private static Logger logger = LoggerFactory.getLogger(MinetestLog.class);
// Cpm [2a01:e0a:22:ce10::adc5:a] joins game. List of players: Cpm
public static final Pattern JOIN_PATTERN = Pattern.compile("^(?<nickname>\\S+) \\[(?<ip>.+)\\] joins game\\..*$");
public static final Pattern NICK_PATTERN = Pattern
.compile(
"^(player )?(?<nickname>\\S+) (activates |crafts |damaged by |digs |has gottern award |leaves game |moves stuff |places node |respawns |right-clicks object |takes stuff |times out\\.).*$");
private LocalDateTime time;
private MinetestLogLevel level;
private String module;
private String message;
/**
* Instantiates a new http access log.
*/
public MinetestLog()
{
this.time = null;
this.level = null;
this.module = null;
this.message = null;
}
public String getDate()
{
String result;
result = this.time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.FRANCE));
//
return result;
}
/**
* Gets the ip.
*
* @return the ip
*/
public String getIp()
{
String result;
Matcher matcher = JOIN_PATTERN.matcher(this.message);
if (matcher.matches())
{
result = matcher.group("ip");
}
else
{
result = null;
}
//
return result;
}
public MinetestLogLevel getLevel()
{
return this.level;
}
public String getMessage()
{
return this.message;
}
public String getModule()
{
return this.module;
}
/**
* Gets the nickname.
*
* @return the nickname
*/
public String getNickname()
{
String result;
Matcher matcher = NICK_PATTERN.matcher(this.message);
if (matcher.matches())
{
result = matcher.group("nickname");
}
else
{
result = null;
}
//
return result;
}
public LocalDateTime getTime()
{
return this.time;
}
/**
* Gets the year.
*
* @return the year
*/
public String getYear()
{
String result;
if (this.time == null)
{
result = null;
}
else
{
result = TimeMarkUtils.yearOf(this.time);
}
//
return result;
}
/**
* Gets the year month.
*
* @return the year month
*/
public String getYearMonth()
{
String result;
if (this.time == null)
{
result = null;
}
else
{
result = TimeMarkUtils.yearMonthOf(this.time);
}
//
return result;
}
/**
* Gets the year week.
*
* @return the year week
*/
public String getYearWeek()
{
String result;
if (this.time == null)
{
result = null;
}
else
{
result = TimeMarkUtils.yearWeekOf(this.time);
}
//
return result;
}
public void setLevel(final MinetestLogLevel level)
{
this.level = level;
}
public void setMessage(final String message)
{
this.message = message;
}
public void setModule(final String module)
{
this.module = module;
}
public void setTime(final LocalDateTime time)
{
this.time = time;
}
/**
* To string.
*
* @return the string
*/
@Override
public String toString()
{
String result;
StringList buffer = new StringList();
buffer.append("[time=").append(this.time).append("]");
result = buffer.toString();
//
return result;
}
}

View file

@ -0,0 +1,278 @@
/*
* Copyright (C) 2020-2021 Christian Pierre MOMON <christian@momon.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.statoolinfos.metrics.minetest;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.regex.Matcher;
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.http.IpCounters;
import fr.devinsy.statoolinfos.util.FilesUtils;
import fr.devinsy.statoolinfos.util.IpUtils;
import fr.devinsy.statoolinfos.util.LineIterator;
/**
* The Class HttpAccessLogProber.
*/
public class MinetestLogAnalyzer
{
private static Logger logger = LoggerFactory.getLogger(MinetestLogAnalyzer.class);
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
// log_format combined '$remote_addr - $remote_user [$time_local] '
// '"$request" $status $body_bytes_sent '
// '"$http_referer" "$http_user_agent"';
public static final Pattern MINETEST_LOG_PATTERN = Pattern.compile(
"^(?<datetime>\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}): (?<level>[^\\[]*)\\[(?<module>[^\\]]+)\\]: (?<message>.*)$");
private int errorCount;
private PathCounters counters;
private ActivePlayerCounters activePlayers;
private IpCounters ips;
private IpCounters ipv4;
private IpCounters ipv6;
/**
* Instantiates a new http access log prober.
*/
public MinetestLogAnalyzer()
{
this.counters = new PathCounters();
this.activePlayers = new ActivePlayerCounters();
this.ips = new IpCounters();
this.ipv4 = new IpCounters();
this.ipv6 = new IpCounters();
}
/**
* Gets the counters.
*
* @return the counters
*/
public PathCounters getCounters()
{
PathCounters result;
result = new PathCounters();
result.putAll(this.counters);
result.putAll(this.activePlayers.getCounters("metrics.metaverse.players.active"));
result.putAll(this.ips.getCounters("metrics.metaverse.ip"));
result.putAll(this.ipv4.getCounters("metrics.metaverse.ip.ipv4"));
result.putAll(this.ipv6.getCounters("metrics.metaverse.ip.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) throws IOException
{
System.out.println("Probing file [" + file.getAbsolutePath() + "]");
//
LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
{
String line = iterator.next();
try
{
if ((!StringUtils.isBlank(line)) && (!StringUtils.startsWith(line, " ")) && (!StringUtils.startsWith(line, "-")))
{
MinetestLog log = parseLog(line);
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();
this.errorCount += 1;
}
}
}
/**
* Probe log.
*
* @param log
* the log
*/
public void probeLog(final MinetestLog log)
{
// logger.info("==================");
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.metaverse.logs
this.counters.inc("metrics.metaverse.logs", year, yearMonth, yearWeek, date);
// metrics.metaverse.logs.action
// metrics.metaverse.logs.warning
// metrics.metaverse.logs.error
// metrics.metaverse.logs.none
if (log.getLevel() == MinetestLogLevel.ACTION)
{
this.counters.inc("metrics.metaverse.logs.action", year, yearMonth, yearWeek, date);
}
else if (log.getLevel() == MinetestLogLevel.WARNING)
{
this.counters.inc("metrics.metaverse.logs.warning", year, yearMonth, yearWeek, date);
}
else if (log.getLevel() == MinetestLogLevel.ERROR)
{
this.counters.inc("metrics.metaverse.logs.error", year, yearMonth, yearWeek, date);
}
else if (log.getLevel() == MinetestLogLevel.NONE)
{
this.counters.inc("metrics.metaverse.logs.none", year, yearMonth, yearWeek, date);
}
else if (log.getLevel() == MinetestLogLevel.UNKNOWN)
{
this.counters.inc("metrics.metaverse.logs.unknown", year, yearMonth, yearWeek, date);
}
// metrics.metaverse.players.active
this.activePlayers.put(log.getNickname(), year, yearMonth, yearWeek, date);
// metrics.metaverse.players.max
// TODO
// metrics.metaverse.joins --
if (log.getMessage().contains(" joins game."))
{
this.counters.inc("metrics.metaverse.joins", year, yearMonth, yearWeek, date);
}
// metrics.metaverse.ip
// metrics.metaverse.ip.ipv4
// metrics.metaverse.ip.ipv6
String ip = log.getIp();
if (ip != null)
{
this.ips.put(ip, year, yearMonth, yearWeek, date);
if (IpUtils.isIpv4(ip))
{
this.ipv4.put(ip, year, yearMonth, yearWeek, date);
}
else
{
this.ipv6.put(ip, year, yearMonth, yearWeek, date);
}
}
// metrics.metaverse.games (visits)
// metrics.metaverse.games.duration (visits)
// TODO
}
}
/**
* Parses the log.
*
* @param line
* the line
* @return the http log
*/
public static MinetestLog parseLog(final String line)
{
MinetestLog result;
Matcher matcher = MINETEST_LOG_PATTERN.matcher(line);
if (matcher.matches())
{
result = new MinetestLog();
result.setTime(LocalDateTime.parse(matcher.group("datetime"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withLocale(Locale.ENGLISH)));
result.setLevel(MinetestLogLevel.of(matcher.group("level")));
result.setModule(matcher.group("module"));
result.setMessage(matcher.group("message"));
}
else
{
result = null;
}
//
return result;
}
/**
* Probe.
*
* @param source
* the source
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws StatoolInfosException
* the statool infos exception
*/
public static PathCounters probe(final String source) throws IOException, StatoolInfosException
{
PathCounters result;
MinetestLogAnalyzer analyzer = new MinetestLogAnalyzer();
for (File file : FilesUtils.searchByWildcard(source))
{
analyzer.probe(file);
}
result = analyzer.getCounters();
//
return result;
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.statoolinfos.metrics.minetest;
import org.apache.commons.lang3.StringUtils;
/**
* The Enum MinetestLogLevel.
*/
public enum MinetestLogLevel
{
ACTION,
WARNING,
ERROR,
NONE,
UNKNOWN;
/**
* Value of.
*
* @param httpCode
* the code
* @return the http status category
*/
public static MinetestLogLevel of(final String value)
{
MinetestLogLevel result;
if (StringUtils.equals(value, "ACTION"))
{
result = ACTION;
}
else if (StringUtils.equals(value, "WARNING"))
{
result = WARNING;
}
else if (StringUtils.equals(value, "ERROR"))
{
result = ERROR;
}
else if (StringUtils.equals(value, "NONE"))
{
result = NONE;
}
else
{
result = UNKNOWN;
}
//
return result;
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (C) 2020 Christian Pierre MOMON <christian@momon.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.statoolinfos.metrics.minetest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class HttpAccesLogStat.
*/
public class MinetestLogStat
{
private static Logger logger = LoggerFactory.getLogger(MinetestLogStat.class);
private int hitCount;
private int hitIpv4Count;
private int hitIpv6Count;
private int pageCount;
private int pageIpv4Count;
private int pageIpv6Count;
private int byteCount;
private int byteIpv4Count;
private int byteIpv6Count;
private int fileCount;
private int fileIpv4Count;
private int fileIpv6Count;
private int status1xxCount;
private int status2xxCount;
private int status3xxCount;
private int status4xxCount;
private int status5xxCount;
private int ipCount;
private int ipIpv4Count;
private int ipIpv6Count;
/**
* Instantiates a new http acces log stat.
*/
public MinetestLogStat()
{
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (C) 2020-2021 Christian Pierre MOMON <christian@momon.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.statoolinfos.metrics.minetest;
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 MinetestProber.
*/
public class MinetestProber
{
private static Logger logger = LoggerFactory.getLogger(MinetestProber.class);
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
/**
* Instantiates a new minetest prober.
*/
public MinetestProber()
{
}
/**
* Probe.
*
* @param logs
* the logs
* @param databaseConfig
* the database config
* @throws StatoolInfosException
* @throws IOException
*/
public static PathCounters probe(final String logs, final DatabaseConfig databaseConfig) throws IOException, StatoolInfosException
{
PathCounters result;
result = MinetestLogAnalyzer.probe(logs);
// metrics.metaverse.players
// accounts
// database size
// file size
//
return result;
}
}

View file

@ -40,15 +40,26 @@ public class IpUtils
/**
* Checks if is ipv4.
*
* @param input
* the input
* @param value
* the value
* @return true, if is ipv4
*/
public static boolean isIpv4(final String input)
public static boolean isIpv4(final String value)
{
boolean result;
result = IPV4_PATTERN.matcher(input).matches();
if (value == null)
{
result = false;
}
else if (value.startsWith("::ffff:"))
{
result = true;
}
else
{
result = value.contains(".");
}
//
return result;
@ -70,4 +81,45 @@ public class IpUtils
//
return result;
}
/**
* Checks if is ipv6.
*
* @param value
* the value
* @return true, if is ipv6
*/
public static boolean isIPv6(final String value)
{
boolean result;
if (value == null)
{
result = false;
}
else
{
result = value.contains(":");
}
//
return result;
}
/**
* Checks if is valid ipv4.
*
* @param input
* the input
* @return true, if is valid ipv4
*/
public static boolean isValidIpv4(final String input)
{
boolean result;
result = IPV4_PATTERN.matcher(input).matches();
//
return result;
}
}