Advertisement
Guest User

Liquid_Logging.js

a guest
Nov 3rd, 2015
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //=======================================================================================
  2. // Liquid Plugins - Liquid Logging
  3. // Liquid_Logging.js
  4. //=======================================================================================
  5.  
  6. var Imported = Imported || {};
  7. Imported.Liquid_Logging = true;
  8.  
  9. var Liquid = Liquid || {};
  10. Liquid.Logging = Liquid.Logging || {};
  11.  
  12. //=======================================================================================
  13. /*:
  14. * @plugindesc v1.0 Gives you the ability to log formatted information in various different
  15. * ways this is useful when you want to have more formatted information when debugging or
  16. * what have you.
  17. * @author Liquidize
  18. *
  19. * @param Allow Logging
  20. * @desc Is logging enabled?
  21. * @default true
  22. *
  23. * @param Logging Pattern
  24. * @desc The pattern used for logging, see the help for more details.
  25. * for more information.
  26. * @default [%c] [%-5l]: %m
  27. *
  28. *
  29. * @param Show Stack Trace
  30. * @desc Show stack trace when given an exception?
  31. * @default true
  32. *
  33. * @param Timestamps in milliseconds
  34. * @desc Show timestamps (when applicable) in milliseconds?
  35. * @default false
  36. *
  37. * @param Default Log Name
  38. * @desc Name of the default logger.
  39. * @default Game
  40. *
  41. * @help
  42. * =======================================================================================
  43. * Introduction
  44. * =======================================================================================
  45. * This plugin adds the ability to log information to a logging system, and then display
  46. * it in a formatted string through the means of the Browsers Console.
  47. * Useful for debugging events, as well as debugging your code.
  48. *
  49. * =======================================================================================
  50. * Pattern Formatting
  51. * =======================================================================================
  52. * By default the logging system logs information using the Liquid_ConsoleAppender with,
  53. * the format of the appender being supplied by Liquid_PatternFormat.
  54. * A pattern format is format given as a pattern, and is then filled with the proper
  55. * variables associated with the values in the pattern.
  56. *
  57. * The Liquid_PatternFormat formatter supports the following pattern variables.
  58. *
  59. * VARIABLE : USE
  60. *  %c : substitutes the name of the logger in.
  61. *  %a : supplies the logged message as an array.
  62. *  %m : supplies the logged message as a string.
  63. *  %l : substitutes the logging level in.
  64. *  %d : substitutes the date in, given a format (or default). EXAMPLE:  %d{HH:mm:ss} or %d{dd MMM yyyy HH:mm:ss}
  65. *  %n : creates a new line.
  66. *  %t : outputs the time since the logging system/the game started.
  67. *  %% : outputs a single %.
  68. *----------------------------------------------------------------------------------------
  69. * EXAMPLES
  70. *
  71. * FORMAT : OUTPUT
  72. *----------------------------------------------------------------------------------------
  73. * [%c] [%l] %m : [My Log Name] [The Logging Level] The Message given to the logger.
  74. * [%d] [%l] %m : [The Date (Using the default format)] [The Logging Level] The message.
  75. * [%d{HH:mm:ss}] [%c - %t] - %m : [The Date as Hours:Minutes:Seconds] [Name of Logger - Time Since Game Start] - The Message.
  76. *========================================================================================
  77. * Calling the Logging system from Events
  78. *========================================================================================
  79. * You are able to call the logging system from events using the plugin command event.
  80. *
  81. * The plugin command(s) are as follows:
  82. *----------------------------------------------------------------------------------------
  83. * LiquidLog LogLevel Message
  84. *
  85. * Purpose:
  86. * The purpose of this command is to log a message to the logger.
  87. *
  88. * Examples:
  89. * LiquidLog info This is an info message.
  90. * LiquidLog error This is an error message.
  91. * LiquidLog debug this is a debug message.
  92. * LiquidLog warn This is a warning message.
  93. * LiquidLog fatal this is another way to call an error message.
  94. *
  95. *========================================================================================
  96. * Calling the logging system from scripts/plugins.
  97. *========================================================================================
  98. * Another nice thing about Liquid_Logging is the ability to create your own loggers in
  99. * your own scripts. Then by doing so have debug messages for private use, or allow your
  100. * script users to see them by having a parameter to set your personal logger to be enabled.
  101. * Doing so would require them to have this plugin as well though.
  102. *
  103. * To call the logging system from your own script, you must first have this plugin installed
  104. * above your script in the list.
  105. *
  106. * After that you need to create a Liquid_Log object such as so:
  107. *
  108. * var mySuperDuperLog = Liquid.Logging.getLogger("My Log Name Here");
  109. *
  110. * After the logger is created you need to set some properties though.
  111. *
  112. * mySuperDuperLog.setLevel(Liquid_LogLevel.Level);
  113. *
  114. * change the "Liquid_LogLevel.Level" to an appropriate level. See further down for more info.
  115. *
  116. * var mySuperDuperAppender = new Liquid_ConsoleAppender();
  117. * var mySuperDuperFormat = new Liquid_PatternFormat("My Logging Pattern Here");
  118. * mySuperDuperAppender.setFormat(mySuperDuperFormat);
  119. * mySuperDuperLog.addApender(mySuperDuperAppender);
  120. *
  121. * Your "mySuperDuperLog" object is then usable by calling the logging methods.
  122. * What all of this code does, is create a new Liquid_Log object using the getLogger() method.
  123. * This method will check to see if a logger by the given name exists, if so it returns it instead.
  124. * If not however, it will then create a bare-bones logger, that isn't useable until you
  125. * Setup some of the properties. Such as the logging level threshold, and an appender.
  126. * An appender is the object that caries out the actual logging of the messages, given the
  127. * specified format, which is set by the "setFormat(YourFormatObjectHere)" method. A logger
  128. * may have multiple appenders. This is useful for custom appenders that users can create,
  129. * such as ones that may send a message to a server, or write to a file, or email a user.
  130. *
  131. * After all of this is setup, you can call your lovely logger using the methods below,
  132. * each of the methods have an option second argument for an exception if one exists.
  133. *
  134. * Info:
  135. * mySuperDuperLog.info("message");
  136. * Debug:
  137. * mySuperDuperLog.debug("message");
  138. * Warn:
  139. * mySuperDuperLog.warn("message");
  140. * Error/Fatal:
  141. * mySuperDuperLog.error("error message");
  142. *---------------------------------------------------------------------------------------
  143. * Logging Level
  144. *---------------------------------------------------------------------------------------
  145. * When creating a logger, it needs to have a logging level threshold set. This is what
  146. * determines what type of messages the logger will actually log. Ignoring ones outside of
  147. * the threshold.
  148. *
  149. * Liquid_LogLevel.All : Logs every type.
  150. * Liquid_LogLevel.Trace : Logs trace.
  151. * Liquid_LogLevel.Debug : Logs debug and up.
  152. * Liquid_LogLevel.Info : Logs info and up.
  153. * Liquid_LogLevel.Warn : Logs warn and up.
  154. * Liquid_LogLevel.Error : Logs error and up.
  155. * Liquid_LogLevel.Fatal : Logs fatal only.
  156. * Liquid_LogLevel.Off : Logs nothing.
  157. *========================================================================================
  158. * Custom Appenders and Formatters
  159. *========================================================================================
  160. * It is possible to create custom Appenders and Formatters for the logging system, by
  161. * creating new objects based off Liquid_LogAppender (for custom appenders) or
  162. * Liquid_LogFormat (for custom formatters).
  163. *
  164. * Once your new Appender or Formatter object is created, you need simply to implement your
  165. * own versions of the required functions. Then simply create a new instance of this object
  166. * and either do "yourAppenderVar.setFormat(YourInstanceOfNewFormatTypeHere)" or
  167. * "yourLogVar.addApender(YourInstanceOfNewAppenderTypeHere)" as shown above in using this
  168. * in custom scripts.
  169. *
  170. * More built in appenders and formatters are planned, but I am busy refactoring,optimizing,
  171. * and cleaning the code up for now.
  172. *========================================================================================
  173. * Change Log
  174. *========================================================================================
  175. * 1.0: Finished Script!
  176. *========================================================================================
  177. */
  178.  
  179.  
  180. //=======================================================================================
  181. // Parameters
  182. //=======================================================================================
  183.  
  184. Liquid.Parameters = PluginManager.parameters("Liquid_Logging");
  185. Liquid.Param = Liquid.Param || {};
  186.  
  187. Liquid.Param.LoggingEnabled = String(Liquid.Parameters['Allow Logging']);
  188. Liquid.Param.LogPattern = String(Liquid.Parameters['Logging Pattern']);
  189. Liquid.Param.LogShowStack = String(Liquid.Parameters['Show Stack Trace']);
  190. Liquid.Param.LogUseTimeStampsInMillisecs = String(Liquid.Parameters['Timestamps in milliseconds']);
  191. Liquid.Param.DefaultLogName = String(Liquid.Parameters['Default Log Name']);
  192.  
  193. //======================================================================================
  194. // Utilities
  195. //======================================================================================
  196.  
  197. Liquid.Logging.gameStartDate = new Date();
  198.  
  199. // Check if object is undefined.
  200. Liquid.Logging.isUndefined = function (obj) {
  201.     return typeof obj == "undefined";
  202. };
  203.  
  204. Liquid.Logging.arrayContains = function (arr, val) {
  205.     for (var i = 0, len = arr.length; i < len; i++) {
  206.         if (arr[i] == val) {
  207.             return true;
  208.         }
  209.     }
  210.     return false;
  211. };
  212.  
  213. Liquid.Logging.arrayRemove = function (arr, val) {
  214.     var index = -1;
  215.     for (var i = 0, len = arr.length; i < len; i++) {
  216.         if (arr[i] === val) {
  217.             index = i;
  218.             break;
  219.         }
  220.     }
  221.     if (index >= 0) {
  222.         arr.splice(index, 1);
  223.         return true;
  224.     } else {
  225.         return false;
  226.     }
  227. };
  228.  
  229. Liquid.Logging.toStr = function (obj) {
  230.     if (obj && obj.toString) {
  231.         return obj.toString();
  232.     } else {
  233.         return String(obj);
  234.     }
  235. };
  236.  
  237. Liquid.Logging.getExceptionMessage = function (exception) {
  238.     if (exception.message) {
  239.         return exception.message;
  240.     } else if (exception.description) {
  241.         return exception.description;
  242.     } else {
  243.         return Liquid.Logging.toStr(exception);
  244.     }
  245. };
  246.  
  247. Liquid.Logging.getFileNameFromUrl = function (url) {
  248.     var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));
  249.     return url.subst(lastSlashIndex + 1);
  250. };
  251.  
  252. Liquid.Logging.getPrettyExceptionString = function (exception) {
  253.     var newLine = "\r\n";
  254.     if (exception) {
  255.         var exStr = "Exception: " + Liquid.Logging.getExceptionMessage(exception);
  256.         try {
  257.             if (exception.lineNumber) {
  258.                 exStr += " on line number " + exception.lineNumber;
  259.             }
  260.             if (exception.fileName) {
  261.                 exStr += " in file " + Liquid.Logging.getUrlFileName(exception.fileName);
  262.             }
  263.         } catch (localEx) {
  264.             LiquidLog.internalLog.warn("Unable to obtain file and line information for error");
  265.         }
  266.         if (eval(Liquid.Param.ShowStack) && exception.stack) {
  267.             exStr += newLine + "Stack trace:" + newLine + exception.stack;
  268.         }
  269.         return exStr;
  270.     }
  271.     return null;
  272. };
  273.  
  274. Liquid.Logging.extractBoolFromParam = function (param, defaultVal) {
  275.     if (Liquid.Logging.isUndefined(param)) {
  276.         return defaultVal;
  277.     } else {
  278.         return Boolean(param);
  279.     }
  280. };
  281.  
  282. Liquid.Logging.extractStringFromParam = function (param, defaultValue) {
  283.     if (Liquid.Logging.isUndefined(param)) {
  284.         return defaultValue;
  285.     } else {
  286.         return String(param);
  287.     }
  288. };
  289.  
  290.  
  291. Liquid.Logging.extractIntFromParam = function (param, defaultValue) {
  292.     if (Liquid.Logging.isUndefined(param)) {
  293.         return defaultValue;
  294.     } else {
  295.         try {
  296.             var value = parseInt(param, 10);
  297.             return isNaN(value) ? defaultValue : value;
  298.         } catch (ex) {
  299.             LiquidLog.internalLog.warn("Invalid int param " + param, ex);
  300.             return defaultValue;
  301.         }
  302.     }
  303. };
  304.  
  305. Liquid.Logging.extractFunctionFromParam = function (param, defaultValue) {
  306.     if (typeof param == "function") {
  307.         return param;
  308.     } else {
  309.         return defaultValue;
  310.     }
  311. };
  312.  
  313. Liquid.Logging.handleError = function (message, exception) {
  314.     LiquidLog.internalLog.error(message, exception);
  315.     LiquidLog.dispatch("error", { "message": message, "exception": exception });
  316. };
  317.    
  318.    
  319. //======================================================================================
  320. // Liquid_InternalLog Object
  321. //======================================================================================
  322. function Liquid_InternalLog() {
  323.  
  324. };
  325.  
  326. Liquid_InternalLog.prototype.debug = function (message) {
  327.     console.log(message);
  328. };
  329.  
  330. Liquid_InternalLog.prototype.warn = function (message, exception) {
  331.     console.warn(message);
  332. };
  333.  
  334. Liquid_InternalLog.prototype.error = function (message, exception) {
  335.     var errorMessage = "Liquid_Log error:" + message;
  336.     if (exception) {
  337.         errorMessage += "\r\n\r\n" + "Original message: " + Liquid.Logging.getPrettyExceptionString(exception);
  338.     }
  339.     console.error(errorMessage);
  340. };
  341.    
  342.    
  343. //======================================================================================
  344. // Liquid_EventSupport Object
  345. // NOTE: This is not for RPGMaker events, though that may come soon!
  346. //======================================================================================
  347. function Liquid_EventSupport() {
  348.     this.eventTypes = [];
  349.     this.eventListeners = {};
  350. };
  351.  
  352. Liquid_EventSupport.prototype.setTypes = function (types) {
  353.     if (types instanceof Array) {
  354.         this.eventTypes = types;
  355.         this.eventListeners = {};
  356.         for (var i = 0, l = this.eventTypes.length; i < l; i++) {
  357.             this.eventListeners[this.eventTypes[i]] = [];
  358.         }
  359.     } else {
  360.         Liquid.Logging.handleError("Liquid_Log.EventSupport [" + this + "]: setTypes: types parameter must be an Array");
  361.  
  362.     }
  363. };
  364.  
  365. Liquid_EventSupport.prototype.addListener = function (eventtype, listener) {
  366.     if (typeof listener == "function") {
  367.         if (!Liquid.Logging.arrayContains(this.eventTypes, eventtype)) {
  368.             Liquid.Logging.handleError("Liquid_Log.EventSupport [" + this + "]: addEventListener: no event called '" + eventtype + "'");
  369.  
  370.         }
  371.         this.eventListeners[eventtype].push(listener);
  372.     } else {
  373.         Liquid.Logging.handleError("Liquid_Log.EventSupport [" + this + "]: addListener: listener must be a function");
  374.  
  375.     }
  376. };
  377.  
  378. Liquid_EventSupport.prototype.removeListener = function (eventtype, listener) {
  379.     if (typeof listener == "function") {
  380.         if (!Liquid.Logging.arrayContains(this.eventTypes, eventtype)) {
  381.             Liquid.Logging.handleError("Liquid_Log.EventSupport [" + this + "]: removeListener: no event called '" + eventtype + "'");
  382.         }
  383.         Liquid.Logging.arrayRemove(this.eventListeners[eventtype], listener);
  384.     } else {
  385.         Liquid.Logging.handleError("Liquid_Log.EventSupport [" + this + "]: removeListener: listener must be a function");
  386.     }
  387. };
  388.  
  389. Liquid_EventSupport.prototype.dispatch = function (eventtype, eventargs) {
  390.     if (Liquid.Logging.arrayContains(this.eventTypes, eventtype)) {
  391.         var listeners = this.eventListeners[eventtype];
  392.         for (var i = 0, l = listeners.length; i < l; i++) {
  393.             listeners[i](this, eventtype, eventargs);
  394.         }
  395.     }
  396.     else {
  397.         Liquid.Logging.handleError("Liquid_Log.EventSupport [" + this + "]: dispatch: no event called '" + eventtype + "'");
  398.  
  399.     }
  400. };
  401.    
  402.  
  403. //======================================================================================
  404. // Liquid_LogLevel Object
  405. //======================================================================================
  406. function Liquid_LogLevel(level, name) {
  407.     this.level = level;
  408.     this.name = name;
  409. };
  410.  
  411. Liquid_LogLevel.prototype.toString = function () {
  412.     return this.name;
  413. };
  414.  
  415. Liquid_LogLevel.prototype.equals = function (level) {
  416.     return this.level == level.level;
  417. };
  418.  
  419. Liquid_LogLevel.prototype.isGreaterThanOrEqual = function (level) {
  420.     return this.level >= level.level;
  421. };
  422.  
  423. Liquid_LogLevel.All = new Liquid_LogLevel(0, "All");
  424. Liquid_LogLevel.Trace = new Liquid_LogLevel(1, "Trace");
  425. Liquid_LogLevel.Debug = new Liquid_LogLevel(2, "Debug");
  426. Liquid_LogLevel.Info = new Liquid_LogLevel(3, "Info");
  427. Liquid_LogLevel.Warn = new Liquid_LogLevel(4, "Warn");
  428. Liquid_LogLevel.Error = new Liquid_LogLevel(5, "Error");
  429. Liquid_LogLevel.Fatal = new Liquid_LogLevel(6, "Fatal");
  430. Liquid_LogLevel.Off = new Liquid_LogLevel(7, "Off");
  431.  
  432. //=======================================================================================
  433. // Liquid_LogTimer Object
  434. //=======================================================================================
  435.  
  436. function Liquid_LogTimer(name, level) {
  437.     this.name = name;
  438.     this.level = Liquid.Logging.isUndefined(level) ? Liquid_LogLevel.Info : level;
  439.     this.start = new Date();
  440. };
  441.  
  442. Liquid_LogTimer.prototype.getElapsedTime = function () {
  443.     return new Date().getTime() - this.start.getTime();
  444. };
  445.  
  446. //=======================================================================================
  447. // Liquid_LogEvent Object
  448. //=======================================================================================
  449.  
  450. function Liquid_LogEvent(logger, timeStamp, level, messages, exception) {
  451.     this.logger = logger;
  452.     this.level = level;
  453.     this.timeStamp = timeStamp;
  454.     this.timeStampInMilliseconds = timeStamp.getTime();
  455.     this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);
  456.     this.milliseconds = this.timeStamp.getMilliseconds();
  457.     this.messages = messages;
  458.     this.exception = exception;
  459. };
  460.  
  461. Liquid_LogEvent.prototype.getThrowableStr = function () {
  462.     return this.exception ? Liquid.Logging.getExceptionString(this.exception) : "";
  463. };
  464.  
  465. Liquid_LogEvent.prototype.getCombinedMessages = function () {
  466.     return (this.messages.length == 1) ? this.messages[0] : this.messages.join("\r\n");
  467. };
  468.  
  469. Liquid_LogLevel.prototype.toString = function () {
  470.     return "Liquid_LogEvent [" + this.level + "]";
  471. };
  472.  
  473. //=======================================================================================
  474. // Liquid_LogFormat Object
  475. //=======================================================================================
  476. function Liquid_LogFormat() {
  477.     this.defaults = {};
  478.     this.defaults.loggerKey = "logger";
  479.     this.defaults.timeStampKey = "timestamp";
  480.     this.defaults.millisecondsKey = "milliseconds";
  481.     this.defaults.levelKey = "level";
  482.     this.defaults.messageKey = "message";
  483.     this.defaults.exceptionKey = "exception";
  484.     this.defaults.urlKey = "url";
  485.  
  486.     this.loggerKey = "logger";
  487.     this.timeStampKey = "timestamp";
  488.     this.millisecondsKey = "milliseconds";
  489.     this.levelKey = "level";
  490.     this.messageKey = "message";
  491.     this.exceptionKey = "exception";
  492.     this.urlKey = "url";
  493.     this.overrideTimeStampsSettings = false;
  494.     this.useTimeStampsMilliseconds = null;
  495.  
  496. };
  497.  
  498. Liquid_LogFormat.prototype.format = function () {
  499.     Liquid.Logging.handleError("Liquid_LogFormat: error Log Formatters must implement a format function.")
  500. };
  501.  
  502. Liquid_LogFormat.prototype.getContentType = function () {
  503.     return "text/plain";
  504. };
  505.  
  506. Liquid_LogFormat.prototype.isTimeStampsInMilliseconds = function () {
  507.     return this.overrideTimeStampsSetting ?
  508.         this.useTimeStampsMilliseconds : eval(Liquid.Param.LogUseTimeStampsInMillisecs);
  509. };
  510.  
  511. Liquid_LogFormat.prototype.setTimeStampsToUseMilliseconds = function (timestampsInMillisecs) {
  512.     this.overrideTimeStampsSettings = true;
  513.     this.useTimeStampsMilliseconds = Boolean(timestampsInMillisecs);
  514. };
  515.  
  516. Liquid_LogFormat.prototype.getTimeStampValue = function (logevent) {
  517.     return this.isTimeStampsInMilliseconds() ? logevent.timeStampInMilliseconds : logevent.timeStampInSeconds;
  518. };
  519.  
  520. Liquid_LogFormat.prototype.getDataValues = function (logevent, combineMessages) {
  521.     var datValues = [
  522.         [this.loggerKey, logevent.logger.name],
  523.         [this.timeStampKey, this.getTimeStampValue(logevent)],
  524.         [this.levelKey, logevent.level.name],
  525.         [this.urlKey, window.location.href],
  526.         [this.messageKey, combineMessages ? logevent.getCombinedMessages() : logevent.messages]
  527.     ];
  528.     if (this.isTimeStampsInMilliseconds() !== true) {
  529.         datValues.push([this.millisecondsKey, logevent.milliseconds]);
  530.     }
  531.     if (logevent.exception) {
  532.         datValues.push([this.exceptionKey, Liquid.Logging.getPrettyExceptionString(logevent.exception)]);
  533.     }
  534.     if (this.hasCustomFields()) {
  535.         for (var i = 0, l = this.customFields.length; i < l; i++) {
  536.             var val = this.customFields[i].value;
  537.                    
  538.             // Is the custom field a function? If so evalute it, then pass it to the logevent and format.
  539.             if (typeof val === "function") {
  540.                 val = val(this, logevent);
  541.             }
  542.             datValues.push([this.customFields[i].name, val]);
  543.         }
  544.     }
  545.     return datValues;
  546.  
  547. };
  548.  
  549. Liquid_LogFormat.prototype.setKeys = function (loggerKey, messageKey, millisecondsKey, timeStampKey,
  550.     levelKey, exceptionKey, urlKey) {
  551.     var extract = Liquid.Logging.extractStringFromParam;
  552.     this.loggerKey = extract(loggerKey, this.defaults.loggerKey);
  553.     this.timeStampKey = extract(timeStampKey, this.defaults.timeStampKey);
  554.     this.levelKey = extract(levelKey, this.defaults.levelKey);
  555.     this.messageKey = extract(messageKey, this.defaults.messageKey);
  556.     this.exceptionKey = extract(exceptionKey, this.defaults.exceptionKey);
  557.     this.urlKey = extract(urlKey, this.defaults.urlKey);
  558.     this.millisecondsKey = extract(millisecondsKey, this.defaults.millisecondsKey);
  559.  
  560. };
  561.  
  562. Liquid_LogFormat.prototype.setCustomField = function (field, value) {
  563.     var update = false;
  564.     for (var i = 0, l = this.customFields.length; i < l; i++) {
  565.         if (this.customFields[i].name === field) {
  566.             this.customFields[i].value = value;
  567.             update = true;
  568.         }
  569.     }
  570.     if (!update) {
  571.         this.customFields.push({ "name": field, "value": value });
  572.     }
  573. };
  574.  
  575. Liquid_LogFormat.prototype.hasCustomFields = function () {
  576.     return (this.customFields.length > 0);
  577. };
  578.  
  579. Liquid_LogFormat.prototype.ignoresThrowable = function () {
  580.     Liquid.Logging.handleError("Liquid_LogFormat.ignoresThrowable: format has no ignoresThrowable() method");
  581.  
  582. };
  583.  
  584. Liquid_LogFormat.prototype.formatWithException = function (logevent) {
  585.     var preformatted = this.format(logevent);
  586.  
  587.     if (logevent.exception && this.ignoresThrowable()) {
  588.         preformatted += logevent.getThrowableStr();
  589.     }
  590.     return preformatted;
  591. };
  592.  
  593. Liquid_LogFormat.prototype.toString = function () {
  594.     Liquid.Logging.handleError("Liquid_LogFormat: error LogFormatters must implement a toString method.")
  595. };
  596.    
  597.    
  598.  
  599. //=======================================================================================
  600. // Liquid_LogAppender Object
  601. //=======================================================================================
  602.  
  603. function Liquid_LogAppender() {
  604.     this.format = new Liquid_PatternFormat();
  605.     this.threshold = Liquid_LogLevel.All;
  606.     this.loggers = [];
  607. };
  608.  
  609. Liquid_LogAppender.prototype = new Liquid_EventSupport();
  610.  
  611. Liquid_LogAppender.prototype.doAppend = function (logevent) {
  612.     if ((eval(Liquid.Param.LoggingEnabled)) && logevent.level.level >= this.threshold.level) {
  613.         this.append(logevent);
  614.     }
  615. };
  616.  
  617. Liquid_LogAppender.prototype.append = function (logevent) {
  618.  
  619. };
  620.  
  621. Liquid_LogAppender.prototype.setFormat = function (format) {
  622.     if (format instanceof Liquid_LogFormat) {
  623.         this.format = format;
  624.     } else {
  625.         Liquid.Logging.handleError("Liquid_LogAppender.setFormat: format supplied is not a subclass of Liquid_LogFormat");
  626.     }
  627. };
  628.  
  629. Liquid_LogAppender.prototype.getFormat = function () {
  630.     return this.format;
  631. };
  632.  
  633. Liquid_LogAppender.prototype.setThreshold = function (threshold) {
  634.     if (threshold instanceof Liquid_LogLevel) {
  635.         this.threshold = threshold;
  636.     } else {
  637.         Liquid.Logging.handleError("Liquid_LogAppender.setThreshold: threshold supplied to " +
  638.             this.toString() + " is not a subclass of Liquid_LogLevel");
  639.     }
  640. };
  641.  
  642. Liquid_LogAppender.prototype.getThreshold = function () {
  643.     return this.threshold;
  644. };
  645.  
  646. Liquid_LogAppender.prototype.setAddedToLogger = function (logger) {
  647.     this.loggers.push(logger);
  648. };
  649.  
  650. Liquid_LogAppender.prototype.setRemovedFromLogger = function (logger) {
  651.     Liquid.Logging.arrayRemove(this.loggers, logger);
  652. };
  653.  
  654. Liquid_LogAppender.prototype.group = function () { };
  655. Liquid_LogAppender.prototype.groupEnd = function () { };
  656.  
  657. Liquid_LogAppender.prototype.toString = function () {
  658.     Liquid.Logging.handleError("Liquid_LogAppender.toString: all appenders must override this method");
  659. };
  660.  
  661. //=======================================================================================
  662. // Liquid_SimpleDateFormat Object
  663. //=======================================================================================
  664.    
  665.    
  666. function Liquid_SimpleDateFormat(formatstring) {
  667.     this.formatString = formatstring;
  668.  
  669.     this.regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;
  670.     this.monthNames = ["January", "February", "March", "April", "May", "June",
  671.         "July", "August", "September", "October", "November", "December"];
  672.     this.dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
  673.     this.TEXT2 = 0, this.TEXT3 = 1, this.NUMBER = 2, this.YEAR = 3, this.MONTH = 4, this.TIMEZONE = 5;
  674.     this.types = {
  675.         G: this.TEXT2,
  676.         y: this.YEAR,
  677.         M: this.MONTH,
  678.         w: this.NUMBER,
  679.         W: this.NUMBER,
  680.         D: this.NUMBER,
  681.         d: this.NUMBER,
  682.         F: this.NUMBER,
  683.         E: this.TEXT3,
  684.         a: this.TEXT2,
  685.         H: this.NUMBER,
  686.         k: this.NUMBER,
  687.         K: this.NUMBER,
  688.         h: this.NUMBER,
  689.         m: this.NUMBER,
  690.         s: this.NUMBER,
  691.         S: this.NUMBER,
  692.         Z: this.TIMEZONE
  693.     };
  694.     this.ONE_DAY = 24 * 60 * 60 * 1000;
  695.     this.ONE_WEEK = 7 * this.ONE_DAY;
  696.     this.DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;
  697.  
  698.     var newDateAtMidnight = function (year, month, day) {
  699.         var d = new Date(year, month, day, 0, 0, 0);
  700.         d.setMilliseconds(0);
  701.         return d;
  702.     };
  703.  
  704.     Date.prototype.getDifference = function (date) {
  705.         return this.getTime() - date.getTime();
  706.     };
  707.  
  708.     Date.prototype.isBefore = function (d) {
  709.         return this.getTime() < d.getTime();
  710.     };
  711.  
  712.     Date.prototype.getUTCTime = function () {
  713.         return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),
  714.             this.getSeconds(), this.getMilliseconds());
  715.     };
  716.  
  717.     Date.prototype.getTimeSince = function (d) {
  718.         return this.getUTCTime() - d.getUTCTime();
  719.     };
  720.  
  721.     Date.prototype.getPreviousSunday = function () {
  722.         // Using midday avoids any possibility of DST messing things up
  723.         var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);
  724.         var previousSunday = new Date(midday.getTime() - this.getDay() * this.ONE_DAY);
  725.         return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),
  726.             previousSunday.getDate());
  727.     };
  728.  
  729.     Date.prototype.getWeekInYear = function (minimalDaysInFirstWeek) {
  730.         if (Liquid.Logging.isUndefined(this.minimalDaysInFirstWeek)) {
  731.             minimalDaysInFirstWeek = this.DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;
  732.         }
  733.         var previousSunday = this.getPreviousSunday();
  734.         var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);
  735.         var numberOfSundays = previousSunday.isBefore(startOfYear) ?
  736.             0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / this.ONE_WEEK);
  737.         var numberOfDaysInFirstWeek = 7 - startOfYear.getDay();
  738.         var weekInYear = numberOfSundays;
  739.         if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {
  740.             weekInYear--;
  741.         }
  742.         return weekInYear;
  743.     };
  744.  
  745.     Date.prototype.getWeekInMonth = function (minimalDaysInFirstWeek) {
  746.         if (Liquid.Logging.isUndefined(this.minimalDaysInFirstWeek)) {
  747.             minimalDaysInFirstWeek = this.DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;
  748.         }
  749.         var previousSunday = this.getPreviousSunday();
  750.         var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);
  751.         var numberOfSundays = previousSunday.isBefore(startOfMonth) ?
  752.             0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / this.ONE_WEEK);
  753.         var numberOfDaysInFirstWeek = 7 - startOfMonth.getDay();
  754.         var weekInMonth = numberOfSundays;
  755.         if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {
  756.             weekInMonth++;
  757.         }
  758.         return weekInMonth;
  759.     };
  760.  
  761.     Date.prototype.getDayInYear = function () {
  762.         var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);
  763.         return 1 + Math.floor(this.getTimeSince(startOfYear) / this.ONE_DAY);
  764.     };
  765.  
  766.  
  767. };
  768.  
  769. Liquid_SimpleDateFormat.prototype.setMinDaysInFirstWeek = function (days) {
  770.     this.minDaysInFirstWeek = days;
  771. };
  772.  
  773. Liquid_SimpleDateFormat.prototype.getMinDaysInFirstWeek = function () {
  774.     return Liquid.Logging.isUndefined(this.minDaysInFirstWeek) ?
  775.         this.DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;
  776. };
  777.  
  778. var padWithZeroes = function (str, len) {
  779.     while (str.length < len) {
  780.         str = "0" + str;
  781.     }
  782.     return str;
  783. };
  784.  
  785. var formatText = function (data, numberOfLetters, minLength) {
  786.     return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));
  787. };
  788.  
  789. var formatNumber = function (data, numberOfLetters) {
  790.     var dataString = "" + data;
  791.     // Pad with 0s as necessary
  792.     return padWithZeroes(dataString, numberOfLetters);
  793. };
  794.  
  795. Liquid_SimpleDateFormat.prototype.format = function (date) {
  796.     var formattedString = "";
  797.     var result;
  798.     var searchString = this.formatString;
  799.     while ((result = this.regex.exec(searchString))) {
  800.         var quotedString = result[1];
  801.         var patternLetters = result[2];
  802.         var otherLetters = result[3];
  803.         var otherCharacters = result[4];
  804.  
  805.         // If the pattern matched is quoted string, output the text between the quotes
  806.         if (quotedString) {
  807.             if (quotedString == "''") {
  808.                 formattedString += "'";
  809.             } else {
  810.                 formattedString += quotedString.substring(1, quotedString.length - 1);
  811.             }
  812.         } else if (otherLetters) {
  813.             // Swallow non-pattern letters by doing nothing here
  814.         } else if (otherCharacters) {
  815.             // Simply output other characters
  816.             formattedString += otherCharacters;
  817.         } else if (patternLetters) {
  818.             // Replace pattern letters
  819.             var patternLetter = patternLetters.charAt(0);
  820.             var numberOfLetters = patternLetters.length;
  821.             var rawData = "";
  822.             switch (patternLetter) {
  823.                 case "G":
  824.                     rawData = "AD";
  825.                     break;
  826.                 case "y":
  827.                     rawData = date.getFullYear();
  828.                     break;
  829.                 case "M":
  830.                     rawData = date.getMonth();
  831.                     break;
  832.                 case "w":
  833.                     rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());
  834.                     break;
  835.                 case "W":
  836.                     rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());
  837.                     break;
  838.                 case "D":
  839.                     rawData = date.getDayInYear();
  840.                     break;
  841.                 case "d":
  842.                     rawData = date.getDate();
  843.                     break;
  844.                 case "F":
  845.                     rawData = 1 + Math.floor((date.getDate() - 1) / 7);
  846.                     break;
  847.                 case "E":
  848.                     rawData = this.dayNames[date.getDay()];
  849.                     break;
  850.                 case "a":
  851.                     rawData = (date.getHours() >= 12) ? "PM" : "AM";
  852.                     break;
  853.                 case "H":
  854.                     rawData = date.getHours();
  855.                     break;
  856.                 case "k":
  857.                     rawData = date.getHours() || 24;
  858.                     break;
  859.                 case "K":
  860.                     rawData = date.getHours() % 12;
  861.                     break;
  862.                 case "h":
  863.                     rawData = (date.getHours() % 12) || 12;
  864.                     break;
  865.                 case "m":
  866.                     rawData = date.getMinutes();
  867.                     break;
  868.                 case "s":
  869.                     rawData = date.getSeconds();
  870.                     break;
  871.                 case "S":
  872.                     rawData = date.getMilliseconds();
  873.                     break;
  874.                 case "Z":
  875.                     rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.
  876.                     break;
  877.             }
  878.             // Format the raw data depending on the type
  879.             switch (this.types[patternLetter]) {
  880.                 case this.TEXT2:
  881.                     formattedString += formatText(rawData, numberOfLetters, 2);
  882.                     break;
  883.                 case this.TEXT3:
  884.                     formattedString += formatText(rawData, numberOfLetters, 3);
  885.                     break;
  886.                 case this.NUMBER:
  887.                     formattedString += formatNumber(rawData, numberOfLetters);
  888.                     break;
  889.                 case this.YEAR:
  890.                     if (numberOfLetters <= 3) {
  891.                         // Output a 2-digit year
  892.                         var dataString = "" + rawData;
  893.                         formattedString += dataString.substr(2, 2);
  894.                     } else {
  895.                         formattedString += formatNumber(rawData, numberOfLetters);
  896.                     }
  897.                     break;
  898.                 case this.MONTH:
  899.                     if (numberOfLetters >= 3) {
  900.                         formattedString += formatText(this.monthNames[rawData], numberOfLetters, numberOfLetters);
  901.                     } else {
  902.                         // NB. Months returned by getMonth are zero-based
  903.                         formattedString += formatNumber(rawData + 1, numberOfLetters);
  904.                     }
  905.                     break;
  906.                 case this.TIMEZONE:
  907.                     var isPositive = (rawData > 0);
  908.                     // The following line looks like a mistake but isn't
  909.                     // because of the way getTimezoneOffset measures.
  910.                     var prefix = isPositive ? "-" : "+";
  911.                     var absData = Math.abs(rawData);
  912.  
  913.                     // Hours
  914.                     var hours = "" + Math.floor(absData / 60);
  915.                     hours = padWithZeroes(hours, 2);
  916.                     // Minutes
  917.                     var minutes = "" + (absData % 60);
  918.                     minutes = padWithZeroes(minutes, 2);
  919.  
  920.                     formattedString += prefix + hours + minutes;
  921.                     break;
  922.             }
  923.         }
  924.         searchString = searchString.substr(result.index + result[0].length);
  925.     }
  926.     return formattedString;
  927. };
  928.  
  929. Liquid.Logging.Liquid_SimpleDateFormat = Liquid_SimpleDateFormat;
  930.    
  931.    
  932. //=======================================================================================
  933. // Liquid_PatternFormat Object
  934. //=======================================================================================
  935. function Liquid_PatternFormat(pattern) {
  936.     if (pattern) {
  937.         this.pattern = pattern;
  938.     }
  939.     else {
  940.         this.pattern = Liquid_PatternFormat.DEFAULT_CONVERSION_PATTERN;
  941.     }
  942.     this.customFields = []
  943. };
  944.  
  945. Liquid_PatternFormat.TTCC_CONVERSION_PATTERN = "%t %l %c - %m%n";
  946. Liquid_PatternFormat.DEFAULT_CONVERSION_PATTERN = "%m%n";
  947. Liquid_PatternFormat.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";
  948. Liquid_PatternFormat.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";
  949. Liquid_PatternFormat.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";
  950.  
  951. Liquid_PatternFormat.prototype = new Liquid_LogFormat();
  952.  
  953. Liquid_PatternFormat.prototype.format = function (logevent) {
  954.     var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdxmMnlt%])(\{([^\}]+)\})?|([^%]+)/;
  955.     var formattedString = "";
  956.     var result;
  957.     var searchString = this.pattern;
  958.        
  959.        
  960.     // Cannot use regex global flag since it doesn't work with exec in Internet explorer 5 (compatibility!)
  961.     while ((result = regex.exec(searchString))) {
  962.         var matchedString = result[0];
  963.         var padding = result[1];
  964.         var truncation = result[2];
  965.         var conversionCharacter = result[3];
  966.         var specifier = result[5];
  967.         var text = result[6];
  968.  
  969.         // Check if the pattern matched was just normal text
  970.         if (text) {
  971.             formattedString += "" + text;
  972.         } else {
  973.             // Create a raw replacement string based on the conversion
  974.             // character and specifier
  975.             var replacement = "";
  976.             switch (conversionCharacter) {
  977.                 case "a":
  978.                 case "m": // Message
  979.                     var depth = 0;
  980.                     if (specifier) {
  981.                         depth = parseInt(specifier, 10);
  982.                         if (isNaN(depth)) {
  983.                             Liquid.Logging.handleError("Liquid_PatternFormat.format: invalid specifier '" +
  984.                                 specifier + "' for conversion character '" + conversionCharacter +
  985.                                 "' - should be a number");
  986.                             depth = 0;
  987.                         }
  988.                     }
  989.                     var messages = (conversionCharacter === "a") ? logevent.messages[0] : logevent.messages;
  990.                     for (var i = 0, len = messages.length; i < len; i++) {
  991.                         if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {
  992.                             replacement += " ";
  993.                         }
  994.                         if (depth === 0) {
  995.                             replacement += messages[i];
  996.                         } else {
  997.                             replacement += Liquid.Logging.formatObjectExpansion(messages[i], depth);
  998.                         }
  999.                     }
  1000.                     break;
  1001.                 case "c": // Logger name
  1002.                     var loggerName = logevent.logger.name;
  1003.                     if (specifier) {
  1004.                         var precision = parseInt(specifier, 10);
  1005.                         var loggerNameBits = logevent.logger.name.split(".");
  1006.                         if (precision >= loggerNameBits.length) {
  1007.                             replacement = loggerName;
  1008.                         } else {
  1009.                             replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");
  1010.                         }
  1011.                     } else {
  1012.                         replacement = loggerName;
  1013.                     }
  1014.                     break;
  1015.                 case "d": // Date
  1016.                     var dateFormat = Liquid_PatternFormat.ABSOLUTETIME_DATEFORMAT;
  1017.                     if (specifier) {
  1018.                         dateFormat = specifier;
  1019.                         // Pick up special cases
  1020.                         if (dateFormat == "ISO8601") {
  1021.                             dateFormat = Liquid_PatternFormat.ISO8601_DATEFORMAT;
  1022.                         } else if (dateFormat == "ABSOLUTE") {
  1023.                             dateFormat = Liquid_PatternFormat.ABSOLUTETIME_DATEFORMAT;
  1024.                         } else if (dateFormat == "DATE") {
  1025.                             dateFormat = Liquid_PatternFormat.DATETIME_DATEFORMAT;
  1026.                         }
  1027.                     }
  1028.                     // Format the date
  1029.                     replacement = (new Liquid_SimpleDateFormat(dateFormat)).format(logevent.timeStamp);
  1030.                     break;
  1031.                 case "x": // Custom field (coming soon!)
  1032.                     if (this.hasCustomFields()) {
  1033.  
  1034.                     }
  1035.                     break;
  1036.                 case "n": // New line
  1037.                     replacement = "\r\n";
  1038.                     break;
  1039.                 case "l": // Log Level
  1040.                     replacement = logevent.level.name;
  1041.                     break;
  1042.                 case "t": // Time since game startup
  1043.                     replacement = "" + logevent.timeStamp.getDifference(Liquid.Logging.gameStartDate);
  1044.                     break;
  1045.                 case "%": // Literal % sign
  1046.                     replacement = "%";
  1047.                     break;
  1048.                 default:
  1049.                     replacement = matchedString;
  1050.                     break;
  1051.             }
  1052.             // Format the replacement according to any padding or
  1053.             // truncation specified
  1054.             var l;
  1055.  
  1056.             // First, truncation
  1057.             if (truncation) {
  1058.                 l = parseInt(truncation.substr(1), 10);
  1059.                 var strLen = replacement.length;
  1060.                 if (l < strLen) {
  1061.                     replacement = replacement.substring(strLen - l, strLen);
  1062.                 }
  1063.             }
  1064.             // Next, padding
  1065.             if (padding) {
  1066.                 if (padding.charAt(0) == "-") {
  1067.                     l = parseInt(padding.substr(1), 10);
  1068.                     // Right pad with spaces
  1069.                     while (replacement.length < l) {
  1070.                         replacement += " ";
  1071.                     }
  1072.                 } else {
  1073.                     l = parseInt(padding, 10);
  1074.                     // Left pad with spaces
  1075.                     while (replacement.length < l) {
  1076.                         replacement = " " + replacement;
  1077.                     }
  1078.                 }
  1079.             }
  1080.             formattedString += replacement;
  1081.         }
  1082.         searchString = searchString.substr(result.index + result[0].length);
  1083.     }
  1084.     return formattedString;
  1085. };
  1086.  
  1087. Liquid_PatternFormat.prototype.ignoresThrowable = function () {
  1088.     return true;
  1089. };
  1090.  
  1091. Liquid_PatternFormat.prototype.toString = function () {
  1092.     return "PatternFormat";
  1093. };
  1094.    
  1095. //=======================================================================================
  1096. // Liquid_ConsoleAppender Object
  1097. //=======================================================================================
  1098.  
  1099. function Liquid_ConsoleAppender() {
  1100.  
  1101. };
  1102.  
  1103. Liquid_ConsoleAppender.prototype = new Liquid_LogAppender();
  1104. Liquid_ConsoleAppender.prototype.format = new Liquid_PatternFormat();
  1105. Liquid_ConsoleAppender.prototype.threshold = Liquid_LogLevel.Debug;
  1106.  
  1107. Liquid_ConsoleAppender.prototype.append = function (logevent) {
  1108.     var appender = this;
  1109.  
  1110.     var getFormattedMessage = function (concatenate) {
  1111.         var formattedMessage = appender.getFormat().formatWithException(logevent);
  1112.         return (typeof formattedMessage == "string") ?
  1113.             (concatenate ? formattedMessage : [formattedMessage]) :
  1114.             (concatenate ? formattedMessage.join(" ") : formattedMessage);
  1115.     };
  1116.  
  1117.     var console = window.console;
  1118.  
  1119.     if (console && console.log) {
  1120.         // Log to console using specific logging
  1121.         // methods or revert to console.log otherwise
  1122.         var consoleMethodName;
  1123.  
  1124.         if (console.debug && Liquid_LogLevel.Debug.isGreaterThanOrEqual(logevent.level)) {
  1125.             consoleMethodName = "debug";
  1126.         } else if (console.info && Liquid_LogLevel.Info.equals(logevent.level)) {
  1127.             consoleMethodName = "info";
  1128.         } else if (console.warn && Liquid_LogLevel.Warn.equals(logevent.level)) {
  1129.             consoleMethodName = "warn";
  1130.         } else if (console.error && logevent.level.isGreaterThanOrEqual(Liquid_LogLevel.Error)) {
  1131.             consoleMethodName = "error";
  1132.         } else {
  1133.             consoleMethodName = "log";
  1134.         }
  1135.  
  1136.         if (typeof console[consoleMethodName].apply == "function") {
  1137.             console[consoleMethodName].apply(console, getFormattedMessage(false));
  1138.         } else {
  1139.             console[consoleMethodName](getFormattedMessage(true));
  1140.         }
  1141.     } else if ((typeof opera != "undefined") && opera.postError) { // Opera
  1142.         opera.postError(getFormattedMessage(true));
  1143.     }
  1144. };
  1145.  
  1146. Liquid_EventSupport.prototype.group = function (name) {
  1147.     if (window.console && window.console.group) {
  1148.         window.console.group(name);
  1149.     }
  1150. };
  1151.  
  1152. Liquid_ConsoleAppender.prototype.groupEnd = function () {
  1153.     if (window.console && window.console.groupEnd) {
  1154.         window.console.groupEnd();
  1155.     }
  1156. };
  1157.  
  1158. Liquid_ConsoleAppender.prototype.toString = function () {
  1159.     return "ConsoleAppender";
  1160. };
  1161.    
  1162.    
  1163. //=======================================================================================
  1164. // Liquid_Log Object
  1165. //=======================================================================================
  1166.  
  1167. function Liquid_Log(name) {
  1168.     this.name = name;
  1169.     this.appenders = [];
  1170.     this.loggerlevel = null;
  1171.     this.appenderCache = null;
  1172.     this.children = [];
  1173.     this.parent = null;
  1174.     this.appenderCacheInvalidated = false;
  1175.     this.additive = true;
  1176.     this.isNull = (this.name === "[null]");
  1177.     this.isRoot = (this.name === "root");
  1178.     this.timers = {};
  1179. };
  1180.  
  1181.  
  1182. Liquid_Log.prototype.addChild = function (childLogger) {
  1183.     this.children.push(childLogger);
  1184.     childLogger.parent = this;
  1185.     childLogger.invalidateAppenderCache();
  1186. };
  1187.  
  1188.  
  1189. Liquid_Log.prototype.getAdditivity = function () {
  1190.     return this.additive;
  1191. };
  1192.  
  1193. Liquid_Log.prototype.setAdditivity = function (additivity) {
  1194.     var valueChanged = (this.additive != additivity);
  1195.     this.additive = additivity;
  1196.     if (valueChanged) {
  1197.         this.invalidateAppenderCache();
  1198.     }
  1199. };
  1200.  
  1201. Liquid_Log.prototype.addAppender = function (appender) {
  1202.     if (this.isNull) {
  1203.         Liquid.Logging.handleError("Liquid_Log.addAppender: you may not add an appender to the null logger");
  1204.     } else {
  1205.         if (appender instanceof Liquid_LogAppender) {
  1206.             if (!Liquid.Logging.arrayContains(this.appenders, appender)) {
  1207.                 this.appenders.push(appender);
  1208.                 appender.setAddedToLogger(this);
  1209.                 this.invalidateAppenderCache();
  1210.             }
  1211.         } else {
  1212.             Liquid.Logging.handleError("Liquid_Log.addAppender: appender supplied ('" +
  1213.                 Liquid.Logging.toStr(appender) + "') is not a subclass of Liquid_LogAppender");
  1214.         }
  1215.     }
  1216. };
  1217.  
  1218. Liquid_Log.prototype.removeAppender = function (appender) {
  1219.     Liquid.Logging.arrayRemove(this.appenders, appender);
  1220.     appender.setRemovedFromLogger(this);
  1221.     this.invalidateAppenderCache();
  1222. };
  1223.  
  1224. Liquid_Log.prototype.removeAllAppenders = function () {
  1225.     var appenderCount = this.appenders.length;
  1226.     if (appenderCount > 0) {
  1227.         for (var i = 0; i < appenderCount; i++) {
  1228.             this.appenders[i].setRemovedFromLogger(this);
  1229.         }
  1230.         this.appenders.length = 0;
  1231.         this.invalidateAppenderCache();
  1232.     }
  1233. };
  1234.  
  1235. Liquid_Log.prototype.getEffectiveAppenders = function () {
  1236.     if (this.appenderCache === null || this.appenderCacheInvalidated) {
  1237.         // Build appender cache
  1238.         var parentEffectiveAppenders = (this.isRoot || !this.getAdditivity()) ?
  1239.             [] : this.parent.getEffectiveAppenders();
  1240.         this.appenderCache = parentEffectiveAppenders.concat(this.appenders);
  1241.         this.appenderCacheInvalidated = false;
  1242.     }
  1243.     return this.appenderCache;
  1244. };
  1245.  
  1246. Liquid_Log.prototype.invalidateAppenderCache = function () {
  1247.     this.appenderCacheInvalidated = true;
  1248.     for (var i = 0, len = this.children.length; i < len; i++) {
  1249.         this.children[i].invalidateAppenderCache();
  1250.     }
  1251. };
  1252.  
  1253. Liquid_Log.prototype.log = function (level, params) {
  1254.     if (eval(Liquid.Param.LoggingEnabled) && level.isGreaterThanOrEqual(this.getEffectiveLevel())) {
  1255.         // Check whether last param is an exception
  1256.         var exception;
  1257.         var finalParamIndex = params.length - 1;
  1258.         var lastParam = params[finalParamIndex];
  1259.         if (params.length > 1 && lastParam instanceof Error) {
  1260.             exception = lastParam;
  1261.             finalParamIndex--;
  1262.         }
  1263.  
  1264.         // Construct genuine array for the params
  1265.         var messages = [];
  1266.         for (var i = 0; i <= finalParamIndex; i++) {
  1267.             messages[i] = params[i];
  1268.         }
  1269.  
  1270.         var loggingEvent = new Liquid_LogEvent(
  1271.             this, new Date(), level, messages, exception);
  1272.  
  1273.         this.callAppenders(loggingEvent);
  1274.     }
  1275. };
  1276.  
  1277. Liquid_Log.prototype.callAppenders = function (loggingEvent) {
  1278.     var effectiveAppenders = this.getEffectiveAppenders();
  1279.     for (var i = 0, len = effectiveAppenders.length; i < len; i++) {
  1280.         effectiveAppenders[i].doAppend(loggingEvent);
  1281.     }
  1282. };
  1283.  
  1284. Liquid_Log.prototype.setLevel = function (level) {
  1285.     // Having a level of null on the root logger would be very bad.
  1286.     if (this.isRoot && level === null) {
  1287.         Liquid.Logging.handleError("Liquid_Log.setLevel: you cannot set the level of the root logger to null");
  1288.     } else if (level instanceof Liquid_LogLevel) {
  1289.         this.loggerLevel = level;
  1290.     } else {
  1291.         Liquid.Logging.handleError("Liquid_Log.setLevel: level supplied to logger " +
  1292.             this.name + " is not an instance of Liquid_LogLevel");
  1293.     }
  1294. };
  1295.  
  1296. Liquid_Log.prototype.getLevel = function () {
  1297.     return this.loggerLevel;
  1298. };
  1299.  
  1300. Liquid_Log.prototype.getEffectiveLevel = function () {
  1301.     for (var logger = this; logger !== null; logger = logger.parent) {
  1302.         var level = logger.getLevel();
  1303.         if (level !== null) {
  1304.             return level;
  1305.         }
  1306.     }
  1307. };
  1308.  
  1309. Liquid_Log.prototype.group = function (name, initiallyExpanded) {
  1310.     if (eval(Liquid.Param.LoggingEnabled)) {
  1311.         var effectiveAppenders = this.getEffectiveAppenders();
  1312.         for (var i = 0, len = effectiveAppenders.length; i < len; i++) {
  1313.             effectiveAppenders[i].group(name, initiallyExpanded);
  1314.         }
  1315.     }
  1316. };
  1317.  
  1318. Liquid_Log.prototype.groupEnd = function () {
  1319.     if (eval(Liquid.Param.LoggingEnabled)) {
  1320.         var effectiveAppenders = this.getEffectiveAppenders();
  1321.         for (var i = 0, len = effectiveAppenders.length; i < len; i++) {
  1322.             effectiveAppenders[i].groupEnd();
  1323.         }
  1324.     }
  1325. };
  1326.  
  1327.  
  1328. Liquid_Log.prototype.time = function (name, level) {
  1329.     if (eval(Liquid.Param.LoggingEnabled)) {
  1330.         if (Liquid.Logging.isUndefined(name)) {
  1331.             Liquid.Logging.handleError("Liquid_Log.time: a name for the timer must be supplied");
  1332.         } else if (level && !(level instanceof Liquid_LogLevel)) {
  1333.             Liquid.logging.handleError("Logger.time: level supplied to timer " +
  1334.                 name + " is not an instance of Liquid_LogLevel");
  1335.         } else {
  1336.             this.timers[name] = new Liquid_LogTimer(name, level);
  1337.         }
  1338.     }
  1339. };
  1340.  
  1341. Liquid_Log.prototype.timeEnd = function (name) {
  1342.     if (eval(Liquid.Param.LoggingEnabled)) {
  1343.         if (Liquid.Logging.isUndefined(name)) {
  1344.             Liquid.Logging.handleError("Liquid_Log.timeEnd: a name for the timer must be supplied");
  1345.         } else if (this.timers[name]) {
  1346.             var timer = this.timers[name];
  1347.             var milliseconds = timer.getElapsedTime();
  1348.             this.log(timer.level, ["Timer " + Liquid.Logging.toStr(name) + " completed in " + milliseconds + "ms"]);
  1349.             delete this.timers[name];
  1350.         } else {
  1351.             LiquidLog.internalLog.warn("Liquid_Log.timeEnd: no timer found with name " + name);
  1352.         }
  1353.     }
  1354. };
  1355.  
  1356. Liquid_Log.prototype.assert = function (expr) {
  1357.     if (eval(Liquid.Param.LoggingEnabled) && !expr) {
  1358.         var args = [];
  1359.         for (var i = 1, len = arguments.length; i < len; i++) {
  1360.             args.push(arguments[i]);
  1361.         }
  1362.         args = (args.length > 0) ? args : ["Assertion Failure"];
  1363.         args.push("\r\n");
  1364.         args.push(expr);
  1365.         this.log(Liquid_LogLevel.Error, args);
  1366.     }
  1367. };
  1368.  
  1369. Liquid_Log.prototype.toString = function () {
  1370.     return "Liquid_Log [" + this.name + "]";
  1371. };
  1372.  
  1373.  
  1374. Liquid_Log.prototype.isLoggingEnabled = function () {
  1375.     return eval(Liquid.Param.LoggingEnabled);
  1376. };
  1377.  
  1378. Liquid_Log.prototype.trace = function () {
  1379.     this.log(Liquid_LogLevel.Trace, arguments);
  1380. };
  1381.  
  1382. Liquid_Log.prototype.debug = function () {
  1383.     this.log(Liquid_LogLevel.Debug, arguments);
  1384. };
  1385.  
  1386. Liquid_Log.prototype.info = function () {
  1387.     this.log(Liquid_LogLevel.Info, arguments);
  1388. };
  1389.  
  1390. Liquid_Log.prototype.warn = function () {
  1391.     this.log(Liquid_LogLevel.Warn, arguments);
  1392. };
  1393.  
  1394. Liquid_Log.prototype.error = function () {
  1395.     this.log(Liquid_LogLevel.Error, arguments);
  1396. };
  1397.  
  1398. Liquid_Log.prototype.fatal = function () {
  1399.     this.log(Liquid_LogLevel.fatal, arguments);
  1400. };
  1401.  
  1402. Liquid_Log.prototype.trace.isEntryPoint = true;
  1403. Liquid_Log.prototype.debug.isEntryPoint = true;
  1404. Liquid_Log.prototype.info.isEntryPoint = true;
  1405. Liquid_Log.prototype.warn.isEntryPoint = true;
  1406. Liquid_Log.prototype.error.isEntryPoint = true;
  1407. Liquid_Log.prototype.fatal.isEntryPoint = true;
  1408.  
  1409. //===========================================================================================
  1410. // Static Methods & Setup
  1411. //===========================================================================================
  1412.  
  1413. // Array of loggers and their names.
  1414. Liquid.Logging.Loggers = [];
  1415. Liquid.Logging.LoggerNames = [];
  1416.  
  1417. // Setup root logger.
  1418. var rootLogger = new Liquid_Log("root");
  1419. rootLogger.setLevel(Liquid_LogLevel.Debug);
  1420.  
  1421. // Static function retrieve the rootLogger
  1422. Liquid.Logging.getRootLogger = function () {
  1423.     return rootLogger;
  1424. };
  1425.  
  1426. // Setup null logger.
  1427. var nullLogger = null;
  1428. Liquid.Logging.getNullLogger = function () {
  1429.     if (!nullLogger) {
  1430.         nullLogger = new Liquid_Log("[null]");
  1431.         nullLogger.setLevel(Liquid_LogLevel.Off);
  1432.     }
  1433.     return nullLogger;
  1434. };
  1435.  
  1436. // Setup default logger.
  1437. var defaultLogger = null;
  1438. Liquid.Logging.getDefaultLogger = function () {
  1439.     if (!defaultLogger) {
  1440.         defaultLogger = Liquid.Logging.getLogger(Liquid.Param.DefaultLogName);
  1441.         var appender = new Liquid_ConsoleAppender();
  1442.         appender.setFormat(new Liquid_PatternFormat(Liquid.Param.LogPattern));
  1443.         defaultLogger.addAppender(appender);
  1444.         defaultLogger.setLevel(Liquid_LogLevel.Debug);
  1445.     }
  1446.     return defaultLogger;
  1447. };
  1448. // Static function to get a logger by name, if the given logger doesn't exists we create it.
  1449. Liquid.Logging.getLogger = function (loggerName) {
  1450.     // Use default logger if loggerName is not specified or invalid
  1451.     if (typeof loggerName != "string") {
  1452.         loggerName = "[anonymous]";
  1453.         LiquidLog.internalLog.warn("Liquid.Logging.getLogger: non-string logger name " +
  1454.             Liquid.Logging.toStr(loggerName) + " supplied, returning anonymous logger");
  1455.     }
  1456.  
  1457.     // Do not allow retrieval of the root logger by name
  1458.     if (loggerName == "root") {
  1459.         Liquid.Logging.handleError("Liquid.Logging.getLogger: root logger may not be obtained by name");
  1460.     }
  1461.  
  1462.     // Create the logger for this name if it doesn't already exist
  1463.     if (!Liquid.Logging.Loggers[loggerName]) {
  1464.         var logger = new Liquid_Log(loggerName);
  1465.         Liquid.Logging.Loggers[loggerName] = logger;
  1466.         Liquid.Logging.LoggerNames.push(loggerName);
  1467.  
  1468.         // Set up parent logger, if it doesn't exist
  1469.         var lastDotIndex = loggerName.lastIndexOf(".");
  1470.         var parentLogger;
  1471.         if (lastDotIndex > -1) {
  1472.             var parentLoggerName = loggerName.substring(0, lastDotIndex);
  1473.             parentLogger = Liquid.Logging.getLogger(parentLoggerName); // Recursively sets up grandparents etc.
  1474.         } else {
  1475.             parentLogger = rootLogger;
  1476.         }
  1477.         parentLogger.addChild(logger);
  1478.     }
  1479.     return Liquid.Logging.Loggers[loggerName];
  1480. };
  1481.  
  1482. // LiquidLog object, used internally.
  1483. function LiquidLogObj() {
  1484. }
  1485.  
  1486. LiquidLogObj.prototype = Object.create(Liquid_EventSupport.prototype);
  1487.  
  1488. var LiquidLog = new LiquidLogObj();
  1489.  
  1490. LiquidLog.setTypes(["load", "error"]);
  1491. var internalLog = new Liquid_InternalLog();
  1492. LiquidLog.internalLog = internalLog;
  1493.  
  1494.  
  1495. //=======================================================================================
  1496. // Main Execution & Plugin Handling
  1497. //=======================================================================================
  1498.  
  1499. (function () {
  1500.  
  1501.     var Liquid_Logging_Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
  1502.  
  1503.     Game_Interpreter.prototype.pluginCommand = function (command, args) {
  1504.  
  1505.         Liquid_Logging_Game_Interpreter_pluginCommand.call(this, command, args);
  1506.         // Process event commands.
  1507.         if (command === 'LiquidLog') {
  1508.  
  1509.             var loglevel = args[0];
  1510.             var logger = Liquid.Logging.getDefaultLogger();
  1511.             var msgStartIndex = 1;
  1512.             if ((loglevel === "info" || loglevel === "error" || loglevel === "warn" || loglevel != "debug" || loglevel === "fatal") != true) {
  1513.                 loglevel = "info";
  1514.             }
  1515.  
  1516.             var msg = "";
  1517.             for (msgStartIndex; msgStartIndex < args.length; msgStartIndex++) {
  1518.                 if (msgStartIndex < args.length) {
  1519.                     msg += args[msgStartIndex] + " ";
  1520.                 }
  1521.                 else {
  1522.                     msg += args[msgStartIndex];
  1523.                 }
  1524.             }
  1525.  
  1526.             switch (loglevel) {
  1527.                 case "info":
  1528.                     logger.info(msg);
  1529.                     break;
  1530.                 case "debug":
  1531.                     logger.debug(msg);
  1532.                     break;
  1533.                 case "warn":
  1534.                     logger.warn(msg);
  1535.                     break;
  1536.                 case "error":
  1537.                 case "fatal":
  1538.                     logger.error(msg);
  1539.                     break;
  1540.             }
  1541.         }
  1542.     };
  1543.  
  1544.  
  1545. })();
  1546.  
  1547. //===========================================================================================
  1548. // End of File
  1549. //===========================================================================================
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement