517 lines
17 KiB
Java
517 lines
17 KiB
Java
/*
|
|
* 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.cli;
|
|
|
|
import java.io.File;
|
|
import java.time.LocalDateTime;
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.apache.commons.lang3.math.NumberUtils;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import fr.devinsy.statoolinfos.core.BotFilter;
|
|
import fr.devinsy.statoolinfos.core.StatoolInfos;
|
|
import fr.devinsy.statoolinfos.util.BuildInformation;
|
|
import fr.devinsy.statoolinfos.util.Chrono;
|
|
import fr.devinsy.statoolinfos.util.Files;
|
|
import fr.devinsy.statoolinfos.util.FilesUtils;
|
|
import fr.devinsy.strings.StringList;
|
|
|
|
/**
|
|
* The Class <code>StatoolInfosCLI</code> manages a Command Line Interface for
|
|
* StatoolInfos.
|
|
*
|
|
*/
|
|
public final class StatoolInfosCLI
|
|
{
|
|
private static Logger logger = LoggerFactory.getLogger(StatoolInfosCLI.class);
|
|
|
|
/**
|
|
* Instantiates a new statool infos CLI.
|
|
*/
|
|
private StatoolInfosCLI()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Convert path.
|
|
*
|
|
* @param path
|
|
* the path
|
|
* @return the files
|
|
*/
|
|
public static Files convertPath(final String path)
|
|
{
|
|
Files result;
|
|
|
|
result = new Files();
|
|
|
|
if (StringUtils.isNotBlank(path))
|
|
{
|
|
File input = new File(path);
|
|
|
|
if (input.exists())
|
|
{
|
|
if (input.isFile())
|
|
{
|
|
result.add(input);
|
|
}
|
|
else
|
|
{
|
|
for (File file : input.listFiles())
|
|
{
|
|
if ((file.isFile()) && (file.getName().endsWith(".conf")))
|
|
{
|
|
result.add(file);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.add(input);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Display help.
|
|
*/
|
|
public static void displayHelp()
|
|
{
|
|
StringList message = new StringList();
|
|
|
|
message.append("StatoolInfos CLI version ").appendln(BuildInformation.instance().version());
|
|
message.appendln("Usage:");
|
|
message.appendln(" statoolinfos [ -h | -help | --help ]");
|
|
message.appendln(" statoolinfos [ -v | -version | --version ]");
|
|
message.appendln();
|
|
message.appendln(" statoolinfos build <configurationfile> build property files from conf and input");
|
|
message.appendln(" statoolinfos clear <configurationfile> remove property files from conf");
|
|
message.appendln(" statoolinfos crawl <configurationfile> crawl all file from conf and input");
|
|
message.appendln(" statoolinfos format <fileordirectory> format property files in tiny way");
|
|
message.appendln(" statoolinfos htmlize <configurationfile> generate web pages from conf");
|
|
message.appendln(" statoolinfos probe OPTION [<directory>|<configurationfile>] generate metrics files from conf");
|
|
message.appendln(" OPTION = [-full|-today|-previousday|-NN] with NN a day count");
|
|
message.appendln(" statoolinfos tagdate <fileordirectory> update the file.datetime file");
|
|
message.appendln(" statoolinfos uptime <configurationfile> update uptime journal");
|
|
message.appendln();
|
|
message.appendln(" statoolinfos list ip [-bot|-nobot] <fileordirectory> generate ip list from http log file");
|
|
message.appendln(" statoolinfos list ua [-bot|-nobot] <fileordirectory> generate user agent list from http log file");
|
|
message.appendln(" statoolinfos list visitors [-bot|-nobot] <fileordirectory> generate visitors (ip+ua) list from http log file");
|
|
message.appendln(" statoolinfos stat ip [-bot|-nobot] <fileordirectory> generate stats about ip from http log file");
|
|
message.appendln(" statoolinfos stat ua [-bot|-nobot] <fileordirectory> generate stats about user agent from http log file");
|
|
message.appendln(" statoolinfos stat visitors [-bot|-nobot] <fileordirectory> generate stats about visitors (ip+ua) from http log file");
|
|
|
|
System.out.print(message.toString());
|
|
}
|
|
|
|
/**
|
|
* Display version.
|
|
*/
|
|
public static void displayVersion()
|
|
{
|
|
StringList message = new StringList();
|
|
|
|
message.appendln(BuildInformation.instance().version());
|
|
|
|
System.out.print(message.toString());
|
|
}
|
|
|
|
/**
|
|
* Checks if is matching.
|
|
*
|
|
* @param args
|
|
* the args
|
|
* @param regexps
|
|
* the regexps
|
|
* @return true, if is matching
|
|
*/
|
|
public static boolean isMatching(final String[] args, final String... regexps)
|
|
{
|
|
boolean result;
|
|
|
|
if ((args.length == 0) && (regexps == null))
|
|
{
|
|
result = true;
|
|
}
|
|
else if ((args.length != 0) && (regexps == null))
|
|
{
|
|
result = false;
|
|
}
|
|
else if (args.length != regexps.length)
|
|
{
|
|
result = false;
|
|
}
|
|
else
|
|
{
|
|
boolean ended = false;
|
|
int index = 0;
|
|
result = false;
|
|
while (!ended)
|
|
{
|
|
if (index < args.length)
|
|
{
|
|
String arg = args[index];
|
|
String regexp = regexps[index];
|
|
|
|
if (arg.matches(regexp))
|
|
{
|
|
index += 1;
|
|
}
|
|
else
|
|
{
|
|
ended = true;
|
|
result = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ended = true;
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Parses the log filter option.
|
|
*
|
|
* @param source
|
|
* the source
|
|
* @return the log filter
|
|
*/
|
|
private static BotFilter parseLogFilterOption(final String source)
|
|
{
|
|
BotFilter result;
|
|
|
|
if (StringUtils.equals(source, "-all"))
|
|
{
|
|
result = BotFilter.ALL;
|
|
}
|
|
else if (StringUtils.equals(source, "-bot"))
|
|
{
|
|
result = BotFilter.BOT;
|
|
}
|
|
else if (StringUtils.equals(source, "-nobot"))
|
|
{
|
|
result = BotFilter.NOBOT;
|
|
}
|
|
else
|
|
{
|
|
result = null;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* This method launch CLI.
|
|
*
|
|
* @param args
|
|
* necessary arguments
|
|
*/
|
|
public static void run(final String[] args)
|
|
{
|
|
// Set default catch.
|
|
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
|
|
{
|
|
@Override
|
|
public void uncaughtException(final Thread thread, final Throwable exception)
|
|
{
|
|
String message;
|
|
if (exception instanceof OutOfMemoryError)
|
|
{
|
|
message = "Java ran out of memory!\n\n";
|
|
}
|
|
else
|
|
{
|
|
message = String.format("An error occured: %1s(%2s)", exception.getClass(), exception.getMessage());
|
|
}
|
|
|
|
logger.error("uncaughtException ", exception);
|
|
logger.error(message);
|
|
logger.info("Oups, an unexpected error occured. Please try again.");
|
|
}
|
|
});
|
|
|
|
logger.debug("{} StatoolInfos call: {}", LocalDateTime.now(), new StringList(args).toStringSeparatedBy(" "));
|
|
|
|
if (isMatching(args))
|
|
{
|
|
logger.info("No parameter.");
|
|
displayHelp();
|
|
}
|
|
else if (isMatching(args, "(-h|--h|--help)"))
|
|
{
|
|
displayHelp();
|
|
}
|
|
else if (isMatching(args, "(-v|-version|--version)"))
|
|
{
|
|
displayVersion();
|
|
}
|
|
else if (isMatching(args, "build", "\\s*.+\\.conf\\s*"))
|
|
{
|
|
File configurationFile = new File(StringUtils.trim(args[1]));
|
|
try
|
|
{
|
|
StatoolInfos.build(configurationFile);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.error("Error with [{}]: {}", configurationFile.getAbsoluteFile(), exception.getMessage());
|
|
}
|
|
}
|
|
else if (isMatching(args, "clear", "\\s*.+\\.conf\\s*"))
|
|
{
|
|
File configurationFile = new File(StringUtils.trim(args[1]));
|
|
try
|
|
{
|
|
StatoolInfos.clear(configurationFile);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.error("Error with [{}]: {}", configurationFile.getAbsoluteFile(), exception.getMessage());
|
|
}
|
|
}
|
|
else if (isMatching(args, "crawl", "\\s*.+\\.conf\\s*"))
|
|
{
|
|
Chrono chrono = new Chrono().start();
|
|
|
|
File configurationFile = new File(StringUtils.trim(args[1]));
|
|
try
|
|
{
|
|
StatoolInfos.crawl(configurationFile);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.error("Error with [{}]: {}", configurationFile.getAbsoluteFile(), exception.getMessage());
|
|
exception.printStackTrace();
|
|
}
|
|
System.out.println(chrono.format());
|
|
}
|
|
else if (isMatching(args, "format", "\\s*.+\\s*"))
|
|
{
|
|
Files inputs = FilesUtils.searchEndingWith(new File(args[1]), ".properties");
|
|
for (File input : inputs)
|
|
{
|
|
try
|
|
{
|
|
StatoolInfos.format(input);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.error("Error with [{}]: {}", input.getAbsoluteFile(), exception.getMessage());
|
|
exception.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
else if (isMatching(args, "htmlize", "\\s*.+\\.conf\\s*"))
|
|
{
|
|
Chrono chrono = new Chrono().start();
|
|
File configurationFile = new File(StringUtils.trim(args[1]));
|
|
try
|
|
{
|
|
StatoolInfos.htmlize(configurationFile);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.error("Error with [{}]: {}", configurationFile.getAbsoluteFile(), exception.getMessage());
|
|
exception.printStackTrace();
|
|
}
|
|
System.out.println(chrono.format());
|
|
}
|
|
else if (isMatching(args, "list", "ip", "\\s*\\S+\\s*"))
|
|
{
|
|
File source = new File(args[2]);
|
|
|
|
StatoolInfos.listIps(source, BotFilter.ALL);
|
|
}
|
|
else if (isMatching(args, "list", "ip", "(-all|-bot|-nobot)", "\\s*\\S+\\s*"))
|
|
{
|
|
BotFilter filter = parseLogFilterOption(args[2]);
|
|
File source = new File(args[3]);
|
|
|
|
StatoolInfos.listIps(source, filter);
|
|
}
|
|
else if (isMatching(args, "list", "(useragent|ua)", "\\s*\\S+\\s*"))
|
|
{
|
|
File source = new File(args[2]);
|
|
|
|
StatoolInfos.listUserAgents(source, BotFilter.ALL);
|
|
}
|
|
else if (isMatching(args, "list", "(useragent|ua)", "(-all|-bot|-nobot)", "\\s*\\S+\\s*"))
|
|
{
|
|
BotFilter filter = parseLogFilterOption(args[2]);
|
|
File source = new File(args[3]);
|
|
|
|
StatoolInfos.listUserAgents(source, filter);
|
|
}
|
|
else if (isMatching(args, "list", "visitors", "\\s*\\S+\\s*"))
|
|
{
|
|
File source = new File(args[2]);
|
|
|
|
StatoolInfos.listVisitors(source, BotFilter.ALL);
|
|
}
|
|
else if (isMatching(args, "list", "visitors", "(-all|-bot|-nobot)", "\\s*\\S+\\s*"))
|
|
{
|
|
BotFilter filter = parseLogFilterOption(args[2]);
|
|
File source = new File(args[3]);
|
|
|
|
StatoolInfos.listVisitors(source, filter);
|
|
}
|
|
else if (isMatching(args, "probe", "\\S*(-full|-today|-previousday|-\\d+)\\s*", "\\s*.+\\s*"))
|
|
{
|
|
File configurationFile = new File(StringUtils.trim(args[2]));
|
|
|
|
String filter = StringUtils.trim(args[1]);
|
|
int dayCountFilter;
|
|
if (filter.equals("-full"))
|
|
{
|
|
dayCountFilter = -1;
|
|
}
|
|
else if (filter.equals("-today"))
|
|
{
|
|
dayCountFilter = 0;
|
|
}
|
|
else if (filter.equals("-previousday"))
|
|
{
|
|
dayCountFilter = 1;
|
|
}
|
|
else
|
|
{
|
|
dayCountFilter = -1 * NumberUtils.toInt(filter);
|
|
}
|
|
|
|
try
|
|
{
|
|
Files inputs = FilesUtils.searchEndingWith(configurationFile, ".conf");
|
|
if (inputs.isEmpty())
|
|
{
|
|
System.out.println("No configuration file found.");
|
|
}
|
|
else
|
|
{
|
|
for (File input : inputs)
|
|
{
|
|
try
|
|
{
|
|
System.out.println("Probing [" + input + "] with day count filter " + dayCountFilter);
|
|
StatoolInfos.probe(input, dayCountFilter);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.error("Error with [{}]: {}", input.getAbsoluteFile(), exception.getMessage());
|
|
exception.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.error("Error with [{}]: {}", configurationFile.getAbsoluteFile(), exception.getMessage());
|
|
exception.printStackTrace();
|
|
}
|
|
}
|
|
else if (isMatching(args, "stat", "ip", "\\s*\\S+\\s*"))
|
|
{
|
|
File source = new File(args[2]);
|
|
|
|
StatoolInfos.statIps(source, BotFilter.ALL);
|
|
}
|
|
else if (isMatching(args, "stat", "ip", "(-all|-bot|-nobot)", "\\s*\\S+\\s*"))
|
|
{
|
|
BotFilter filter = parseLogFilterOption(args[2]);
|
|
File source = new File(args[3]);
|
|
|
|
StatoolInfos.statIps(source, filter);
|
|
}
|
|
else if (isMatching(args, "stat", "(useragent|ua)", "\\s*\\S+\\s*"))
|
|
{
|
|
File source = new File(args[2]);
|
|
StatoolInfos.statUserAgents(source, BotFilter.ALL);
|
|
}
|
|
else if (isMatching(args, "stat", "(useragent|ua)", "(-all|-bot|-nobot)", "\\s*\\S+\\s*"))
|
|
{
|
|
BotFilter filter = parseLogFilterOption(args[2]);
|
|
File source = new File(args[3]);
|
|
|
|
StatoolInfos.statUserAgents(source, filter);
|
|
}
|
|
else if (isMatching(args, "stat", "visitors", "\\s*\\S+\\s*"))
|
|
{
|
|
File source = new File(args[2]);
|
|
|
|
StatoolInfos.statVisitors(source, BotFilter.ALL);
|
|
}
|
|
else if (isMatching(args, "stat", "visitors", "(-all|-bot|-nobot)", "\\s*\\S+\\s*"))
|
|
{
|
|
BotFilter filter = parseLogFilterOption(args[2]);
|
|
File source = new File(args[3]);
|
|
|
|
StatoolInfos.statVisitors(source, filter);
|
|
}
|
|
else if (isMatching(args, "tagdate", "\\s*.+\\s*"))
|
|
{
|
|
Files inputs = FilesUtils.searchEndingWith(new File(args[1]), ".properties");
|
|
for (File input : inputs)
|
|
{
|
|
try
|
|
{
|
|
StatoolInfos.tagDate(input);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.error("Error with [{}]: {}", input.getAbsoluteFile(), exception.getMessage());
|
|
exception.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
else if (isMatching(args, "uptime", "\\s*.+\\.conf\\s*"))
|
|
{
|
|
Chrono chrono = new Chrono().start();
|
|
|
|
File configurationFile = new File(StringUtils.trim(args[1]));
|
|
try
|
|
{
|
|
StatoolInfos.uptime(configurationFile);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
logger.error("Error with [{}]: {}", configurationFile.getAbsoluteFile(), exception.getMessage());
|
|
exception.printStackTrace();
|
|
}
|
|
System.out.println(chrono.format());
|
|
}
|
|
else
|
|
{
|
|
System.out.println("Bad usage.");
|
|
displayHelp();
|
|
}
|
|
}
|
|
}
|