Skip to content

Commit

Permalink
Merge pull request #105 from matty-r/84
Browse files Browse the repository at this point in the history
84
  • Loading branch information
matty-r authored Mar 3, 2024
2 parents d7c7e80 + e234d37 commit 4347f18
Show file tree
Hide file tree
Showing 19 changed files with 1,137 additions and 251 deletions.
31 changes: 27 additions & 4 deletions src/urChatBasic/backend/logging/URLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.util.Map;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
Expand All @@ -28,19 +29,17 @@ public class URLogger

public static void init () throws IOException, URISyntaxException
{
// System.out.println("LOG CONFIG: "+ LOG4J_CONFIG_FILE);
File logDir = new File(Constants.DIRECTORY_LOGS);
if (!logDir.exists())
{
logDir.mkdir();
}

File logConfigFile = new File(DriverGUI.class.getResource(LOG4J_CONFIG_FILE).toURI());

if(!logConfigFile.exists())
throw new IOException("LOG FILE NOT FOUND");

// System.setProperty("log4j2.debug", "true");
System.setProperty("log4j2.configurationFile", logConfigFile.toString());
System.setProperty("log4j2.configurationFile", DriverGUI.class.getResource(LOG4J_CONFIG_FILE).toURI().toString());

LOGGER = LoggerFactory.getLogger("urchat");

Expand Down Expand Up @@ -89,6 +88,30 @@ public static Marker getMarker (String markerName)
// }
// }

/**
* Get the path for the logfile associated with the given markerName.
*
* @param markerName The markerName associated with the logfile.
* @return The path for the associated logfile, or null if not found.
*/
public static String getLogFilePath(String markerName) {
// Get the root LoggerConfig
Configuration rootLoggerConfig = currentConfig;
if (rootLoggerConfig != null) {
// Find the appender associated with the given markerName
Map<String, Appender> appenders = rootLoggerConfig.getAppenders();
String appenderName = markerName + "Appender";
Appender appender = appenders.get(appenderName);
if (appender instanceof FileAppender) {
// If the appender is a FileAppender, return its file name
FileAppender fileAppender = (FileAppender) appender;
return fileAppender.getFileName();
}
}
// Return null if the logfile for the given markerName is not found
return null;
}

public static void logChannelComms (IRCChannelBase ircChannel, String message)
{

Expand Down
177 changes: 177 additions & 0 deletions src/urChatBasic/backend/utils/LogPatternParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package urChatBasic.backend.utils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LogPatternParser
{

// Define enum for log patterns
public enum LogPattern
{
DATE("%d", "(?<DATE>.*UTC?)", Date.class, "UTC "),
SERVER("%marker", "\\s(?<SERVER>[A-Za-z0-9.-]+)-", String.class, "-"),
CHANNEL("%marker", "(?<CHANNEL>#.*?)\\s", String.class, " "), // Named group for channel, excluding the trailing whitespace
USER("%msg", "(?<USER>.*?):", String.class, ": "),
MESSAGE("%msg", "\\s(?<MESSAGE>.*)$", String.class, "");

private final String pattern;
private final String regex;
private final String appendString;
private final Class<?> patternClass;
public final static String PATTERN_LAYOUT = "%d{yyy-MM-dd HH:mm:ss.SSS}{UTC}UTC %marker %msg%n";
public final static String DATE_LAYOUT = "yyyy-MM-dd HH:mm:ss.SSS";

LogPattern (String pattern, String regex, Class<?> patternClass, String appendString)
{
this.pattern = pattern;
this.regex = regex;
this.patternClass = patternClass;
this.appendString = appendString;
}

public String getPattern ()
{
return pattern;
}

public Class<?> getPatternClass ()
{
return patternClass;
}

public String getRegex ()
{
return regex;
}

public String getMatchGroup ()
{
return this.toString();
}

public String getAppendString ()
{
return appendString;
}
}

public static Date parseDate (String dateString)
{
dateString = dateString.trim();
// Step 1: Define the DateTimeFormatter with the pattern
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
TemporalAccessor temporalAccessor = null;
try{
// Step 2: Parse the string into a TemporalAccessor object using the formatter
temporalAccessor = formatter.parse(dateString.replace("UTC", ""));
} catch (Exception exc)
{
System.out.println(exc);
}

// Step 3: Convert the TemporalAccessor to a LocalDateTime object
LocalDateTime localDateTime = LocalDateTime.from(temporalAccessor);

// Step 4: Convert the LocalDateTime to the local timezone
LocalDateTime localDateTimeInLocalTimeZone = localDateTime
.atZone(ZoneId.of("UTC"))
.withZoneSameInstant(ZoneId.systemDefault())
.toLocalDateTime();

// Step 5: Convert the LocalDateTime to a Date object
Date date = Date.from(localDateTimeInLocalTimeZone.atZone(ZoneId.systemDefault()).toInstant());


return date;
}

// Method to format Date object to string in UTC
public static String formatDateToString(Date date) {
// Define the DateTimeFormatter with the pattern
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

// Convert the Date object to LocalDateTime
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

// Convert the LocalDateTime to UTC time zone
LocalDateTime localDateTimeInUtc = localDateTime.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime();

// Format the LocalDateTime to string
return formatter.format(localDateTimeInUtc);
}

// Parse log line using specified pattern
public static void parseLogLine (String logLine)
{
Map<String, Object> parsedValues = new HashMap<String, Object>();

for (LogPattern pattern : LogPattern.values())
{
Pattern regexPattern = Pattern.compile(pattern.getRegex());
Matcher matcher = regexPattern.matcher(logLine);
if (matcher.find())
{
String fullMatch = matcher.group(0);
String match = matcher.group(pattern.getMatchGroup());
System.out.println(pattern.name() + " group: " + match);
// parsedValues.put(pattern.toString(), match);
switch (pattern.getPatternClass().getSimpleName()) {
case "Date":
parsedValues.put(pattern.toString(), parseDate(match));
logLine = logLine.replaceFirst(fullMatch, "").trim();
break;
default:
parsedValues.put(pattern.toString(), match);
if(logLine.length() == fullMatch.length())
break;

logLine = logLine.replaceFirst(fullMatch, "").trim();
break;
}
}
}

System.out.println("Done");
}

public static Map<String, Object> parseLogLineFull (String logLine) {
logLine = logLine.trim();
Map<String, Object> parsedValues = new HashMap<>();

StringBuilder combinedRegexBuilder = new StringBuilder();
combinedRegexBuilder.append(LogPattern.DATE.getRegex());
combinedRegexBuilder.append(LogPattern.SERVER.getRegex());
combinedRegexBuilder.append(LogPattern.CHANNEL.getRegex());
combinedRegexBuilder.append(LogPattern.USER.getRegex());
combinedRegexBuilder.append(LogPattern.MESSAGE.getRegex());
String combinedRegex = combinedRegexBuilder.toString();

Pattern regexPattern = Pattern.compile(combinedRegex);
Matcher matcher = regexPattern.matcher(logLine);
while (matcher.find()) {
for (LogPattern pattern : LogPattern.values()) {
if (matcher.group(pattern.toString()) != null) {
String match = matcher.group(pattern.getMatchGroup());
switch (pattern.getPatternClass().getSimpleName()) {
case "Date":
parsedValues.put(pattern.toString(), parseDate(match));
break;
default:
parsedValues.put(pattern.toString(), match);
break;
}
}
}
}

return parsedValues;
}
}
101 changes: 101 additions & 0 deletions src/urChatBasic/backend/utils/ReverseLineInputStream.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package urChatBasic.backend.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

/**
* @see https://web.archive.org/web/20220701011119/https://stackoverflow.com/questions/8664705/how-to-read-file-from-end-to-start-in-reverse-order-in-javaa
*/
public class ReverseLineInputStream extends InputStream {

RandomAccessFile in;

long currentLineStart = -1;
long currentLineEnd = -1;
long currentPos = -1;
long lastPosInFile = -1;
int lastChar = -1;


public ReverseLineInputStream(File file) throws FileNotFoundException {
in = new RandomAccessFile(file, "r");
currentLineStart = file.length();
currentLineEnd = file.length();
lastPosInFile = file.length() -1;
currentPos = currentLineEnd;

}

private void findPrevLine() throws IOException {
if (lastChar == -1) {
in.seek(lastPosInFile);
lastChar = in.readByte();
}

currentLineEnd = currentLineStart;

// There are no more lines, since we are at the beginning of the file and no lines.
if (currentLineEnd == 0) {
currentLineEnd = -1;
currentLineStart = -1;
currentPos = -1;
return;
}

long filePointer = currentLineStart -1;

while ( true) {
filePointer--;

// we are at start of file so this is the first line in the file.
if (filePointer < 0) {
break;
}

in.seek(filePointer);
int readByte = in.readByte();

// We ignore last LF in file. search back to find the previous LF.
if (readByte == 0xA && filePointer != lastPosInFile ) {
break;
}
}
// we want to start at pointer +1 so we are after the LF we found or at 0 the start of the file.
currentLineStart = filePointer + 1;
currentPos = currentLineStart;
}

public int read() throws IOException {

if (currentPos < currentLineEnd ) {
in.seek(currentPos++);
int readByte = in.readByte();
return readByte;
} else if (currentPos > lastPosInFile && currentLineStart < currentLineEnd) {
// last line in file (first returned)
findPrevLine();
if (lastChar != '\n' && lastChar != '\r') {
// last line is not terminated
return '\n';
} else {
return read();
}
} else if (currentPos < 0) {
return -1;
} else {
findPrevLine();
return read();
}
}

@Override
public void close() throws IOException {
if (in != null) {
in.close();
in = null;
}
}
}
5 changes: 4 additions & 1 deletion src/urChatBasic/backend/utils/URProfilesUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public static void deleteProfile (String profileName, boolean fireListeners)

if(allProfiles.length > 1)
{
Constants.BASE_PREFS.node(profileName).clear();
Constants.LOGGER.info( "Deleting profile [" + profileName + "].");
Constants.BASE_PREFS.node(profileName).removeNode();
if(fireListeners)
Expand Down Expand Up @@ -271,7 +272,7 @@ public static void setDefaultProfile (String profileName)
BASE.put(Constants.KEY_DEFAULT_PROFILE_NAME, profileName);
}

public static void createProfile (String profileName)
public static String createProfile (String profileName)
{
int newProfileNumber = 0;
String newProfileName = profileName;
Expand All @@ -292,6 +293,8 @@ public static void createProfile (String profileName)
Constants.LOGGER.info( "Creating new profile [" + newProfileName + "]");
setDefaultSettings(newProfileName);
fireListeners(EventType.CREATE);

return newProfileName;
}

private static void setDefaultSettings (String profileName)
Expand Down
5 changes: 5 additions & 0 deletions src/urChatBasic/base/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public class Constants
public static final String KEY_CLICKABLE_LINKS_ENABLED = "clickable links";
public static final String KEY_EVENT_TICKER_JOINS_QUITS = "show events in ticker";
public static final String KEY_MAIN_WINDOW_JOINS_QUITS = "show events in main window";
public static final String KEY_LOAD_CHANNEL_LOGS_ON_JOIN = "load channel logs on join";
public static final String KEY_LOG_CHANNEL_ACTIVITY = "log channel history";
public static final String KEY_LOG_SERVER_ACTIVITY = "log server activity";
public static final String KEY_LIMIT_CHANNEL_LINES = "limit number of channel lines";
Expand Down Expand Up @@ -129,6 +130,7 @@ public class Constants
public static final Boolean DEFAULT_USERS_LIST_ACTIVE = true;
public static final Boolean DEFAULT_EVENT_TICKER_JOINS_QUITS = true;
public static final Boolean DEFAULT_MAIN_WINDOW_JOINS_QUITS = true;
public static final Boolean DEFAULT_LOAD_CHANNEL_LOGS_ON_JOIN = true;
public static final Boolean DEFAULT_LOG_CHANNEL_ACTIVITY = true;
public static final Boolean DEFAULT_LOG_SERVER_ACTIVITY = true;
public static final Boolean DEFAULT_AUTO_CONNECT_FAVOURITES = false;
Expand All @@ -152,6 +154,8 @@ public class Constants
public static final char SPACES_AHEAD_DELIMITER = ':';
public static final int MESSAGE_LIMIT = 510;
public static final String END_MESSAGE = "\r\n";
public static final int MAXIMUM_QUEUE_SIZE = 100;

// We 'must' match against http(s) in order to define the correct protocol to be used
public static final String URL_REGEX = "((http:\\/\\/|https:\\/\\/)(www.)?(([a-zA-Z0-9-]){2,}\\.){1,4}([a-zA-Z]){2,6}(\\/([a-zA-Z-_\\/\\.0-9#:?=&;,]*)?)?)";
public static final String CHANNEL_REGEX = "(?:^|\s)(#([^\s,]+)(?!,))(?:$|\s)";
Expand Down Expand Up @@ -263,6 +267,7 @@ public enum ConfigKeys {
KEY_CLICKABLE_LINKS_ENABLED(Constants.KEY_CLICKABLE_LINKS_ENABLED, DEFAULT_CLICKABLE_LINKS_ENABLED),
KEY_EVENT_TICKER_JOINS_QUITS(Constants.KEY_EVENT_TICKER_JOINS_QUITS, DEFAULT_EVENT_TICKER_JOINS_QUITS),
KEY_MAIN_WINDOW_JOINS_QUITS(Constants.KEY_MAIN_WINDOW_JOINS_QUITS, DEFAULT_MAIN_WINDOW_JOINS_QUITS),
KEY_LOAD_CHANNEL_LOGS_ON_JOIN(Constants.KEY_LOAD_CHANNEL_LOGS_ON_JOIN, DEFAULT_LOAD_CHANNEL_LOGS_ON_JOIN),
KEY_LOG_CHANNEL_ACTIVITY(Constants.KEY_LOG_CHANNEL_ACTIVITY, DEFAULT_LOG_CHANNEL_ACTIVITY),
KEY_LOG_SERVER_ACTIVITY(Constants.KEY_LOG_SERVER_ACTIVITY, DEFAULT_LOG_SERVER_ACTIVITY),
KEY_LIMIT_CHANNEL_LINES(Constants.KEY_LIMIT_CHANNEL_LINES, DEFAULT_LIMIT_CHANNEL_LINES),
Expand Down
Loading

0 comments on commit 4347f18

Please sign in to comment.