Added code for http log analyze.

This commit is contained in:
Christian P. MOMON 2021-02-18 05:33:27 +01:00
parent a1f9dbabf9
commit 029a9f563d
16 changed files with 1736 additions and 276 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2020 Christian Pierre MOMON <christian@momon.org> * Copyright (C) 2020-2021 Christian Pierre MOMON <christian@momon.org>
* *
* This file is part of StatoolInfos, simple service statistics tool. * This file is part of StatoolInfos, simple service statistics tool.
* *
@ -25,6 +25,7 @@ import org.apache.commons.lang3.StringUtils;
import fr.devinsy.statoolinfos.crawl.CrawlCache; import fr.devinsy.statoolinfos.crawl.CrawlCache;
import fr.devinsy.statoolinfos.properties.PathProperties; import fr.devinsy.statoolinfos.properties.PathProperties;
import fr.devinsy.statoolinfos.properties.PathPropertyList; import fr.devinsy.statoolinfos.properties.PathPropertyList;
import fr.devinsy.strings.StringList;
/** /**
* The Class PathProperty. * The Class PathProperty.
@ -346,6 +347,80 @@ public class Configuration extends PathPropertyList
return result; return result;
} }
/**
* Gets the probe http access log file.
*
* @return the probe http access log file
*/
public String getProbeHttpAccessLogSource()
{
String result;
result = get("conf.probe.httpaccesslog.file");
//
return result;
}
/**
* Gets the probe http error log source.
*
* @return the probe http error log source
*/
public String getProbeHttpErrorLogSource()
{
String result;
result = get("conf.probe.httperrorlog.file");
//
return result;
}
/**
* Gets the probe target.
*
* @return the probe target
*/
public File getProbeTarget()
{
File result;
String filename = get("conf.probe.target");
if (StringUtils.isBlank(filename))
{
result = null;
}
else
{
result = new File(filename);
}
//
return result;
}
/**
* Gets the probe types.
*
* @return the probe types
*/
public StringList getProbeTypes()
{
StringList result;
result = new StringList();
String types = get("conf.probe.types");
if (!StringUtils.isBlank(types))
{
result.append(types.split("[, ;]"));
}
//
return result;
}
/** /**
* Checks for valid cache. * Checks for valid cache.
* *

View file

@ -18,18 +18,14 @@
*/ */
package fr.devinsy.statoolinfos.htmlize.probes; package fr.devinsy.statoolinfos.htmlize.probes;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -45,62 +41,42 @@ public class HttpAccessLogAnalyzer
public static final String DEFAULT_CHARSET_NAME = "UTF-8"; public static final String DEFAULT_CHARSET_NAME = "UTF-8";
private int errorCount;
private PathCounters counters;
private VisitCounters visits;
private IpCounters ips;
private IpCounters ipv4;
private IpCounters ipv6;
/** /**
* Instantiates a new http access log prober. * Instantiates a new http access log prober.
*/ */
private HttpAccessLogAnalyzer() public HttpAccessLogAnalyzer()
{ {
this.counters = new PathCounters();
this.visits = new VisitCounters();
this.ips = new IpCounters();
this.ipv4 = new IpCounters();
this.ipv6 = new IpCounters();
} }
/** /**
* Parses the log. * Gets the counters.
* *
* @param line * @return the counters
* the line
* @return the http log
*/ */
public static HttpLog parseLog(final String line) public PathCounters getCounters()
{ {
HttpLog result; PathCounters result;
// result = new PathCounters();
// log_format combined '$remote_addr - $remote_user [$time_local] ' result.putAll(this.counters);
// '"$request" $status $body_bytes_sent '
// '"$http_referer" "$http_user_agent"';
String remoteAddressPattern = "(?<remoteAddress>[a-zA-F0-9\\\\:\\\\.]+)";
String remoteUserPattern = "(?<remoteUser>\\S+)";
String timePattern = "(?<time>[^\\]]+)";
String requestPattern = "(?<request>[^\"]*)";
String statusPattern = "(?<status>\\d+)";
String bodyBytesSentPattern = "(?<bodyBytesSent>\\d+)";
String refererPattern = "(?<referer>[^\"]*)";
String httpUserAgentPattern = "(?<httpUserAgent>[^\"]*)";
String combinedPattern = String.format("^%s - %s \\[%s\\] \"%s\" %s %s \"%s\" \"%s\".*$", result.putAll(this.ips.getCounters("metrics.http.ip"));
remoteAddressPattern, remoteUserPattern, timePattern, requestPattern, statusPattern, bodyBytesSentPattern, result.putAll(this.ipv4.getCounters("metrics.http.ip.ipv4"));
refererPattern, httpUserAgentPattern); result.putAll(this.ipv6.getCounters("metrics.http.ip.ipv6"));
// logger.info("pattern=[{}]", combinedPattern); result.putAll(this.visits.getCounters("metrics.http.visits"));
Pattern combined = Pattern.compile(combinedPattern);
Matcher matcher = combined.matcher(line);
if (matcher.matches())
{
result = new HttpLog();
result.setRemoteAddress(matcher.group("remoteAddress"));
result.setRemoteUser(matcher.group("remoteUser"));
result.setTime(LocalDateTime.parse(matcher.group("time"), DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z").withLocale(Locale.ENGLISH)));
result.setRequest(matcher.group("request"));
result.setStatus(HttpStatusTable.instance().get(matcher.group("status")));
result.setBodyBytesSent(Long.valueOf(matcher.group("bodyBytesSent")));
result.setReferer(matcher.group("referer"));
result.setHttpUserAgent(new UserAgent(matcher.group("httpUserAgent")));
}
else
{
result = null;
}
// //
return result; return result;
@ -109,86 +85,31 @@ public class HttpAccessLogAnalyzer
/** /**
* Probe. * Probe.
* *
* @param source * @param file
* the source * the file
* @param target
* the target
* @throws IOException * @throws IOException
* Signals that an I/O exception has occurred. * Signals that an I/O exception has occurred.
* @throws StatoolInfosException * @throws StatoolInfosException
* the statool infos exception * the statool infos exception
*/ */
public static PathCounters probe(final File source, final File target) throws IOException, StatoolInfosException public void probe(final File file) throws IOException
{ {
PathCounters result = new PathCounters(); LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
int errorCount = 0;
for (File file : source.getParentFile().listFiles())
{ {
// if (file.getName().startsWith(source.getName())) String line = iterator.next();
if (file.getName().equals(source.getName()))
try
{ {
errorCount += probe(result, source); probeLine(line);
}
catch (Exception exception)
{
logger.warn("Error parsing line [{}][{}]", line, exception.getMessage());
exception.printStackTrace();
this.errorCount += 1;
} }
} }
//
return result;
}
/**
* Probe.
*
* @param source
* the source
* @param counters
* the counters
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws StatoolInfosException
* the statool infos exception
*/
public static int probe(final PathCounters counters, final File source) throws IOException, StatoolInfosException
{
int result;
BufferedReader in = null;
try
{
result = 0;
in = new BufferedReader(new InputStreamReader(new FileInputStream(source), DEFAULT_CHARSET_NAME));
boolean ended = false;
while (!ended)
{
String line = in.readLine();
if (line == null)
{
ended = true;
}
else if (StringUtils.isNotEmpty(line))
{
try
{
probe(counters, line);
}
catch (Exception exception)
{
exception.printStackTrace();
result += 1;
}
}
}
}
finally
{
IOUtils.closeQuietly(in);
}
//
return result;
} }
/** /**
@ -199,9 +120,10 @@ public class HttpAccessLogAnalyzer
* @param line * @param line
* the line * the line
*/ */
public static void probe(final PathCounters counters, final String line) public void probeLine(final String line)
{ {
HttpLog log = parseLog(line);
HttpLog log = parseNginxCombinedLog(line);
// logger.info("=================="); // logger.info("==================");
if (log == null) if (log == null)
@ -220,64 +142,174 @@ public class HttpAccessLogAnalyzer
String date = log.getDate(); String date = log.getDate();
// metrics.http.hits // metrics.http.hits
counters.inc("metrics.http.hits", year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.hits", year, yearMonth, yearWeek, date);
if (log.isIPv4()) if (log.isIPv4())
{ {
counters.inc("metrics.http.hits.ipv4", year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.hits.ipv4", year, yearMonth, yearWeek, date);
} }
else else
{ {
counters.inc("metrics.http.hits.ipv6", year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.hits.ipv6", year, yearMonth, yearWeek, date);
} }
// metrics.http.files // metrics.http.files
if (log.getBodyBytesSent() != 0) if (log.getBodyBytesSent() != 0)
{ {
counters.inc("metrics.http.file", year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.file", year, yearMonth, yearWeek, date);
} }
// metrics.http.bytes // metrics.http.bytes
counters.inc(log.getBodyBytesSent(), "metrics.http.bytes", year, yearMonth, yearWeek, date); this.counters.inc(log.getBodyBytesSent(), "metrics.http.bytes", year, yearMonth, yearWeek, date);
// metrics.http.hits.bots.* = // metrics.http.hits.bots.* =
if (log.isBot()) if (log.isBot())
{ {
counters.inc("metrics.http.hits.bots", year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.hits.bots", year, yearMonth, yearWeek, date);
} }
// metrics.http.pages.* = // metrics.http.pages.* =
if (StringUtils.endsWithAny(log.getRequest(), ".html", ".htm", ".xhtml", ".cgi")) if (StringUtils.endsWithAny(log.getRequest(), ".html", ".htm", ".xhtml", ".cgi"))
{ {
counters.inc("metrics.http.pages", year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.pages", year, yearMonth, yearWeek, date);
} }
// metrics.http.status.XXX // metrics.http.status.XXX
String status = String.valueOf(log.getStatus().getCode()); String status = String.valueOf(log.getStatus().getCode());
counters.inc("metrics.http.status." + status, year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.status." + status, year, yearMonth, yearWeek, date);
// metrics.http.os.XXXXX // metrics.http.os.XXXXX
UserAgentOS os = log.getHttpUserAgent().getOS(); UserAgentOS os = log.getUserAgent().getOS();
counters.inc("metrics.http.browsers." + os.toString().toLowerCase(), year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.browsers." + os.toString().toLowerCase(), year, yearMonth, yearWeek, date);
// metrics.http.browsers.XXXXX // metrics.http.browsers.XXXXX
UserAgentBrowser browser = log.getHttpUserAgent().getBrowser(); UserAgentBrowser browser = log.getUserAgent().getBrowser();
counters.inc("metrics.http.browsers." + browser.toString().toLowerCase(), year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.browsers." + browser.toString().toLowerCase(), year, yearMonth, yearWeek, date);
// metrics.http.devices.XXXXX = // metrics.http.devices.XXXXX =
UserAgentDevice device = log.getHttpUserAgent().getDevice(); UserAgentDevice device = log.getUserAgent().getDevice();
counters.inc("metrics.http.devices." + device.toString().toLowerCase(), year, yearMonth, yearWeek, date); this.counters.inc("metrics.http.devices." + device.toString().toLowerCase(), year, yearMonth, yearWeek, date);
// metrics.http.countries.XX =
// metrics.http.ip.* = // metrics.http.ip.* =
// metrics.http.ip.ipv4.* = // metrics.http.ip.ipv4.* =
// metrics.http.ip.ipv6.* = // metrics.http.ip.ipv6.* =
this.ips.put(log.getRemoteAddress(), year, yearMonth, yearWeek, date);
if (log.isIPv4())
{
this.ipv4.put(log.getRemoteAddress(), year, yearMonth, yearWeek, date);
}
else
{
this.ipv6.put(log.getRemoteAddress(), year, yearMonth, yearWeek, date);
}
// metrics.http.visits.* = // metrics.http.visits.* =
this.visits.putVisit(log);
this.visits.storeTimeMarks(year, yearMonth, yearWeek, date);
// metrics.http.countries.XX =
// metrics.http.errors.* = // metrics.http.errors.* =
// metrics.http.errors.php.* = // metrics.http.errors.php.* =
} }
} }
/**
* Parses the log.
*
* @param line
* the line
* @return the http log
*/
public static HttpLog parseNginxCombinedLog(final String line)
{
HttpLog result;
// log_format combined '$remote_addr - $remote_user [$time_local] '
// '"$request" $status $body_bytes_sent '
// '"$http_referer" "$http_user_agent"';
String combinedPattern = "^(?<remoteAddress>[a-zA-F0-9\\\\:\\\\.]+) - (?<remoteUser>\\S+) \\[(?<time>[^\\]]+)\\] \"(?<request>[^\"]*)\" (?<status>\\d+) (?<bodyBytesSent>\\d+) \"(?<referer>[^\"]*)\" \"(?<userAgent>[^\"]*)\".*$";
result = parseLog(line, combinedPattern);
//
return result;
}
/**
* Parses the log.
*
* @param line
* the line
* @return the http log
*/
public static HttpLog parseLog(final String line, final String pattern)
{
HttpLog result;
Pattern combined = Pattern.compile(pattern);
Matcher matcher = combined.matcher(line);
if (matcher.matches())
{
result = new HttpLog();
result.setRemoteAddress(matcher.group("remoteAddress"));
result.setRemoteUser(matcher.group("remoteUser"));
result.setTime(LocalDateTime.parse(matcher.group("time"), DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z").withLocale(Locale.ENGLISH)));
result.setRequest(matcher.group("request"));
result.setStatus(HttpStatusTable.instance().get(matcher.group("status")));
result.setBodyBytesSent(Long.valueOf(matcher.group("bodyBytesSent")));
result.setReferer(matcher.group("referer"));
result.setUserAgent(new UserAgent(matcher.group("userAgent")));
}
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;
HttpAccessLogAnalyzer analyzer = new HttpAccessLogAnalyzer();
if (!StringUtils.isBlank(source))
{
if (source.endsWith("*"))
{
for (File file : new File(source).getParentFile().listFiles())
{
// if (file.getName().startsWith(source.getName()))
if (file.getName().equals(source))
{
analyzer.probe(file);
}
}
}
else
{
File file = new File(source);
analyzer.probe(file);
}
}
result = analyzer.getCounters();
//
return result;
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2020 Christian Pierre MOMON <christian@momon.org> * Copyright (C) 2020-2021 Christian Pierre MOMON <christian@momon.org>
* *
* This file is part of StatoolInfos, simple service statistics tool. * This file is part of StatoolInfos, simple service statistics tool.
* *
@ -18,16 +18,12 @@
*/ */
package fr.devinsy.statoolinfos.htmlize.probes; package fr.devinsy.statoolinfos.htmlize.probes;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Locale; import java.util.Locale;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -35,86 +31,68 @@ import org.slf4j.LoggerFactory;
import fr.devinsy.statoolinfos.core.StatoolInfosException; import fr.devinsy.statoolinfos.core.StatoolInfosException;
/** /**
* The Class HttpErrorLogProber. * The Class HttpErrorLogAnalyzer.
*/ */
public class HttpErrorLogProber public class HttpErrorLogAnalyzer
{ {
private static Logger logger = LoggerFactory.getLogger(HttpErrorLogProber.class); private static Logger logger = LoggerFactory.getLogger(HttpErrorLogAnalyzer.class);
public static final String DEFAULT_CHARSET_NAME = "UTF-8"; public static final String DEFAULT_CHARSET_NAME = "UTF-8";
private PathCounters counters;
private int errorCount;
/** /**
* Instantiates a new http error log prober. * Instantiates a new http error log analyzer.
*/ */
private HttpErrorLogProber() public HttpErrorLogAnalyzer()
{ {
this.counters = new PathCounters();
this.errorCount += 1;
}
/**
* Gets the counters.
*
* @return the counters
*/
public PathCounters getCounters()
{
PathCounters result;
result = new PathCounters();
result.putAll(this.counters);
//
return result;
} }
/** /**
* Probe. * Probe.
* *
* @param source * @param file
* the source * the file
* @param target
* the target
* @throws IOException * @throws IOException
* Signals that an I/O exception has occurred. * Signals that an I/O exception has occurred.
* @throws StatoolInfosException
* the statool infos exception
*/ */
public static void probe(final File source, final File target) throws IOException, StatoolInfosException public void probe(final File file) throws IOException
{ {
PathCounters counters; LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
counters = new PathCounters();
for (File file : source.getParentFile().listFiles())
{ {
if (file.getName().startsWith(source.getName())) String line = iterator.next();
try
{ {
probe(counters, source); probeLine(line);
} }
} catch (Exception exception)
}
/**
* Probe.
*
* @param source
* the source
* @param counters
* the counters
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws StatoolInfosException
* the statool infos exception
*/
public static void probe(final PathCounters counters, final File source) throws IOException, StatoolInfosException
{
BufferedReader in = null;
try
{
in = new BufferedReader(new InputStreamReader(new FileInputStream(source), DEFAULT_CHARSET_NAME));
boolean ended = false;
while (!ended)
{ {
String line = in.readLine(); logger.warn("Error parsing line [{}][{}]", line, exception.getMessage());
exception.printStackTrace();
if (line == null) this.errorCount += 1;
{
ended = true;
}
else if (StringUtils.isNotEmpty(line))
{
probe(counters, line);
}
} }
} }
finally
{
IOUtils.closeQuietly(in);
}
} }
/** /**
@ -125,7 +103,7 @@ public class HttpErrorLogProber
* @param line * @param line
* the line * the line
*/ */
public static void probe(final PathCounters counters, final String line) public void probeLine(final String line)
{ {
// //
LocalDateTime date; LocalDateTime date;
@ -137,18 +115,52 @@ public class HttpErrorLogProber
String week = date.format(DateTimeFormatter.ofPattern("yyyyWW", Locale.FRANCE)); String week = date.format(DateTimeFormatter.ofPattern("yyyyWW", Locale.FRANCE));
String day = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.FRANCE)); String day = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.FRANCE));
// General HTTP access logs.
// metrics.http.errors // metrics.http.errors
counters.inc("metrics.http.errors", year); this.counters.inc("metrics.http.errors", year, month, week, day);
counters.inc("metrics.http.errors", month);
counters.inc("metrics.http.errors", week);
counters.inc("metrics.http.errors", day);
// metrics.http.hits.ipv4 // metrics.http.errors.php
counters.inc("metrics.http.errors.php", year); }
counters.inc("metrics.http.errors.php", month);
counters.inc("metrics.http.errors.php", week); /**
counters.inc("metrics.http.errors.php", day); * Probe.
*
* @param source
* the source
* @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 source) throws IOException, StatoolInfosException
{
PathCounters result;
HttpErrorLogAnalyzer analyzer = new HttpErrorLogAnalyzer();
if (!StringUtils.isBlank(source))
{
if (source.endsWith("*"))
{
for (File file : new File(source).getParentFile().listFiles())
{
// if (file.getName().startsWith(source.getName()))
if (file.getName().equals(source))
{
analyzer.probe(file);
}
}
}
else
{
File file = new File(source);
analyzer.probe(file);
}
}
result = analyzer.getCounters();
//
return result;
} }
} }

View file

@ -46,7 +46,7 @@ public class HttpLog
private HttpStatus status; private HttpStatus status;
private long bodyBytesSent; private long bodyBytesSent;
private String referer; private String referer;
private UserAgent httpUserAgent; private UserAgent userAgent;
/** /**
* Instantiates a new http log. * Instantiates a new http log.
@ -60,7 +60,7 @@ public class HttpLog
this.status = null; this.status = null;
this.bodyBytesSent = 0; this.bodyBytesSent = 0;
this.referer = null; this.referer = null;
this.httpUserAgent = null; this.userAgent = null;
} }
public long getBodyBytesSent() public long getBodyBytesSent()
@ -78,11 +78,6 @@ public class HttpLog
return result; return result;
} }
public UserAgent getHttpUserAgent()
{
return this.httpUserAgent;
}
public String getReferer() public String getReferer()
{ {
return this.referer; return this.referer;
@ -113,6 +108,11 @@ public class HttpLog
return this.time; return this.time;
} }
public UserAgent getUserAgent()
{
return this.userAgent;
}
/** /**
* Gets the year. * Gets the year.
* *
@ -128,7 +128,7 @@ public class HttpLog
} }
else else
{ {
result = this.time.format(DateTimeFormatter.ofPattern("yyyy", Locale.FRANCE)); result = TimeMarkUtils.yearOf(this.time);
} }
// //
@ -150,7 +150,7 @@ public class HttpLog
} }
else else
{ {
result = this.time.format(DateTimeFormatter.ofPattern("yyyy-MM", Locale.FRANCE)); result = TimeMarkUtils.yearMonthOf(this.time);
} }
// //
return result; return result;
@ -170,8 +170,7 @@ public class HttpLog
} }
else else
{ {
result = TimeMarkUtils.yearWeekOf(this.time);
result = this.time.format(DateTimeFormatter.ofPattern("yyyy'W'ww", Locale.FRANCE));
} }
// //
return result; return result;
@ -184,7 +183,7 @@ public class HttpLog
{ {
boolean result; boolean result;
result = StringsUtils.containsAnyIgnoreCase(this.httpUserAgent.toString(), "bot", "monitoring"); result = StringsUtils.containsAnyIgnoreCase(this.userAgent.toString(), "bot", "monitoring");
// //
return result; return result;
@ -237,11 +236,6 @@ public class HttpLog
this.bodyBytesSent = bodyBytesSent; this.bodyBytesSent = bodyBytesSent;
} }
public void setHttpUserAgent(final UserAgent httpUserAgent)
{
this.httpUserAgent = httpUserAgent;
}
public void setReferer(final String referer) public void setReferer(final String referer)
{ {
this.referer = referer; this.referer = referer;
@ -272,6 +266,11 @@ public class HttpLog
this.time = time; this.time = time;
} }
public void setUserAgent(final UserAgent userAgent)
{
this.userAgent = userAgent;
}
/** /**
* To string. * To string.
* *
@ -291,7 +290,7 @@ public class HttpLog
buffer.append("[status=").append(this.status.getCode()).append("]"); buffer.append("[status=").append(this.status.getCode()).append("]");
buffer.append("[bodyBytesSent=").append(this.bodyBytesSent).append("]"); buffer.append("[bodyBytesSent=").append(this.bodyBytesSent).append("]");
buffer.append("[referer=").append(this.referer).append("]"); buffer.append("[referer=").append(this.referer).append("]");
buffer.append("[httpUserAgent=").append(this.httpUserAgent).append("]"); buffer.append("[userAgent=").append(this.userAgent).append("]");
result = buffer.toString(); result = buffer.toString();

View file

@ -97,7 +97,7 @@ public class HttpLogIterator
try try
{ {
String line = this.iterator.next(); String line = this.iterator.next();
result = HttpAccessLogAnalyzer.parseLog(line); result = HttpAccessLogAnalyzer.parseNginxCombinedLog(line);
} }
catch (Exception exception) catch (Exception exception)
{ {

View file

@ -0,0 +1,116 @@
/*
* 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.htmlize.probes;
import java.util.HashMap;
import fr.devinsy.strings.StringSet;
/**
* The Class IpCounters.
*/
public class IpCounters extends HashMap<String, StringSet>
{
private static final long serialVersionUID = -1597516678500117985L;
/**
* Instantiates a new path counters.
*/
public IpCounters()
{
super();
}
/**
* Gets the.
*
* @param path
* the path
* @param timeMark
* the time mark
* @return the path counter
*/
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 ip
* the ip
*/
public void put(final String ip, final String timemark)
{
StringSet set = super.get(ip);
if (set == null)
{
set = new StringSet();
put(timemark, set);
}
set.put(ip);
}
/**
* Put.
*
* @param ip
* the ip
* @param timeMarks
* the time marks
*/
public void put(final String ip, final String... timeMarks)
{
for (String timeMark : timeMarks)
{
put(ip, timeMark);
}
}
}

View file

@ -23,6 +23,7 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.zip.GZIPInputStream;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -51,7 +52,15 @@ public class LineIterator
*/ */
public LineIterator(final File source) throws IOException public LineIterator(final File source) throws IOException
{ {
this.in = new BufferedReader(new InputStreamReader(new FileInputStream(source), DEFAULT_CHARSET_NAME)); if (source.getName().endsWith(".gz"))
{
this.in = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(source))));
}
else
{
this.in = new BufferedReader(new InputStreamReader(new FileInputStream(source), DEFAULT_CHARSET_NAME));
}
this.nextLine = null; this.nextLine = null;
this.ready = false; this.ready = false;
} }

View file

@ -18,8 +18,6 @@
*/ */
package fr.devinsy.statoolinfos.htmlize.probes; package fr.devinsy.statoolinfos.htmlize.probes;
import java.util.regex.Pattern;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -86,9 +84,22 @@ public class PathCounter
{ {
boolean result; boolean result;
Pattern pattern = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$"); result = TimeMarkUtils.isDate(this.timeMark);
result = (pattern.matcher(this.timeMark).matches()); //
return result;
}
/**
* Checks if is year.
*
* @return true, if is year
*/
public boolean isYear()
{
boolean result;
result = TimeMarkUtils.isYear(this.timeMark);
// //
return result; return result;
@ -103,9 +114,7 @@ public class PathCounter
{ {
boolean result; boolean result;
Pattern pattern = Pattern.compile("^\\d{4}$"); result = TimeMarkUtils.isYear(this.timeMark);
result = (pattern.matcher(this.timeMark).matches());
// //
return result; return result;
@ -120,9 +129,7 @@ public class PathCounter
{ {
boolean result; boolean result;
Pattern pattern = Pattern.compile("^\\d{4}W\\d{2}$"); result = TimeMarkUtils.isYearWeek(this.timeMark);
result = (pattern.matcher(this.timeMark).matches());
// //
return result; return result;

View file

@ -226,7 +226,7 @@ public class PathCounters extends HashMap<String, PathCounter>
for (int week = 1; week <= weekCount; week++) for (int week = 1; week <= weekCount; week++)
{ {
String timeMark = String.format("%sW%02d", year, week); String timeMark = String.format("%s-W%02d", year, week);
PathCounter weekCounter = get(prefix, timeMark); PathCounter weekCounter = get(prefix, timeMark);
if (weekCounter != null) if (weekCounter != null)
{ {

View file

@ -23,7 +23,6 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -61,46 +60,63 @@ public class Prober
*/ */
public static void probe(final Configuration configuration) throws IOException, StatoolInfosException public static void probe(final Configuration configuration) throws IOException, StatoolInfosException
{ {
StringList types = configuration.getProbeTypes();
PathCounters counters = new PathCounters();
// //
if (types.containsAnyIgnoreCase("HttpAccessLog"))
{ {
String sourceFileName = configuration.get("conf.probe.http.accesslogs.source"); logger.info("== Processing HttpAccessLog.");
String targetFileName = configuration.get("conf.probe.http.accesslogs.target"); String source = configuration.getProbeHttpAccessLogSource();
logger.info("source=[{}]", source);
logger.info("source=[{}]", sourceFileName); PathCounters data = HttpAccessLogAnalyzer.probe(source);
logger.info("target=[{}]", targetFileName); counters.putAll(data);
if (!StringUtils.isAllBlank(sourceFileName, targetFileName))
{
PathCounters counters = HttpAccessLogAnalyzer.probe(new File(sourceFileName), new File(targetFileName));
writeMetrics(new File(targetFileName), counters);
// for (PathCounter counter : counters.values())
// {
// logger.info(counter.getPath() + " " +
// counter.getTimeMark() + " " + counter.getCounter());
// }
{
PathCounter counter = counters.get("metrics.http.hits", "2020");
logger.info("counter=" + counter.getCounter());
logger.info("size={}", counters.size());
}
}
} }
// //
// { if (types.containsAnyIgnoreCase("HttpErrorLog"))
// String sourceFileName = {
// configuration.get("conf.probe.httperrorlogs.source"); logger.info("== Processing HttpErrorLog.");
// String targetFileName = String source = configuration.getProbeHttpErrorLogSource();
// configuration.get("conf.probe.httperrorlogs.target"); logger.info("source=[{}]", source);
// if (!StringUtils.isAllBlank(sourceFileName, targetFileName))
// { PathCounters data = HttpErrorLogAnalyzer.probe(source);
// HttpErrorLogProber.probe(sourceFileName, targetFileName); counters.putAll(data);
// } }
// }
//
if (types.containsAnyIgnoreCase("Framadate"))
{
logger.info("== Processing Framadate.");
String source = configuration.getProbeHttpErrorLogSource();
logger.info("source=[{}]", source);
// PathCounters data = HttpErrorLogAnalyzer.probe(source);
// counters.putAll(data);
}
//
logger.info("== Writing.");
File target = configuration.getProbeTarget();
logger.info("target=[{}]", target);
if (target == null)
{
throw new IllegalArgumentException("Undefined target.");
}
else
{
writeMetrics(target, counters);
}
//
{
PathCounter counter = counters.get("metrics.http.hits", "2020");
logger.info("counter=" + counter.getCounter());
logger.info("size={}", counters.size());
}
} }
/** /**

View file

@ -0,0 +1,171 @@
/*
* 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.htmlize.probes;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class TimeMark.
*/
public class TimeMark
{
private static Logger logger = LoggerFactory.getLogger(TimeMark.class);
private String value;
/**
* Instantiates a new path counter.
*
* @param path
* the path
* @param timeMark
* the time mark
*/
public TimeMark(final String value)
{
this.value = value;
}
/**
* Checks if is date.
*
* @return true, if is date
*/
public boolean isDate()
{
boolean result;
Pattern pattern = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");
result = (pattern.matcher(this.value).matches());
//
return result;
}
/**
* Checks if is year mark.
*
* @return true, if is year mark
*/
public boolean isYearMark()
{
boolean result;
Pattern pattern = Pattern.compile("^\\d{4}$");
result = (pattern.matcher(this.value).matches());
//
return result;
}
/**
* Checks if is year week.
*
* @return true, if is year week
*/
public boolean isYearWeek()
{
boolean result;
Pattern pattern = Pattern.compile("^\\d{4}W\\d{2}$");
result = (pattern.matcher(this.value).matches());
//
return result;
}
public void setValue(final String value)
{
this.value = value;
}
public static TimeMark dayOf(final LocalDateTime date)
{
TimeMark result;
String day = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.FRANCE));
result = new TimeMark(day);
//
return result;
}
/**
* Month of.
*
* @param date
* the date
* @return the time mark
*/
public static TimeMark monthOf(final LocalDateTime date)
{
TimeMark result;
String month = date.format(DateTimeFormatter.ofPattern("yyyy-MM", Locale.FRANCE));
result = new TimeMark(month);
//
return result;
}
/**
* Year of.
*
* @param date
* the date
* @return the time mark
*/
public static TimeMark yearOf(final LocalDateTime date)
{
TimeMark result;
String year = date.format(DateTimeFormatter.ofPattern("yyyy", Locale.FRANCE));
result = new TimeMark(year);
//
return result;
}
/**
* Year week of.
*
* @param date
* the date
* @return the time mark
*/
public static TimeMark yearWeekOf(final LocalDateTime date)
{
TimeMark result;
String yearWeek = date.format(DateTimeFormatter.ofPattern("yyyyWW", Locale.FRANCE));
result = new TimeMark(yearWeek);
//
return result;
}
}

View file

@ -0,0 +1,254 @@
/*
* 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.htmlize.probes;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.extra.YearWeek;
/**
* The Class TimeMarkUtils.
*/
public class TimeMarkUtils
{
private static Logger logger = LoggerFactory.getLogger(TimeMarkUtils.class);
private static final Pattern YEAR_PATTERN = Pattern.compile("^(?<year>\\d{4})$");
private static final Pattern YEAR_MONTH_PATTERN = Pattern.compile("^(?<year>\\d{4})-(?<month>\\d{2})$");
private static final Pattern YEAR_WEEK_PATTERN = Pattern.compile("^(?<year>\\d{4})-W(?<week>\\d{2})$");
private static final Pattern DATE_PATTERN = Pattern.compile("^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})$");
/**
* Instantiates a new time mark utils.
*/
private TimeMarkUtils()
{
}
/**
* Day of.
*
* @param date
* the date
* @return the string
*/
public static String dateOf(final LocalDateTime date)
{
String result;
result = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.FRANCE));
//
return result;
}
/**
* Checks if is date.
*
* @param value
* the value
* @return true, if is date
*/
public static boolean isDate(final String value)
{
boolean result;
result = (DATE_PATTERN.matcher(value).matches());
//
return result;
}
/**
* Checks if is year mark.
*
* @param value
* the value
* @return true, if is year mark
*/
public static boolean isYear(final String value)
{
boolean result;
result = (YEAR_PATTERN.matcher(value).matches());
//
return result;
}
/**
* Checks if is year month.
*
* @param value
* the value
* @return true, if is year month
*/
public static boolean isYearMonth(final String value)
{
boolean result;
result = (YEAR_MONTH_PATTERN.matcher(value).matches());
//
return result;
}
/**
* Checks if is year week.
*
* @param value
* the value
* @return true, if is year week
*/
public static boolean isYearWeek(final String value)
{
boolean result;
result = (YEAR_WEEK_PATTERN.matcher(value).matches());
//
return result;
}
/**
* Parses the date.
*
* @param value
* the value
* @return the local date
*/
public static LocalDate parseDate(final String value)
{
LocalDate result;
result = LocalDate.parse(value);
//
return result;
}
/**
* Parses the year.
*
* @param value
* the value
* @return the int
*/
public static int parseYear(final String value)
{
int result;
result = Integer.parseInt(value);
//
return result;
}
/**
* Parses the year month.
*
* @param value
* the value
* @return the year month
*/
public static YearMonth parseYearMonth(final String value)
{
YearMonth result;
result = YearMonth.parse(value);
//
return result;
}
/**
* Parses the year week.
*
* @param value
* the value
* @return the year week
*/
public static YearWeek parseYearWeek(final String value)
{
YearWeek result;
result = YearWeek.parse(value);
//
return result;
}
/**
* Month of.
*
* @param date
* the date
* @return the string
*/
public static String yearMonthOf(final LocalDateTime date)
{
String result;
result = date.format(DateTimeFormatter.ofPattern("yyyy-MM", Locale.FRANCE));
//
return result;
}
/**
* Year of.
*
* @param date
* the date
* @return the string
*/
public static String yearOf(final LocalDateTime date)
{
String result;
result = date.format(DateTimeFormatter.ofPattern("yyyy", Locale.FRANCE));
//
return result;
}
/**
* Year week of.
*
* @param date
* the date
* @return the string
*/
public static String yearWeekOf(final LocalDateTime date)
{
String result;
result = date.format(DateTimeFormatter.ofPattern("yyyy'-W'ww", Locale.FRANCE));
//
return result;
}
}

View file

@ -0,0 +1,248 @@
/*
* 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.htmlize.probes;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.temporal.WeekFields;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.extra.YearWeek;
/**
* The Class PathCounter.
*/
public class Visit
{
private static Logger logger = LoggerFactory.getLogger(Visit.class);
private LocalDateTime start;
private LocalDateTime end;
/**
* Instantiates a new visit.
*
* @param start
* the start
*/
public Visit(final LocalDateTime start)
{
this(start, start);
}
/**
* Instantiates a new visit.
*
* @param start
* the start
* @param end
* the end
*/
public Visit(final LocalDateTime start, final LocalDateTime end)
{
if (start == null)
{
throw new IllegalArgumentException("Null parameter [start].");
}
else if (end == null)
{
throw new IllegalArgumentException("Null parameter [end].");
}
else
{
this.start = start;
this.end = end;
}
}
public LocalDateTime getEnd()
{
return this.end;
}
public LocalDateTime getStart()
{
return this.start;
}
/**
* Checks if is matching.
*
* @param year
* the year
* @return true, if is matching
*/
public boolean isMatching(final int year)
{
boolean result;
if ((year >= this.start.getYear()) && (year <= this.end.getYear()))
{
result = true;
}
else
{
result = false;
}
//
return result;
}
/**
* Checks if is matching.
*
* @param date
* the date
* @return true, if is matching
*/
public boolean isMatching(final LocalDate date)
{
boolean result;
if (date == null)
{
result = false;
}
else
{
LocalDate startDate = this.start.toLocalDate();
LocalDate endDate = this.end.toLocalDate();
if ((date.isBefore(startDate)) || (date.isAfter(endDate)))
{
result = false;
}
else
{
result = true;
}
}
//
return result;
}
/**
* Checks if is matching.
*
* @param date
* the date
* @return true, if is matching
*/
public boolean isMatching(final LocalDateTime date)
{
boolean result;
if (date == null)
{
result = false;
}
else
{
if ((date.isBefore(this.start)) || (date.isAfter(this.end)))
{
result = false;
}
else
{
result = true;
}
}
//
return result;
}
/**
* Checks if is matching.
*
* @param timemark
* the timemark
* @return true, if is matching
*/
public boolean isMatching(final YearMonth yearMonth)
{
boolean result;
if (yearMonth == null)
{
result = false;
}
else
{
YearMonth startYearMonth = YearMonth.of(this.start.getYear(), this.start.getMonth());
YearMonth endYearMonth = YearMonth.of(this.end.getYear(), this.end.getMonth());
if ((yearMonth.isBefore(startYearMonth)) || (yearMonth.isAfter(endYearMonth)))
{
result = false;
}
else
{
result = true;
}
}
//
return result;
}
/**
* Checks if is matching.
*
* @param year
* the year
* @param week
* the week
* @return true, if is matching
*/
public boolean isMatching(final YearWeek yearWeek)
{
boolean result;
YearWeek startYearWeek = YearWeek.of(this.start.getYear(), this.start.get(WeekFields.ISO.weekOfYear()));
YearWeek endYearWeek = YearWeek.of(this.end.getYear(), this.end.get(WeekFields.ISO.weekOfYear()));
if ((yearWeek.isBefore(startYearWeek)) || (yearWeek.isAfter(endYearWeek)))
{
result = false;
}
else
{
result = true;
}
//
return result;
}
public void setEnd(final LocalDateTime end)
{
this.end = end;
}
public void setStart(final LocalDateTime start)
{
this.start = start;
}
}

View file

@ -0,0 +1,145 @@
/*
* 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.htmlize.probes;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class PathCounter.
*/
public class VisitCounter
{
private static Logger logger = LoggerFactory.getLogger(VisitCounter.class);
private String path;
private String timeMark;
private long counter;
/**
* Instantiates a new path counter.
*
* @param path
* the path
* @param timeMark
* the time mark
*/
public VisitCounter(final String path, final String timeMark)
{
this.path = path;
this.timeMark = timeMark;
this.counter = 0;
}
public long getCounter()
{
return this.counter;
}
public String getPath()
{
return this.path;
}
public String getTimeMark()
{
return this.timeMark;
}
/**
* Inc.
*/
public void inc()
{
this.counter += 1;
}
public void inc(final long value)
{
this.counter += value;
}
/**
* Checks if is date.
*
* @return true, if is date
*/
public boolean isDate()
{
boolean result;
Pattern pattern = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");
result = (pattern.matcher(this.timeMark).matches());
//
return result;
}
/**
* Checks if is year mark.
*
* @return true, if is year mark
*/
public boolean isYearMark()
{
boolean result;
Pattern pattern = Pattern.compile("^\\d{4}$");
result = (pattern.matcher(this.timeMark).matches());
//
return result;
}
/**
* Checks if is year week.
*
* @return true, if is year week
*/
public boolean isYearWeek()
{
boolean result;
Pattern pattern = Pattern.compile("^\\d{4}W\\d{2}$");
result = (pattern.matcher(this.timeMark).matches());
//
return result;
}
public void setCounter(final long counter)
{
this.counter = counter;
}
public void setPath(final String path)
{
this.path = path;
}
public void setTimeMark(final String timeMark)
{
this.timeMark = timeMark;
}
}

View file

@ -0,0 +1,167 @@
/*
* 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.htmlize.probes;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.extra.YearWeek;
import fr.devinsy.strings.StringSet;
/**
* The Class VisitCounters.
*/
public class VisitCounters extends HashMap<String, Visits>
{
private static final long serialVersionUID = 7081954620691577515L;
private static Logger logger = LoggerFactory.getLogger(VisitCounters.class);
private StringSet timeMarks;
/**
* Instantiates a new path counters.
*/
public VisitCounters()
{
super();
this.timeMarks = new StringSet();
}
/**
* Compute key.
*
* @param path
* the path
* @param timeMark
* the time mark
* @return the string
*/
public String computeKey(final HttpLog log)
{
String result;
result = String.format("%s--%s", log.getRemoteAddress(), log.getUserAgent().toString());
//
return result;
}
/**
* Gets the counters.
*
* @return the counters
*/
public PathCounters getCounters(final String prefix)
{
PathCounters result;
result = new PathCounters();
logger.info("timemark count={}", this.timeMarks.size());
for (String timemark : this.timeMarks)
{
long count = 0;
if (TimeMarkUtils.isDate(timemark))
{
LocalDate date = TimeMarkUtils.parseDate(timemark);
for (Visits visits : this.values())
{
count += visits.count(date);
}
}
else if (TimeMarkUtils.isYearMonth(timemark))
{
YearMonth yearMonth = TimeMarkUtils.parseYearMonth(timemark);
for (Visits visits : this.values())
{
count += visits.count(yearMonth);
}
}
else if (TimeMarkUtils.isYearWeek(timemark))
{
YearWeek yearWeek = TimeMarkUtils.parseYearWeek(timemark);
for (Visits visits : this.values())
{
count += visits.count(yearWeek);
}
}
else if (TimeMarkUtils.isYear(timemark))
{
int year = TimeMarkUtils.parseYear(timemark);
for (Visits visits : this.values())
{
count += visits.count(year);
}
}
logger.info("timemark/count = {}/{}", timemark, count);
result.inc(count, prefix, timemark);
}
logger.info("visits counters [{}]", result.size());
//
return result;
}
/**
* Put visit.
*
* @param log
* the log
*/
public void putVisit(final HttpLog log)
{
if (log != null)
{
String key = computeKey(log);
Visits visits = get(key);
if (visits == null)
{
visits = new Visits();
put(key, visits);
}
visits.add(log.getTime());
}
}
/**
* Store time marks.
*
* @param timemarks
* the timemarks
*/
public void storeTimeMarks(final String... timemarks)
{
for (String timemark : timemarks)
{
this.timeMarks.put(timemark);
}
}
}

View file

@ -0,0 +1,209 @@
/*
* 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.htmlize.probes;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.ArrayList;
import org.threeten.extra.YearWeek;
/**
* The Class Visits.
*/
public class Visits extends ArrayList<Visit>
{
private static final long serialVersionUID = 4172108458534266440L;
private static final int BORDER_MINUTES = 30;
/**
* Instantiates a new visits.
*/
public Visits()
{
super();
}
/**
* Adds the.
*
* @param date
* the date
*/
public void add(final LocalDateTime date)
{
boolean ended = false;
int index = 0;
while (!ended)
{
if (index < size())
{
Visit visit = get(index);
if (date.isBefore(visit.getStart().minusMinutes(BORDER_MINUTES)))
{
this.add(index, new Visit(date));
ended = true;
}
else if (date.isBefore(visit.getStart()))
{
visit.setStart(date);
if (index > 0)
{
Visit previous = get(index - 1);
if (previous.getEnd().isAfter(visit.getStart().minusMinutes(BORDER_MINUTES)))
{
visit.setStart(previous.getStart());
remove(index - 1);
}
}
ended = true;
}
else if (date.isAfter(visit.getEnd().plusMinutes(BORDER_MINUTES)))
{
index += 1;
}
else if (date.isAfter(visit.getEnd()))
{
visit.setEnd(date);
if (index + 1 < size())
{
Visit next = get(index - 1);
if (next.getStart().isBefore(visit.getEnd().plusMinutes(BORDER_MINUTES)))
{
visit.setEnd(next.getEnd());
remove(index + 1);
}
}
ended = true;
}
else
{
// Matching visit case.
ended = true;
}
}
else
{
add(new Visit(date));
ended = true;
}
}
}
/**
* Count.
*
* @param year
* the year
* @return the long
*/
public long count(final int year)
{
long result;
result = 0;
for (Visit visit : this)
{
if (visit.isMatching(year))
{
result += 1;
}
}
//
return result;
}
/**
* Count.
*
* @param date
* the date
* @return the long
*/
public long count(final LocalDate date)
{
long result;
result = 0;
for (Visit visit : this)
{
if (visit.isMatching(date))
{
result += 1;
}
}
//
return result;
}
/**
* Count.
*
* @param yearMonth
* the year month
* @return the long
*/
public long count(final YearMonth yearMonth)
{
long result;
result = 0;
for (Visit visit : this)
{
if (visit.isMatching(yearMonth))
{
result += 1;
}
}
//
return result;
}
/**
* Count.
*
* @param year
* the year
* @param week
* the week
* @return the long
*/
public long count(final YearWeek yearWeek)
{
long result;
result = 0;
for (Visit visit : this)
{
if (visit.isMatching(yearWeek))
{
result += 1;
}
}
//
return result;
}
}