gt22

Untitled

Jul 23rd, 2017
257
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.80 KB | None | 0 0
  1. /*
  2. * Copyright 2015-2017 Austin Keener & Michael Ritter
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package net.dv8tion.jda.core.utils;
  17.  
  18. import org.apache.commons.lang3.exception.ExceptionUtils;
  19.  
  20. import javax.swing.JOptionPane;
  21. import java.io.*;
  22. import java.nio.charset.StandardCharsets;
  23. import java.nio.file.Files;
  24. import java.nio.file.StandardOpenOption;
  25. import java.text.SimpleDateFormat;
  26. import java.util.*;
  27.  
  28. public class SimpleLog
  29. {
  30. /**
  31. * The global LOG-level that is used as standard if not overwritten
  32. */
  33. public static Level LEVEL = Level.INFO;
  34.  
  35. /**
  36. * If this boolean is set to true, if there is no console present, messages are shown as message-dialogs
  37. */
  38. public static boolean ENABLE_GUI = false;
  39.  
  40. private static final String FORMAT = "[%time%] [%level%] [%name%]: %text%";
  41. private static final String MSGFORMAT = "%text%";
  42. private static final SimpleDateFormat DFORMAT = new SimpleDateFormat("HH:mm:ss");
  43.  
  44. private static final Map<String, SimpleLog> LOGS = new HashMap<>();
  45. private static final Set<LogListener> listeners = new HashSet<>();
  46.  
  47. /**
  48. * Will get the LOG with the given LOG-name or create one if it didn't exist
  49. *
  50. * @param name the name of the LOG
  51. * @return SimpleLog with given LOG-name
  52. */
  53. public static SimpleLog getLog(String name) {
  54. synchronized (LOGS) {
  55. if(!LOGS.containsKey(name.toLowerCase())) {
  56. LOGS.put(name.toLowerCase(), new SimpleLog(name));
  57. }
  58. }
  59. return LOGS.get(name.toLowerCase());
  60. }
  61.  
  62. private static final Map<Level, Set<File>> fileLogs = new HashMap<>();
  63. private static PrintStream origStd = null;
  64. private static PrintStream origErr = null;
  65. private static FileOutputStream stdOut = null;
  66. private static FileOutputStream errOut = null;
  67.  
  68. /**
  69. * Will duplicate the output-streams to the specified Files.
  70. * This will catch everything that is sent to sout and serr (even stuff not logged via SimpleLog).
  71. *
  72. * @param std
  73. * The file to use for System.out logging, or null to not LOG System.out to a file
  74. * @param err
  75. * The file to use for System.err logging, or null to not LOG System.err to a file
  76. * @throws java.io.IOException
  77. * If an IO error is encountered while dealing with the file. Most likely
  78. * to be caused by a lack of permissions when creating the log folders or files.
  79. */
  80. @SuppressWarnings("ResultOfMethodCallIgnored")
  81. public static void addFileLogs(File std, File err) throws IOException {
  82. if(std != null) {
  83. if (origStd == null)
  84. origStd = System.out;
  85. if(!std.getAbsoluteFile().getParentFile().exists()) {
  86. std.getAbsoluteFile().getParentFile().mkdirs();
  87. }
  88. if(!std.exists()) {
  89. std.createNewFile();
  90. }
  91. FileOutputStream fOut = new FileOutputStream(std, true);
  92. System.setOut(new PrintStream(new OutputStream() {
  93. @Override
  94. public void write(int b) throws IOException {
  95. origStd.write(b);
  96. fOut.write(b);
  97. }
  98. }));
  99. if (stdOut != null)
  100. stdOut.close();
  101. stdOut = fOut;
  102. }
  103. else if (origStd != null)
  104. {
  105. System.setOut(origStd);
  106. stdOut.close();
  107. origStd = null;
  108. }
  109. if(err != null) {
  110. if (origErr == null)
  111. origErr = System.err;
  112. if(!err.getAbsoluteFile().getParentFile().exists()) {
  113. err.getAbsoluteFile().getParentFile().mkdirs();
  114. }
  115. if(!err.exists()) {
  116. err.createNewFile();
  117. }
  118. FileOutputStream fOut = new FileOutputStream(err, true);
  119. System.setErr(new PrintStream(new OutputStream() {
  120. @Override
  121. public void write(int b) throws IOException {
  122. origErr.write(b);
  123. fOut.write(b);
  124. }
  125. }));
  126. if (errOut != null)
  127. errOut.close();
  128. errOut = fOut;
  129. }
  130. else if (origErr != null)
  131. {
  132. System.setErr(origErr);
  133. errOut.close();
  134. origErr = null;
  135. }
  136. }
  137.  
  138. /**
  139. * Sets up a File to log all messages that are not visible via sout and serr and meet a given log-level criteria.
  140. * All logs that would not be printed and are above given logLevel are printed to that File.
  141. * If you want to log Logs printed to sout and serr to file(s), use {@link #addFileLogs(java.io.File, java.io.File)} instead.
  142. *
  143. * @param logLevel
  144. * The log-level criteria. Only logs equal or above this level are printed to the File
  145. * @param file
  146. * The File where the logs should be printed
  147. * @throws java.io.IOException
  148. * If the File can't be canonically resolved (access denied)
  149. */
  150. public static void addFileLog(Level logLevel, File file) throws IOException
  151. {
  152. File canonicalFile = file.getCanonicalFile();
  153. if (!fileLogs.containsKey(logLevel))
  154. {
  155. fileLogs.put(logLevel, new HashSet<>());
  156. }
  157. fileLogs.get(logLevel).add(canonicalFile);
  158. }
  159.  
  160. /**
  161. * Removes all File-logs created via {@link #addFileLog(net.dv8tion.jda.core.utils.SimpleLog.Level, java.io.File)} with given Level.
  162. * To remove the sout and serr logs, call {@link #addFileLogs(java.io.File, java.io.File)} with null args.
  163. *
  164. * @param logLevel
  165. * The level for which all fileLogs should be removed
  166. */
  167. public static void removeFileLog(Level logLevel)
  168. {
  169. fileLogs.remove(logLevel);
  170. }
  171.  
  172. /**
  173. * Removes all File-logs created via {@link #addFileLog(net.dv8tion.jda.core.utils.SimpleLog.Level, java.io.File)} with given File.
  174. * To remove the sout and serr logs, call {@link #addFileLogs(java.io.File, java.io.File)} with null args.
  175. *
  176. * @param file
  177. * The file to remove from all FileLogs (except sout and serr logs)
  178. * @throws java.io.IOException
  179. * If the File can't be canonically resolved (access denied)
  180. */
  181. public static void removeFileLog(File file) throws IOException
  182. {
  183. File canonicalFile = file.getCanonicalFile();
  184. Iterator<Map.Entry<Level, Set<File>>> setIter = fileLogs.entrySet().iterator();
  185. while (setIter.hasNext())
  186. {
  187. Map.Entry<Level, Set<File>> set = setIter.next();
  188. Iterator<File> fileIter = set.getValue().iterator();
  189. while (fileIter.hasNext())
  190. {
  191. File logFile = fileIter.next();
  192. if(logFile.equals(canonicalFile))
  193. {
  194. fileIter.remove();
  195. break;
  196. }
  197. }
  198. if (set.getValue().isEmpty())
  199. {
  200. setIter.remove();
  201. }
  202. }
  203. }
  204.  
  205. private static Set<File> collectFiles(Level level)
  206. {
  207. Set<File> out = new HashSet<>();
  208. for (Map.Entry<Level, Set<File>> mapEntry : fileLogs.entrySet())
  209. {
  210. if(mapEntry.getKey().getPriority() <= level.getPriority())
  211. out.addAll(mapEntry.getValue());
  212. }
  213. return out;
  214. }
  215.  
  216. private static void logToFiles(String msg, Level level)
  217. {
  218. Set<File> files = collectFiles(level);
  219. for (File file : files)
  220. {
  221. try
  222. {
  223. Files.write(file.toPath(), (msg + '\n').getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
  224. }
  225. catch (IOException e)
  226. {
  227. e.printStackTrace();
  228. // JDAImpl.LOG.fatal("Could not write log to logFile...");
  229. // JDAImpl.LOG.log(e);
  230. }
  231. }
  232. }
  233.  
  234. /**
  235. * Adds a custom Listener that receives all logs
  236. * @param listener the listener to add
  237. */
  238. public static void addListener(LogListener listener)
  239. {
  240. synchronized (listeners)
  241. {
  242. listeners.add(listener);
  243. }
  244. }
  245.  
  246. /**
  247. * Removes a custom Listener
  248. * @param listener the listener to remove
  249. */
  250. public static void removeListener(LogListener listener)
  251. {
  252. synchronized (listeners)
  253. {
  254. listeners.remove(listener);
  255. }
  256. }
  257.  
  258. public final String name;
  259. private Level level = null;
  260.  
  261. private SimpleLog(String name) {
  262. this.name = name;
  263. }
  264.  
  265. /**
  266. * Set the LOG-level
  267. * All messages with lower LOG-level will not be printed
  268. * If this level is set to null, the global Log-level ({@link net.dv8tion.jda.core.utils.SimpleLog#LEVEL}) will be used
  269. *
  270. * @param lev the new LOG-level
  271. */
  272. public void setLevel(Level lev) {
  273. this.level = lev;
  274. }
  275.  
  276. /**
  277. * Gets the current logging-level of this Logger.
  278. * This might return null, if the global logging-level is used.
  279. *
  280. * @return the logging-level of this Logger or null
  281. */
  282. public Level getLevel()
  283. {
  284. return level;
  285. }
  286.  
  287. /**
  288. * Gets the effective logging-level of this Logger.
  289. * This considers the global logging-level.
  290. *
  291. * @return the effective logging-level of this Logger
  292. */
  293. public Level getEffectiveLevel()
  294. {
  295. return level == null ? SimpleLog.LEVEL : level;
  296. }
  297.  
  298. /**
  299. * Will LOG a message with given LOG-level
  300. *
  301. * @param level The level of the Log
  302. * @param msg The message to LOG
  303. */
  304. public void log(Level level, Object msg) {
  305. synchronized (listeners)
  306. {
  307. for (LogListener listener : listeners)
  308. {
  309. listener.onLog(this, level, msg);
  310. }
  311. }
  312. String format = (ENABLE_GUI && !isConsolePresent()) ? MSGFORMAT : FORMAT;
  313. format = format.replace("%time%", DFORMAT.format(new Date())).replace("%level%", level.getTag()).replace("%name%", name).replace("%text%", String.valueOf(msg));
  314. if(level == Level.OFF || level.getPriority() < ((this.level == null) ? SimpleLog.LEVEL.getPriority() : this.level.getPriority())) {
  315. logToFiles(format, level);
  316. }
  317. else
  318. {
  319. print(format, level);
  320. }
  321. }
  322.  
  323. public void log(Throwable ex)
  324. {
  325. synchronized (listeners)
  326. {
  327. for (LogListener listener : listeners)
  328. {
  329. listener.onError(this, ex);
  330. }
  331. }
  332. log(Level.FATAL, "Encountered an exception:");
  333. log(Level.FATAL, ExceptionUtils.getStackTrace(ex));
  334. }
  335.  
  336. /**
  337. * Will LOG a message with trace level.
  338. *
  339. * @param msg the object, which should be logged
  340. */
  341. public void trace(Object msg) {
  342. log(Level.TRACE, msg);
  343. }
  344.  
  345. /**
  346. * Will LOG a message with debug level
  347. *
  348. * @param msg the object, which should be logged
  349. */
  350. public void debug(Object msg) {
  351. log(Level.DEBUG, msg);
  352. }
  353.  
  354. /**
  355. * Will LOG a message with info level
  356. *
  357. * @param msg the object, which should be logged
  358. */
  359. public void info(Object msg) {
  360. log(Level.INFO, msg);
  361. }
  362.  
  363. /**
  364. * Will LOG a message with warning level
  365. *
  366. * @param msg the object, which should be logged
  367. */
  368. public void warn(Object msg) {
  369. log(Level.WARNING, msg);
  370. }
  371.  
  372. /**
  373. * Will LOG a message with fatal level
  374. *
  375. * @param msg the object, which should be logged
  376. */
  377. public void fatal(Object msg) {
  378. log(Level.FATAL, msg);
  379. }
  380.  
  381. /**
  382. * prints a message to the console or as message-box.
  383. *
  384. * @param msg the message, that should be displayed
  385. * @param level the LOG level of the message
  386. */
  387. private void print(String msg, Level level) {
  388. if(ENABLE_GUI && !isConsolePresent()) {
  389. if(level.isError()) {
  390. JOptionPane.showMessageDialog(null, msg, "An Error occurred!", JOptionPane.ERROR_MESSAGE);
  391. } else {
  392. JOptionPane.showMessageDialog(null, msg, level.getTag(), JOptionPane.INFORMATION_MESSAGE);
  393. }
  394. } else {
  395. if(level.isError()) {
  396. System.err.println(msg);
  397. } else {
  398. System.out.println(msg);
  399. }
  400. }
  401. }
  402.  
  403. /**
  404. * Will return whether the program has a console present, or was launched without
  405. *
  406. * @return boolean true, if console is present
  407. */
  408. public static boolean isConsolePresent() {
  409. return System.console() != null;
  410. }
  411.  
  412. /**
  413. * This interface has to be able to register (via {@link net.dv8tion.jda.core.utils.SimpleLog#addListener(net.dv8tion.jda.core.utils.SimpleLog.LogListener)}) and listen to log-messages.
  414. */
  415. public interface LogListener
  416. {
  417. /**
  418. * Called on any incoming log-messages (including stacktraces).
  419. * This is also called on log-messages that would normally not print to console due to log-level.
  420. * @param log
  421. * the log this message was sent to
  422. * @param logLevel
  423. * the level of the message sent
  424. * @param message
  425. * the message as object
  426. */
  427. void onLog(SimpleLog log, Level logLevel, Object message);
  428.  
  429. /**
  430. * Called on any incoming error-message (Throwable).
  431. * Note: Throwables are also logged with FATAL level.
  432. * This is just a convenience Method to do special Throwable handling.
  433. * @param log
  434. * the log this error was sent to
  435. * @param err
  436. * the error as Throwable
  437. */
  438. void onError(SimpleLog log, Throwable err);
  439. }
  440.  
  441. /**
  442. * Enum containing all the LOG-levels
  443. */
  444. public enum Level {
  445. ALL("Finest", 0, false),
  446. TRACE("Trace", 1, false),
  447. DEBUG("Debug", 2, false),
  448. INFO("Info", 3, false),
  449. WARNING("Warning", 4, true),
  450. FATAL("Fatal", 5, true),
  451. OFF("NO-LOGGING", 6, true);
  452.  
  453. private final String msg;
  454. private final int pri;
  455. private final boolean isError;
  456.  
  457. Level(String message, int priority, boolean isError) {
  458. this.msg = message;
  459. this.pri = priority;
  460. this.isError = isError;
  461. }
  462.  
  463. /**
  464. * Returns the Log-Tag (e.g. Fatal)
  465. *
  466. * @return the logTag
  467. */
  468. public String getTag() {
  469. return msg;
  470. }
  471.  
  472. /**
  473. * Returns the numeric priority of this loglevel, with 0 being the lowest
  474. *
  475. * @return the level-priority
  476. */
  477. public int getPriority() {
  478. return pri;
  479. }
  480.  
  481. /**
  482. * Returns whether this LOG-level should be treated like an error or not
  483. *
  484. * @return boolean true, if this LOG-level is an error-level
  485. */
  486. public boolean isError() {
  487. return isError;
  488. }
  489. }
  490. }
Advertisement
Add Comment
Please, Sign In to add comment