diff --git a/src/main/java/org/telegram/telegrambots/BotLogger.java b/src/main/java/org/telegram/telegrambots/BotLogger.java new file mode 100644 index 00000000..e098f60d --- /dev/null +++ b/src/main/java/org/telegram/telegrambots/BotLogger.java @@ -0,0 +1,355 @@ +package org.telegram.telegrambots; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.time.LocalDateTime; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author Ruben Bermudez + * @version 2.0 + * @brief Logger to file + * @date 21/01/15 + */ +public class BotLogger { + private static final Object lockToWrite = new Object(); + private static final String pathToLogs = "./"; + private static final Logger logger = Logger.getLogger("Telegram Bots Api"); + private static final ConcurrentLinkedQueue logsToFile = new ConcurrentLinkedQueue<>(); + private static volatile PrintWriter logginFile; + private static volatile String currentFileName; + private static volatile LocalDateTime lastFileDate; + private static LoggerThread loggerThread = new LoggerThread(); + + static { + logger.setLevel(Level.OFF); + loggerThread.start(); + lastFileDate = LocalDateTime.now(); + if ((currentFileName == null) || (currentFileName.compareTo("") == 0)) { + currentFileName = pathToLogs + dateFormatterForFileName(lastFileDate) + ".log"; + try { + final File file = new File(currentFileName); + if (file.exists()) { + logginFile = new PrintWriter(new BufferedWriter(new FileWriter(currentFileName, true))); + } else { + final boolean created = file.createNewFile(); + if (created) { + logginFile = new PrintWriter(new BufferedWriter(new FileWriter(currentFileName, true))); + } else { + throw new NullPointerException("File for logging error"); + } + } + } catch (IOException ignored) { + } + + } + } + + public static void setLevel(Level level) { + logger.setLevel(level); + } + + public static void registerLogger(Handler handler) { + logger.addHandler(handler); + } + + public static void log(Level level, String tag, String msg) { + logger.log(level, String.format("[%s] %s", tag, msg)); + logToFile(level, tag, msg); + } + + + public static void severe(String tag, String msg) { + logger.severe(String.format("[%s] %s", tag, msg)); + logToFile(Level.SEVERE, tag, msg); + } + + public static void warn(String tag, String msg) { + warning(tag, msg); + } + + public static void debug(String tag, String msg) { + fine(tag, msg); + } + + public static void error(String tag, String msg) { + severe(tag, msg); + } + + public static void trace(String tag, String msg) { + finer(tag, msg); + } + + public static void warning(String tag, String msg) { + logger.warning(String.format("[%s] %s", tag, msg)); + logToFile(Level.WARNING, tag, msg); + } + + + public static void info(String tag, String msg) { + logger.info(String.format("[%s] %s", tag, msg)); + logToFile(Level.INFO, tag, msg); + } + + + public static void config(String tag, String msg) { + logger.config(String.format("[%s] %s", tag, msg)); + logToFile(Level.CONFIG, tag, msg); + } + + + public static void fine(String tag, String msg) { + logger.fine(String.format("[%s] %s", tag, msg)); + logToFile(Level.FINE, tag, msg); + } + + + public static void finer(String tag, String msg) { + logger.finer(String.format("[%s] %s", tag, msg)); + logToFile(Level.FINER, tag, msg); + } + + + public static void finest(String tag, String msg) { + logger.finest(String.format("[%s] %s", tag, msg)); + logToFile(Level.FINEST, tag, msg); + } + + + public static void log(Level level, String tag, Throwable throwable) { + logger.log(level, String.format("[%s] Exception", tag), throwable); + logToFile(level, tag, throwable); + } + + public static void log(Level level, String tag, String msg, Throwable thrown) { + logger.log(level, msg, thrown); + logToFile(level, msg, thrown); + } + + public static void severe(String tag, Throwable throwable) { + logToFile(Level.SEVERE, tag, throwable); + } + + public static void warning(String tag, Throwable throwable) { + logToFile(Level.WARNING, tag, throwable); + } + + public static void info(String tag, Throwable throwable) { + logToFile(Level.INFO, tag, throwable); + } + + public static void config(String tag, Throwable throwable) { + logToFile(Level.CONFIG, tag, throwable); + } + + public static void fine(String tag, Throwable throwable) { + logToFile(Level.FINE, tag, throwable); + } + + public static void finer(String tag, Throwable throwable) { + logToFile(Level.FINER, tag, throwable); + } + + public static void finest(String tag, Throwable throwable) { + logToFile(Level.FINEST, tag, throwable); + } + + public static void warn(String tag, Throwable throwable) { + warning(tag, throwable); + } + + public static void debug(String tag, Throwable throwable) { + fine(tag, throwable); + } + + public static void error(String tag, Throwable throwable) { + severe(tag, throwable); + } + + public static void trace(String tag, Throwable throwable) { + finer(tag, throwable); + } + + public static void severe(String msg, String tag, Throwable throwable) { + log(Level.SEVERE, tag, msg, throwable); + } + + public static void warning(String msg, String tag, Throwable throwable) { + log(Level.WARNING, tag, msg, throwable); + } + + public static void info(String msg, String tag, Throwable throwable) { + log(Level.INFO, tag, msg, throwable); + } + + public static void config(String msg, String tag, Throwable throwable) { + log(Level.CONFIG, tag, msg, throwable); + } + + public static void fine(String msg, String tag, Throwable throwable) { + log(Level.FINE, tag, msg, throwable); + } + + public static void finer(String msg, String tag, Throwable throwable) { + log(Level.FINER, tag, msg, throwable); + } + + public static void finest(String msg, String tag, Throwable throwable) { + log(Level.FINEST, msg, throwable); + } + + public static void warn(String msg, String tag, Throwable throwable) { + log(Level.WARNING, tag, msg, throwable); + } + + public static void debug(String msg, String tag, Throwable throwable) { + log(Level.FINE, tag, msg, throwable); + } + + public static void error(String msg, String tag, Throwable throwable) { + log(Level.SEVERE, tag, msg, throwable); + } + + public static void trace(String msg, String tag, Throwable throwable) { + log(Level.FINER, tag, msg, throwable); + } + + private static boolean isCurrentDate(LocalDateTime dateTime) { + return dateTime.toLocalDate().isEqual(lastFileDate.toLocalDate()); + } + + private static String dateFormatterForFileName(LocalDateTime dateTime) { + String dateString = ""; + dateString += dateTime.getDayOfMonth(); + dateString += dateTime.getMonthValue(); + dateString += dateTime.getYear(); + return dateString; + } + + private static String dateFormatterForLogs(LocalDateTime dateTime) { + String dateString = "["; + dateString += dateTime.getDayOfMonth() + "_"; + dateString += dateTime.getMonthValue() + "_"; + dateString += dateTime.getYear() + "_"; + dateString += dateTime.getHour() + ":"; + dateString += dateTime.getMinute() + ":"; + dateString += dateTime.getSecond(); + dateString += "] "; + return dateString; + } + + private static void updateAndCreateFile(LocalDateTime dateTime) { + if (!isCurrentDate(dateTime)) { + lastFileDate = LocalDateTime.now(); + currentFileName = pathToLogs + dateFormatterForFileName(lastFileDate) + ".log"; + try { + logginFile.flush(); + logginFile.close(); + final File file = new File(currentFileName); + if (file.exists()) { + logginFile = new PrintWriter(new BufferedWriter(new FileWriter(currentFileName, true))); + } else { + final boolean created = file.createNewFile(); + if (created) { + logginFile = new PrintWriter(new BufferedWriter(new FileWriter(currentFileName, true))); + } else { + throw new NullPointerException("Error updating log file"); + } + } + } catch (IOException ignored) { + } + } + } + + + private static void logToFile(Level level, String tag, Throwable throwable) { + if (isLoggable(level)) { + synchronized (lockToWrite) { + final LocalDateTime currentDate = LocalDateTime.now(); + final String dateForLog = dateFormatterForLogs(currentDate); + updateAndCreateFile(currentDate); + logThrowableToFile(level, tag, throwable, dateForLog); + } + } + } + + + private static void logToFile(Level level, String tag, String msg) { + if (isLoggable(level)) { + synchronized (lockToWrite) { + final LocalDateTime currentDate = LocalDateTime.now(); + updateAndCreateFile(currentDate); + final String dateForLog = dateFormatterForLogs(currentDate); + logMsgToFile(level, tag, msg, dateForLog); + } + } + } + + private static void logToFile(Level level, String tag, String msg, Throwable throwable) { + if (isLoggable(level)) { + synchronized (lockToWrite) { + final LocalDateTime currentDate = LocalDateTime.now(); + updateAndCreateFile(currentDate); + final String dateForLog = dateFormatterForLogs(currentDate); + logMsgToFile(level, tag, msg, dateForLog); + logThrowableToFile(level, tag, throwable, dateForLog); + } + } + } + + private static void logMsgToFile(Level level, String tag, String msg, String dateForLog) { + final String logMessage = String.format("%s{%s} %s - %s", dateForLog, level.toString(), tag, msg); + logsToFile.add(logMessage); + synchronized (logsToFile) { + logsToFile.notifyAll(); + } + } + + private static void logThrowableToFile(Level level, String tag, Throwable throwable, String dateForLog) { + String throwableLog = String.format("%s{%s} %s - %s", dateForLog, level.toString(), tag, throwable.toString()); + for (StackTraceElement element : throwable.getStackTrace()) { + throwableLog += "\tat " + element + "\n"; + } + logsToFile.add(throwableLog); + synchronized (logsToFile) { + logsToFile.notifyAll(); + } + } + + private static boolean isLoggable(Level level) { + return logger.isLoggable(level); + } + + private static class LoggerThread extends Thread { + + @Override + public void run() { + while (true) { + final ConcurrentLinkedQueue stringsToLog = new ConcurrentLinkedQueue<>(); + synchronized (logsToFile) { + if (logsToFile.isEmpty()) { + try { + logsToFile.wait(); + } catch (InterruptedException e) { + return; + } + if (logsToFile.isEmpty()) { + continue; + } + } + stringsToLog.addAll(logsToFile); + logsToFile.clear(); + } + + stringsToLog.stream().forEach(logginFile::println); + logginFile.flush(); + } + } + } +} diff --git a/src/main/java/org/telegram/telegrambots/updatesreceivers/BotSession.java b/src/main/java/org/telegram/telegrambots/updatesreceivers/BotSession.java index 0f979910..f770700c 100644 --- a/src/main/java/org/telegram/telegrambots/updatesreceivers/BotSession.java +++ b/src/main/java/org/telegram/telegrambots/updatesreceivers/BotSession.java @@ -14,6 +14,7 @@ import org.apache.http.util.EntityUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.telegram.telegrambots.BotLogger; import org.telegram.telegrambots.Constants; import org.telegram.telegrambots.api.methods.updates.GetUpdates; import org.telegram.telegrambots.api.objects.Update; @@ -32,6 +33,7 @@ import java.util.concurrent.TimeUnit; * @date 20 of June of 2015 */ public class BotSession { + private static final String LOGTAG = "BOTSESSION"; private static final int SOCKET_TIMEOUT = 30 * 1000; private final ITelegramLongPollingBot callback; @@ -64,8 +66,9 @@ public class BotSession { { httpclient.close(); httpclient = null; - } catch (IOException ignored) { - } + } catch (IOException e) { + BotLogger.severe(LOGTAG, e); + } } } @@ -123,17 +126,21 @@ public class BotSession { synchronized (this) { this.wait(500); } - } catch (InterruptedException ignored) { + } catch (InterruptedException e) { + BotLogger.severe(LOGTAG, e); } } - } catch (JSONException ignored) { + } catch (InvalidObjectException | JSONException e) { + BotLogger.severe(LOGTAG, e); } - } catch (Exception e) { + } catch (Exception global) { + BotLogger.severe(LOGTAG, global); try { synchronized (this) { this.wait(500); } - } catch (InterruptedException ignored) { + } catch (InterruptedException e) { + BotLogger.severe(LOGTAG, e); } } } @@ -152,6 +159,7 @@ public class BotSession { try { receivedUpdates.wait(); } catch (InterruptedException e) { + BotLogger.severe(LOGTAG, e); continue; } update = receivedUpdates.pollLast(); @@ -161,7 +169,8 @@ public class BotSession { } } callback.onUpdateReceived(update); - } catch (Exception ignored) { + } catch (Exception e) { + BotLogger.severe(LOGTAG, e); } } }