Added anonymize feature.

This commit is contained in:
Christian P. MOMON 2021-04-22 02:36:11 +02:00
parent a0d78392fc
commit 2ff492fc83
20 changed files with 2116 additions and 51 deletions

View File

@ -21,5 +21,6 @@
<classpathentry kind="lib" path="lib/commons-text-1.9.jar" sourcepath="lib/commons-text-1.9-sources.jar"/>
<classpathentry kind="lib" path="lib/devinsy-strings-0.11.3.jar" sourcepath="lib/devinsy-strings-0.11.3-sources.zip"/>
<classpathentry kind="lib" path="lib/threeten-extra-1.5.0.jar" sourcepath="lib/threeten-extra-1.5.0-sources.jar"/>
<classpathentry kind="lib" path="lib/devinsy-cmdexec-0.11.1.jar" sourcepath="lib/devinsy-cmdexec-0.11.1-sources.zip"/>
<classpathentry kind="output" path="bin"/>
</classpath>

Binary file not shown.

Binary file not shown.

View File

@ -3,7 +3,7 @@
# Java check.
javaCheck=`which java`
if [[ "$javaCheck" =~ ^/.* ]]; then
echo "Java requirement............... OK"
#echo "Java requirement............... OK"
java -jar "$(dirname "$0")"/logar.jar $@
else
echo "Java requirement............... MISSING"

223
src/anonymizer/AnonMap.java Normal file
View File

@ -0,0 +1,223 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package anonymizer;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.strings.StringSet;
/**
* The Class AnonMap.
*/
public final class AnonMap
{
private static Logger logger = LoggerFactory.getLogger(AnonMap.class);
private HashMap<String, String> map;
private HashMap<String, String> unmap;
/**
* Instantiates a new anon map.
*/
public AnonMap()
{
this.map = new HashMap<String, String>();
this.unmap = new HashMap<String, String>();
}
/**
* Adds the all.
*
* @param source
* the source
*/
public void addAll(final AnonMap source)
{
for (String key : source.getKeys())
{
String value = source.get(key);
this.map.put(key, value);
this.unmap.put(value, key);
}
}
/**
* Gets the ip.
*
* @param ip
* the ip
* @return the ip
*/
public String anonymizeIp(final String ip)
{
String result;
if (ip == null)
{
result = null;
}
else
{
result = this.map.get(ip);
if (result == null)
{
boolean ended = false;
while (!ended)
{
if (ip.contains(":"))
{
result = Ipv6Generator.random(ip);
}
else
{
result = Ipv4Generator.random(ip);
}
// Check it does not already exist.
if ((this.map.get(result) == null) && (this.unmap.get(result) == null))
{
this.map.put(ip, result);
this.unmap.put(ip, result);
ended = true;
}
}
}
}
//
return result;
}
/**
* Gets the user.
*
* @param user
* the user
* @return the user
*/
public String anonymizeUser(final String user)
{
String result;
if (user == null)
{
result = null;
}
else if (user.equals("-"))
{
result = user;
}
else
{
result = this.map.get(user);
if (result == null)
{
boolean ended = false;
while (!ended)
{
result = UserGenerator.random(user);
// Check it does not already exist.
if ((this.map.get(result) == null) && (this.unmap.get(result) == null))
{
this.map.put(user, result);
this.unmap.put(user, result);
ended = true;
}
}
}
}
//
return result;
}
/**
* Gets the.
*
* @param key
* the key
* @return the string
*/
public String get(final String key)
{
String result;
if (key == null)
{
result = null;
}
else
{
result = this.map.get(key);
}
//
return result;
}
/**
* Gets the keys.
*
* @return the keys
*/
public StringSet getKeys()
{
StringSet result;
result = new StringSet(this.map.keySet());
//
return result;
}
/**
* Put.
*
* @param key
* the key
* @param value
* the value
*/
public void put(final String key, final String value)
{
this.map.put(key, value);
}
/**
* Size.
*
* @return the int
*/
public int size()
{
int result;
result = this.map.size();
//
return result;
}
}

View File

@ -0,0 +1,157 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package anonymizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class AnonMapFile.
*/
public final class AnonMapFile
{
private static Logger logger = LoggerFactory.getLogger(AnonMapFile.class);
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
/**
* Instantiates a new anon map file.
*/
private AnonMapFile()
{
}
/**
* Load.
*
* @param source
* the source
* @return the anon map
*/
public static AnonMap load(final File source)
{
AnonMap result;
result = new AnonMap();
if ((source != null) && (source.exists()))
{
BufferedReader in = null;
try
{
if (source.getName().endsWith(".gz"))
{
in = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(source))));
}
else
{
in = new BufferedReader(new InputStreamReader(new FileInputStream(source), DEFAULT_CHARSET_NAME));
}
boolean ended = false;
while (!ended)
{
String key = in.readLine();
String value = in.readLine();
if (key == null)
{
ended = true;
}
else
{
result.put(key, value);
}
}
}
catch (IOException exception)
{
exception.printStackTrace();
}
finally
{
IOUtils.closeQuietly(in);
}
}
//
return result;
}
/**
* Save.
*
* @param source
* the source
* @param map
* the map
*/
public static void save(final File target, final AnonMap map)
{
if (target == null)
{
throw new IllegalArgumentException("Null parameter source.");
}
else if (map == null)
{
throw new IllegalArgumentException("Null parameter map.");
}
else
{
PrintWriter out = null;
try
{
if (target.getName().endsWith(".gz"))
{
out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(target)));
}
else
{
out = new PrintWriter(new FileOutputStream(target));
}
for (String key : map.getKeys())
{
out.println(key);
out.println(map.get(key));
}
}
catch (IOException exception)
{
System.err.println("Error with file [" + target.getAbsolutePath() + "]");
exception.printStackTrace();
}
finally
{
IOUtils.closeQuietly(out);
}
}
}
}

View File

@ -0,0 +1,199 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package anonymizer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.format.DateTimeParseException;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.io.IOUtils;
import org.april.logar.util.LineIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.logar.app.log.Log;
import fr.devinsy.logar.app.log.LogUtils;
/**
* The Class Anonymizer.
*/
public final class Anonymizer
{
private static Logger logger = LoggerFactory.getLogger(Anonymizer.class);
private AnonMap map;
/**
* Instantiates a new anonymizer.
*/
public Anonymizer()
{
this.map = new AnonMap();
}
/**
* Anonymize.
*
* @param source
* the source
* @param target
* the target
*/
public void anonymize(final File source)
{
if (source == null)
{
throw new IllegalArgumentException("Null parameter.");
}
else if (!source.isFile())
{
throw new IllegalArgumentException("Parameter is not a file.");
}
else
{
System.out.println("== Anonymize log for [" + source.getName() + "]");
File target;
if (source.getName().endsWith(".log.gz"))
{
target = new File(source.getParentFile(), source.getName().replace(".log.gz", "-anon.log.gz"));
}
else
{
target = new File(source.getParentFile(), source.getName().replace(".log", "-anon.log"));
}
PrintWriter out = null;
try
{
LineIterator iterator = new LineIterator(source);
out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(target)));
while (iterator.hasNext())
{
String line = iterator.next();
try
{
Log log = LogUtils.parseAccessLog(line);
// logger.info("line={}", line);
// logger.info("log =[{}][{}][{}]", log.getIp(),
// log.getUser(), log.getDatetime());
Log anon = anonymize(log);
// logger.info("anon=[{}][{}][{}]", anon.getIp(),
// anon.getUser(), anon.getDatetime());
// logger.info("anon={}", anon);
out.println(anon);
}
catch (IllegalArgumentException exception)
{
System.out.println("Bad format line: " + line);
exception.printStackTrace();
}
catch (DateTimeParseException exception)
{
System.out.println("Bad datetime format: " + line);
}
}
}
catch (IOException exception)
{
System.err.println("Error with file [" + source.getAbsolutePath() + "]");
exception.printStackTrace();
}
finally
{
IOUtils.closeQuietly(out);
}
}
}
/**
* Anonymize.
*
* @param log
* the log
* @return the log
*/
public Log anonymize(final Log log)
{
Log result;
String anonIp = this.map.anonymizeIp(log.getIp());
String anonUser = this.map.anonymizeUser(log.getUser());
String line = log.getLine().replace(log.getIp(), anonIp);
if (!log.getUser().equals("-"))
{
line = line.replace(log.getUser(), anonUser);
}
result = new Log(line, log.getDatetime(), anonIp, anonUser);
//
return result;
}
/**
* Gets the map table.
*
* @return the map table
*/
public AnonMap getMapTable()
{
AnonMap result;
result = this.map;
//
return result;
}
/**
* Inits the map.
*
* @param source
* the source
*/
public void loadMapTable(final File source)
{
if (source != null)
{
this.map.addAll(AnonMapFile.load(source));
}
}
/**
* Save map table.
*
* @param target
* the target
*/
public void SaveMapTable(final File target)
{
if (target != null)
{
AnonMapFile.save(target, this.map);
}
}
}

View File

@ -0,0 +1,252 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package anonymizer;
import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class RandomIpv4Generator.
*/
public final class Ipv4Generator
{
private static Logger logger = LoggerFactory.getLogger(Ipv4Generator.class);
/**
* Instantiates a new random ipv 4 generator.
*/
private Ipv4Generator()
{
}
/**
* Gets the ipv 4 max length part.
*
* @param length
* the length (1..12)
* @param column
* the column (4...1)
* @return the ipv 4 max length part
*/
public static int getIpv4MaxLengthPart(final int length, final int column)
{
int result;
if ((length < 1) || (length > 12))
{
throw new IllegalArgumentException("Bad length value: " + length);
}
else if ((column < 1) || (column > 12))
{
throw new IllegalArgumentException("Bad column value:" + column);
}
else
{
final int[] col4 = { 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3 };
final int[] col3 = { 0, 0, 1, 2, 3, 3, 3, 3, 3, 0, 0, 0 };
final int[] col2 = { 0, 1, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0 };
final int[] col1 = { 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
final int[][] table = { col1, col2, col3, col4 };
result = table[column - 1][length - 1];
if (result == 0)
{
throw new IllegalArgumentException(String.format("Zero detected (%d, %d).", length, column));
}
}
//
return result;
}
/**
* Gets the ipv 4 max value part.
*
* @param length
* the length
* @param column
* the column
* @return the ipv 4 max value part
*/
public static int getIpv4MaxValuePart(final int length, final int column)
{
int result;
int max = getIpv4MaxLengthPart(length, column);
switch (max)
{
case 1:
result = 9;
break;
case 2:
result = 99;
break;
case 3:
result = 255;
break;
default:
throw new IllegalArgumentException("Bad value: " + max);
}
//
return result;
}
/**
* Gets the ipv 4 min length part.
*
* @param length
* the length (1..12)
* @param column
* the column (4...1)
* @return the ipv 4 min length part
*/
public static int getIpv4MinLengthPart(final int length, final int column)
{
int result;
if ((length < 1) || (length > 12))
{
throw new IllegalArgumentException("Bad length value: " + length);
}
else if ((column < 1) || (column > 12))
{
throw new IllegalArgumentException("Bad column value:" + column);
}
else
{
final int[] col4 = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 3 };
final int[] col3 = { 0, 0, 1, 1, 1, 1, 1, 2, 3, 0, 0, 0 };
final int[] col2 = { 0, 1, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0 };
final int[] col1 = { 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
final int[][] table = { col1, col2, col3, col4 };
result = table[column - 1][length - 1];
if (result == 0)
{
throw new IllegalArgumentException(String.format("Zero detected (%d, %d).", length, column));
}
}
//
return result;
}
public static int getIpv4MinValuePart(final int length, final int column)
{
int result;
int max = getIpv4MinLengthPart(length, column);
switch (max)
{
case 1:
result = 0;
break;
case 2:
result = 10;
break;
case 3:
result = 100;
break;
default:
throw new IllegalArgumentException("Bad value: " + max);
}
//
return result;
}
/**
* Generates a ipv4 of a fixed length.
*
* @param length
* the length
* @return the string
*/
public static String random(final int length)
{
String result;
if ((length < 7) || (length > 15))
{
throw new IllegalArgumentException("Bad parameter: " + length);
}
else
{
int size = length - 3;
int a = (int) RandomUtils.nextLong(getIpv4MinValuePart(size, 4), getIpv4MaxValuePart(size, 4) + 1);
size -= String.valueOf(a).length();
int b = (int) RandomUtils.nextLong(getIpv4MinValuePart(size, 3), getIpv4MaxValuePart(size, 3) + 1);
size -= String.valueOf(b).length();
int c = (int) RandomUtils.nextLong(getIpv4MinValuePart(size, 2), getIpv4MaxValuePart(size, 2) + 1);
size -= String.valueOf(c).length();
int d = (int) RandomUtils.nextLong(getIpv4MinValuePart(size, 1), getIpv4MaxValuePart(size, 1) + 1);
size -= String.valueOf(d).length();
result = String.format("%d.%d.%d.%d", a, b, c, d);
}
//
return result;
}
/**
* Generates a ipv4 with the same length than the parameter.
*
* @param ip
* the source
* @return the string
*/
public static String random(final String ip)
{
String result;
if (ip == null)
{
result = null;
}
else
{
result = random(ip.length());
if (result.equals(ip))
{
random(ip);
}
}
//
return result;
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package anonymizer;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class RandomIpv6Generator.
*/
public final class Ipv6Generator
{
private static Logger logger = LoggerFactory.getLogger(Ipv6Generator.class);
/**
* Instantiates a new random ipv 6 generator.
*/
private Ipv6Generator()
{
}
/**
* Random.
*
* @param ip
* the source
* @return the string
*/
public static String random(final String ip)
{
String result;
if (ip == null)
{
result = null;
}
else
{
StringBuffer buffer = new StringBuffer(ip.length());
for (int index = 0; index < ip.length(); index++)
{
char c = ip.charAt(index);
if (c == ':')
{
buffer.append(c);
}
else
{
buffer.append(RandomStringUtils.random(1, "0123456789abcdef"));
}
}
result = buffer.toString();
if (result.equals(ip))
{
random(ip);
}
}
//
return result;
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package anonymizer;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class RandomUserGenerator.
*/
public final class UserGenerator
{
private static Logger logger = LoggerFactory.getLogger(UserGenerator.class);
/**
* Instantiates a new random user generator.
*/
private UserGenerator()
{
}
/**
* Random.
*
* @param length
* the length
* @return the string
*/
public static String random(final int length)
{
String result;
if (length < 0)
{
throw new IllegalArgumentException("Bad parameter: " + length);
}
else
{
result = RandomStringUtils.random(length);
}
//
return result;
}
/**
* Random.
*
* @param source
* the source
* @return the string
*/
public static String random(final String source)
{
String result;
if (source == null)
{
result = null;
}
else if (source.equals("-"))
{
result = source;
}
else
{
result = RandomStringUtils.random(source.length(), "abcdefghijklmnopqrstuvwxyz");
}
//
return result;
}
}

View File

@ -34,10 +34,14 @@ import java.util.zip.GZIPOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.april.logar.util.Files;
import org.april.logar.util.FilesUtils;
import org.april.logar.util.LineIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import anonymizer.Anonymizer;
import fr.devinsy.logar.app.log.LogUtils;
/**
* The Class Logar.
*/
@ -45,9 +49,6 @@ public final class Logar
{
private static Logger logger = LoggerFactory.getLogger(Logar.class);
public static Pattern nginxAccessLogLinePatternFull = Pattern.compile(
"^(?<remoteAddress>[a-zA-F0-9\\\\:\\\\.]+) - (?<remoteUser>\\S+) \\[(?<time>[^\\]]+)\\] \"(?<request>[^\"]*)\" (?<status>\\d+) (?<bodyBytesSent>\\d+) \"(?<referer>[^\"]*)\" \"(?<userAgent>[^\"]*)\".*$");
public static Pattern nginxAccessLogLinePattern = Pattern.compile("^\\S+ - [^\\[]+ \\[(?<time>[^\\]]+)\\] .*$");
public static Pattern nginxErrorLogLinePattern = Pattern.compile("^(?<time>\\S+\\s\\S+)\\s\\[(?<level>[^\\]]*)\\]\\s.*$");
@ -66,9 +67,55 @@ public final class Logar
* @param target
* the target
*/
public static void anonymize(final File source, final File target)
public static void anonymize(final File source)
{
System.out.println("En cours de développement…");
anonymize(source, null);
}
/**
* Anonymize.
*
* @param source
* the source
* @param target
* the target
*/
public static void anonymize(final File source, final File mapFile)
{
if (source == null)
{
throw new IllegalArgumentException("Null source file.");
}
else if (!source.exists())
{
throw new IllegalArgumentException("Source file does not exist.");
}
else
{
Anonymizer anonymizer = new Anonymizer();
anonymizer.loadMapTable(mapFile);
System.out.println("Table size=" + anonymizer.getMapTable().size());
Files files = FilesUtils.searchFileRecursively(source, ".log", ".log.gz").removeContaining("-anon.log");
logger.info("file count={}", files.size());
for (File file : files)
{
if (file.getName().contains("access"))
{
anonymizer.anonymize(file);
}
else if (file.getName().contains("error"))
{
//
}
}
if (mapFile != null)
{
System.out.println("Table size=" + anonymizer.getMapTable().size());
anonymizer.SaveMapTable(mapFile);
}
}
}
/**
@ -294,6 +341,163 @@ public final class Logar
}
}
/**
* Check.
*
* @param source
* the source
*/
public static void check(final File source)
{
if (source != null)
{
if (source.isFile())
{
if (source.getName().contains("access"))
{
checkAccessFiles(source);
}
else if (source.getName().contains("error"))
{
checkErrorFiles(source);
}
}
else
{
for (File file : Files.of(source).removeHidden().sortByName())
{
if (file.isDirectory())
{
check(file);
}
else if (StringUtils.endsWithAny(file.getName(), ".log", ".gz", ".1", ".2"))
{
check(file);
}
}
}
}
}
/**
* Check access files.
*
* @param file
* the source
*/
public static void checkAccessFiles(final File file)
{
if (file == null)
{
throw new IllegalArgumentException("Null parameter.");
}
else if (!file.isFile())
{
throw new IllegalArgumentException("Parameter is not a file.");
}
else
{
System.out.println("== Check access log for [" + file.getName() + "]");
int lineCount = 0;
int badLineCount = 0;
try
{
LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
{
String line = iterator.next();
lineCount += 1;
try
{
LogUtils.parseAccessLog(line).getDatetime();
}
catch (IllegalArgumentException exception)
{
System.out.println("Bad format line: " + line);
badLineCount += 1;
exception.printStackTrace();
}
catch (DateTimeParseException exception)
{
System.out.println("Bad datetime format: " + line);
badLineCount += 1;
}
}
}
catch (IOException exception)
{
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
exception.printStackTrace();
}
if (badLineCount > 0)
{
System.out.println("Bad line count: " + badLineCount + "/" + lineCount);
}
}
}
/**
* Check error files.
*
* @param file
* the file
*/
public static void checkErrorFiles(final File file)
{
if (file == null)
{
throw new IllegalArgumentException("Null parameter.");
}
else if (!file.isFile())
{
throw new IllegalArgumentException("Parameter is not a file.");
}
else
{
System.out.println("== Check error log for [" + file.getName() + "]");
int lineCount = 0;
int badLineCount = 0;
try
{
LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
{
String line = iterator.next();
lineCount += 1;
try
{
LogUtils.parseErrorLog(line).getDatetime();
}
catch (IllegalArgumentException exception)
{
System.out.println("Bad format line: " + line);
badLineCount += 1;
}
catch (DateTimeParseException exception)
{
System.out.println("Bad datetime format: " + line);
badLineCount += 1;
}
}
}
catch (IOException exception)
{
System.err.println("Error with file [" + file.getAbsolutePath() + "]");
exception.printStackTrace();
}
if (badLineCount > 0)
{
System.out.println("Bad line count: " + badLineCount + "/" + lineCount);
}
}
}
/**
* Check sort.
*
@ -306,26 +510,22 @@ public final class Logar
if (source != null)
{
if (source.isFile())
{
if (source.getName().contains("access"))
{
checkSortForAccessFiles(source);
}
else if (source.getName().contains("error"))
{
checkSortForErrorFiles(source);
}
}
else
{
for (File file : Files.of(source).removeHidden().sortByName())
{
if (file.isDirectory())
{
checkSort(file);
}
else if (file.getName().contains("access"))
{
checkSortForAccessFiles(file);
}
else if (file.getName().contains("error"))
{
checkSortForErrorFiles(file);
}
}
}
}
}
@ -358,21 +558,18 @@ public final class Logar
{
String line = iterator.next();
lineCount += 1;
LocalDateTime date = getLogDate(line);
if (currentDate == null)
LocalDateTime date = LogUtils.parseAccessLog(line).getDatetime();
if ((currentDate != null) && (date.isBefore(currentDate)))
{
currentDate = date;
}
else if (date.isBefore(currentDate))
{
System.out.println(String.format("detected line: %d %s", lineCount, currentDate.toString()));
System.out.println(String.format("break detected: %d %s", lineCount, currentDate.toString()));
badLineCount += 1;
}
currentDate = date;
}
if (badLineCount > 0)
{
System.out.println("Bad line count: " + badLineCount);
System.out.println("Bad line count: " + badLineCount + "/" + lineCount);
}
}
}
@ -382,8 +579,9 @@ public final class Logar
*
* @param source
* the source
* @throws IOException
*/
public static void checkSortForErrorFiles(final File file)
public static void checkSortForErrorFiles(final File file) throws IOException
{
if (file == null)
{
@ -396,40 +594,110 @@ public final class Logar
else
{
System.out.println("== Check sort for [" + file.getName() + "]");
LocalDateTime currentDate = null;
int lineCount = 0;
int badLineCount = 0;
LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
{
String line = iterator.next();
lineCount += 1;
LocalDateTime date = LogUtils.parseErrorLog(line).getDatetime();
if ((currentDate != null) && (date.isBefore(currentDate)))
{
System.out.println(String.format("break detected: %d %s", lineCount, currentDate.toString()));
badLineCount += 1;
}
currentDate = date;
}
if (badLineCount > 0)
{
System.out.println("Bad line count: " + badLineCount + "/" + lineCount);
}
}
}
/**
* Gets the log date.
* Sort.
*
* @param line
* the line
* @return the log date
* @param source
* the source
* @throws IOException
* Signals that an I/O exception has occurred.
*/
private static LocalDateTime getLogDate(final String line)
public static void sort(final File source) throws IOException
{
LocalDateTime result;
Matcher matcher = nginxAccessLogLinePattern.matcher(line);
if (matcher.matches())
if (source != null)
{
String value = matcher.group("time");
try
if (source.isFile())
{
result = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z").withLocale(Locale.ENGLISH));
if (source.getName().contains("access"))
{
sortAccessFiles(source);
}
catch (DateTimeParseException exception)
else if (source.getName().contains("error"))
{
throw new IllegalArgumentException("Bad format time [" + value + "]");
sortErrorFiles(source);
}
}
else
{
throw new IllegalArgumentException("Bad format line [" + line + "]");
for (File file : Files.of(source).removeHidden().sortByName())
{
sort(file);
}
}
}
}
//
return result;
/**
* Sort access files.
*
* @param file
* the file
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static void sortAccessFiles(final File file) throws IOException
{
if (file == null)
{
throw new IllegalArgumentException("Null parameter [source]");
}
else if (!file.isFile())
{
throw new IllegalArgumentException("Source parameter is not a file.");
}
else
{
System.out.println("== Sort for [" + file.getName() + "]");
LogUtils.sortAccessLog(file);
}
}
/**
* Sort error files.
*
* @param file
* the file
* @throws IOException
*/
public static void sortErrorFiles(final File file) throws IOException
{
if (file == null)
{
throw new IllegalArgumentException("Null parameter [source]");
}
else if (!file.isFile())
{
throw new IllegalArgumentException("Source parameter is not a file.");
}
else
{
System.out.println("== Sort for [" + file.getName() + "]");
LogUtils.sortErrorLog(file);
}
}
/**
@ -462,6 +730,7 @@ public final class Logar
}
else
{
System.out.println("== Test access log for [" + source.getName() + "]");
Stats counter = new Stats();
for (File directory : source.listFiles())
@ -523,7 +792,6 @@ public final class Logar
}
}
System.out.println("=====================================================");
counter.stop();
System.out.println(counter.toString());
}
@ -547,6 +815,7 @@ public final class Logar
}
else
{
System.out.println("== Test error log for [" + source.getName() + "]");
Stats counter = new Stats();
for (File directory : source.listFiles())

View File

@ -18,6 +18,15 @@
*/
package fr.devinsy.logar.app;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -28,6 +37,8 @@ public final class LogarUtils
{
private static Logger logger = LoggerFactory.getLogger(LogarUtils.class);
public static final String DEFAULT_CHARSET_NAME = "UTF-8";
/**
* Instantiates a new log tool utils.
*/
@ -35,6 +46,38 @@ public final class LogarUtils
{
}
/**
* Sha 1 sum.
*
* @param file
* the file
* @return the string
* @throws IOException
*/
public static String sha1sum(final File file) throws IOException
{
String result;
DigestInputStream digestStream = null;
try
{
digestStream = new DigestInputStream(new FileInputStream(file), MessageDigest.getInstance("SHA-1"));
digestStream.readAllBytes();
result = DigestUtils.sha1Hex(digestStream.getMessageDigest().digest());
}
catch (NoSuchAlgorithmException e1)
{
throw new IOException("Impossible to get SHA-1 digester", e1);
}
finally
{
IOUtils.closeQuietly(digestStream);
}
//
return result;
}
/**
* To human.
*

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.logar.app.log;
import java.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class Log.
*/
public final class Log
{
private static Logger logger = LoggerFactory.getLogger(Log.class);
private String line;
private LocalDateTime datetime;
private String ip;
private String user;
/**
* Instantiates a new log.
*/
public Log(final String line, final LocalDateTime datetime)
{
this.line = line;
this.datetime = datetime;
this.ip = null;
this.user = null;
}
/**
* Instantiates a new log.
*
* @param line
* the line
* @param datetime
* the datetime
* @param ip
* the ip
* @param user
* the login
*/
public Log(final String line, final LocalDateTime datetime, final String ip, final String user)
{
this.line = line;
this.datetime = datetime;
this.ip = ip;
this.user = user;
}
public LocalDateTime getDatetime()
{
return this.datetime;
}
public String getIp()
{
return this.ip;
}
public String getLine()
{
return this.line;
}
public String getUser()
{
return this.user;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
String result;
result = this.line;
//
return result;
}
}

View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.logar.app.log;
import java.time.LocalDateTime;
import java.util.Comparator;
import org.april.logar.util.CompareUtils;
/**
* The Class LogComparator.
*/
public class LogComparator implements Comparator<Log>
{
public enum Sorting
{
DATETIME
}
private Sorting sorting;
/**
* Instantiates a new organization comparator.
*
* @param sorting
* the sorting
*/
public LogComparator(final Sorting sorting)
{
this.sorting = sorting;
}
/**
* Compare.
*
* @param alpha
* the alpha
* @param bravo
* the bravo
* @return the int
*/
@Override
public int compare(final Log alpha, final Log bravo)
{
int result;
result = compare(alpha, bravo, this.sorting);
//
return result;
}
/**
* Compare.
*
* @param alpha
* the alpha
* @param bravo
* the bravo
* @param sorting
* the sorting
* @return the int
*/
public static int compare(final Log alpha, final Log bravo, final Sorting sorting)
{
int result;
if (sorting == null)
{
result = 0;
}
else
{
switch (sorting)
{
default:
case DATETIME:
result = CompareUtils.compare(getDatetime(alpha), getDatetime(bravo));
break;
}
}
//
return result;
}
/**
* Gets the datetime.
*
* @param source
* the source
* @return the datetime
*/
public static LocalDateTime getDatetime(final Log source)
{
LocalDateTime result;
if (source == null)
{
result = null;
}
else
{
result = source.getDatetime();
}
//
return result;
}
}

View File

@ -0,0 +1,276 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.logar.app.log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.io.IOUtils;
import org.april.logar.util.LineIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fr.devinsy.cmdexec.CmdExecException;
import fr.devinsy.cmdexec.CmdExecUtils;
/**
* The Class NginxAccessLogParser.
*/
public final class LogUtils
{
private static Logger logger = LoggerFactory.getLogger(LogUtils.class);
public static Pattern nginxAccessLogLinePatternFull = Pattern.compile(
"^(?<remoteAddress>[a-zA-F0-9\\\\:\\\\.]+) - (?<remoteUser>\\S+) \\[(?<time>[^\\]]+)\\] \"(?<request>[^\"]*)\" (?<status>\\d+) (?<bodyBytesSent>\\d+) \"(?<referer>[^\"]*)\" \"(?<userAgent>[^\"]*)\".*$");
public static Pattern NGINX_ACCESSLOG_LINE_PATTERN = Pattern.compile("^(?<remoteAddress>[a-fA-F0-9\\\\:\\\\.]+) - (?<remoteUser>[^\\[]+) \\[(?<time>[^\\]]+)\\] .*$");
public static Pattern NGINX_ERRORLOG_LINE_PATTERN = Pattern.compile("^(?<time>\\S+\\s\\S+)\\s\\[(?<level>[^\\]]*)\\]\\s.*$");
public static Pattern NGINX_ACCESSLOG_LINE_PATTERN2 = Pattern.compile("^\\S+ - [^\\[]+ \\[(?<time>[^\\]]+)\\] .*$");
public static Pattern NGINX_ERRORLOG_LINE_PATTERN2 = Pattern.compile("^(?<time>\\S+\\s\\S+)\\s\\[(?<level>[^\\]]*)\\]\\s.*$");
/**
* Instantiates a new nginx access log parser.
*/
private LogUtils()
{
}
/**
* Load.
*
* @param file
* the file
* @return the logs
* @throws IOException
*/
public static Logs loadAccessLog(final File file) throws IOException
{
Logs result;
result = new Logs();
LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
{
String line = iterator.next();
Log log = parseAccessLog(line);
result.add(log);
}
//
return result;
}
/**
* Load error log.
*
* @param file
* the file
* @return the logs
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static Logs loadErrorLog(final File file) throws IOException
{
Logs result;
result = new Logs();
LineIterator iterator = new LineIterator(file);
while (iterator.hasNext())
{
String line = iterator.next();
Log log = parseErrorLog(line);
result.add(log);
}
//
return result;
}
/**
* From access log.
*
* @param line
* the line
* @return the log
*/
public static Log parseAccessLog(final String line)
{
Log result;
Matcher matcher = NGINX_ACCESSLOG_LINE_PATTERN.matcher(line);
if (matcher.matches())
{
String value = matcher.group("time");
LocalDateTime date = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z").withLocale(Locale.ENGLISH));
String ip = matcher.group("remoteAddress").trim();
String user = matcher.group("remoteUser").trim();
result = new Log(line, date, ip, user);
}
else
{
throw new IllegalArgumentException("Bad line format: " + line);
}
//
return result;
}
/**
* From error log.
*
* @param line
* the line
* @return the log
*/
public static Log parseErrorLog(final String line)
{
Log result;
Matcher matcher = NGINX_ERRORLOG_LINE_PATTERN.matcher(line);
if (matcher.matches())
{
String value = matcher.group("time");
LocalDateTime date = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").withLocale(Locale.ENGLISH));
result = new Log(line, date);
}
else
{
throw new IllegalArgumentException("Bad line format: " + line);
}
//
return result;
}
/**
* Save access log.
*
* @param source
* the source
* @throws IOException
* @throws FileNotFoundException
*/
public static void saveLogs(final File target, final Logs logs) throws FileNotFoundException, IOException
{
PrintWriter out = null;
try
{
out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(target)));
for (Log log : logs)
{
out.println(log.getLine());
}
}
finally
{
IOUtils.closeQuietly(out);
}
}
/**
* Sort access log.
*
* @param target
* the target
* @throws IOException
*/
public static void sortAccessLog(final File file) throws IOException
{
File work = new File(file.getParent(), file.getName() + ".tmp");
Logs logs = loadAccessLog(file);
logs.sortByDatetime();
saveLogs(work, logs);
File backup = new File(file.getParentFile(), file.getName() + ".bak");
if (file.renameTo(backup))
{
if (!work.renameTo(file))
{
backup.renameTo(file);
}
}
try
{
String out = CmdExecUtils.run("/bin/bash -c \"zcat " + file.getAbsolutePath() + "| sort | sha1sum \"");
System.out.print(out);
out = CmdExecUtils.run("/bin/bash -c \"zcat " + file.getAbsolutePath() + ".bak | sort | sha1sum \"");
System.out.println(out);
}
catch (CmdExecException exception)
{
exception.printStackTrace();
}
}
/**
* Sort error log.
*
* @param file
* the file
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static void sortErrorLog(final File file) throws IOException
{
File work = new File(file.getParent(), file.getName() + ".tmp");
Logs logs = loadErrorLog(file);
logs.sortByDatetime();
saveLogs(work, logs);
File backup = new File(file.getParentFile(), file.getName() + ".bak");
if (file.renameTo(backup))
{
if (!work.renameTo(file))
{
backup.renameTo(file);
}
}
try
{
String out = CmdExecUtils.run("/bin/bash -c \"zcat " + file.getAbsolutePath() + "| sort | sha1sum \"");
System.out.print(out);
out = CmdExecUtils.run("/bin/bash -c \"zcat " + file.getAbsolutePath() + ".bak | sort | sha1sum \"");
System.out.println(out);
}
catch (CmdExecException exception)
{
exception.printStackTrace();
}
}
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.devinsy.logar.app.log;
import java.util.ArrayList;
/**
* The Class Logs.
*/
public class Logs extends ArrayList<Log>
{
private static final long serialVersionUID = 869606603972696142L;
/**
* Instantiates a new logs.
*/
public Logs()
{
super();
}
/**
* Instantiates a new logs.
*
* @param initialCapacity
* the initial capacity
*/
public Logs(final int initialCapacity)
{
super(initialCapacity);
}
/**
* Sort.
*
* @param sorting
* the sorting
* @return the logs
*/
public Logs sort(final LogComparator.Sorting sorting)
{
Logs result;
sort(new LogComparator(sorting));
result = this;
//
return result;
}
/**
* Sort by datetime.
*
* @return the logs
*/
public Logs sortByDatetime()
{
Logs result;
result = sort(LogComparator.Sorting.DATETIME);
//
return result;
}
}

View File

@ -56,8 +56,10 @@ public final class LogarCLI
message.appendln(" logar [ -v | -version | --version ]");
message.appendln(" logar anonymize source target anonymize ip and login");
message.appendln(" logar archive source target archive previous month");
message.appendln(" logar checksort file check sort of an access log file");
message.appendln(" logar test source census bad format line in log files");
message.appendln(" logar checksort fileordirectory check sort of an access log file");
message.appendln(" logar check fileordirectory census bad format line in log files");
message.appendln(" logar sort fileordirectory sort log files by datetime");
message.appendln(" logar testarchive source test archive");
logger.info(message.toString());
}
@ -181,12 +183,18 @@ public final class LogarCLI
{
displayVersion();
}
else if (isMatching(args, "anonymize", "\\s*\\S+\\s*"))
{
File source = new File(args[1]);
Logar.anonymize(source);
}
else if (isMatching(args, "anonymize", "\\s*\\S+\\s*", "\\s*\\S+\\s*"))
{
File source = new File(args[1]);
File target = new File(args[2]);
File map = new File(args[2]);
Logar.anonymize(source, target);
Logar.anonymize(source, map);
}
else if (isMatching(args, "archive", "\\s*\\S+\\s*", "\\s*\\S+\\s*"))
{
@ -195,13 +203,25 @@ public final class LogarCLI
Logar.archive(source, target);
}
else if (isMatching(args, "check", "\\s*\\S+\\s*"))
{
File source = new File(args[1]);
Logar.check(source);
}
else if (isMatching(args, "checksort", "\\s*\\S+\\s*"))
{
File source = new File(args[1]);
Logar.checkSort(source);
}
else if (isMatching(args, "test", "\\s*\\S+\\s*"))
else if (isMatching(args, "sort", "\\s*\\S+\\s*"))
{
File source = new File(args[1]);
Logar.sort(source);
}
else if (isMatching(args, "testarchive", "\\s*\\S+\\s*"))
{
File source = new File(args[1]);

View File

@ -48,6 +48,33 @@ public class Files extends ArrayList<File>
super(initialCapacity);
}
/**
* Removes the containing.
*
* @param token
* the token
* @return the files
*/
public Files removeContaining(final String token)
{
Files result;
Iterator<File> iterator = iterator();
while (iterator.hasNext())
{
File file = iterator.next();
if (file.getName().contains(token))
{
iterator.remove();
}
}
result = this;
//
return result;
}
/**
* Removes the hidden.
*

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2021 Christian Pierre MOMON <christian@momon.org>
*
* This file is part of Logar, simple tool to manage http log files.
*
* Logar 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.
*
* Logar 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 Logar. If not, see <http://www.gnu.org/licenses/>.
*/
package org.april.logar.util;
import java.io.File;
import org.apache.commons.lang3.StringUtils;
/**
* The Class FilesUtils.
*/
public class FilesUtils
{
/**
* Instantiates a new files utils.
*/
private FilesUtils()
{
}
/**
* List recursively.
*
* @param source
* the source
* @return the files
*/
public static Files listRecursively(final File source)
{
Files result;
result = new Files();
if (source != null)
{
if (source.isFile())
{
result.add(source);
}
else
{
for (File file : source.listFiles())
{
if (file.isDirectory())
{
result.addAll(listRecursively(file));
}
else
{
result.add(file);
}
}
}
}
//
return result;
}
/**
* List recursively.
*
* @param source
* the source
* @param extensions
* the extensions
* @return the files
*/
public static Files searchFileRecursively(final File source, final String... extensions)
{
Files result;
result = new Files();
Files full = listRecursively(source);
for (File file : full)
{
if ((file.isFile()) && (StringUtils.endsWithAny(file.getName(), extensions)))
{
result.add(file);
}
}
//
return result;
}
}

View File

@ -26,6 +26,7 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import anonymizer.Ipv4Generator;
import fr.devinsy.logar.app.LogarException;
/**
@ -47,6 +48,20 @@ public class TestFoo
Assert.assertEquals(1, 1);
}
@Test
public void test02() throws Exception
{
System.out.println(" 7: " + Ipv4Generator.random(7));
System.out.println(" 8: " + Ipv4Generator.random(8));
System.out.println(" 9: " + Ipv4Generator.random(9));
System.out.println("10: " + Ipv4Generator.random(10));
System.out.println("11: " + Ipv4Generator.random(11));
System.out.println("12: " + Ipv4Generator.random(12));
System.out.println("13: " + Ipv4Generator.random(13));
System.out.println("14: " + Ipv4Generator.random(14));
System.out.println("15: " + Ipv4Generator.random(15));
}
/**
* After class.
*