From: Siobhan Tully Date: Sun, 23 Feb 2014 19:23:34 +0000 (-0500) Subject: Added in support for new HPC Dashboard View, ability to retrieve HPC Dashboard view... X-Git-Url: http://git.onelab.eu/?p=plstackapi.git;a=commitdiff_plain;h=e18b3446e847dc64339db83990f2db9af6803b99 Added in support for new HPC Dashboard View, ability to retrieve HPC Dashboard view from views.py in separate function, support for log4javascript to provide integration with browser console for debugging, and leaflet support for MakiMarkers on encodings. --- diff --git a/planetstack/core/plus/views.py b/planetstack/core/plus/views.py index 386f6b5..b49e3a3 100644 --- a/planetstack/core/plus/views.py +++ b/planetstack/core/plus/views.py @@ -31,4 +31,147 @@ class DashboardWelcomeView(TemplateView): 'reservations': reservations}) context['userSliceInfo'] = userSliceInfo + context['cdnData'] = self.getCDNOperatorData(); return self.render_to_response(context=context) + + def getCDNOperatorData(self): + cdnData = { + "Arizona": { + "lat": 32.2333, + "long": -110.94799999999998, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 2, + "siteUrl": "http://www.cs.arizona.edu/" + }, + "I2 Singapore": { + "lat": 1.33544, + "long": 103.88999999999999, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 5, + "siteUrl": "http://www.internet2.edu/" + }, + "ON.Lab": { + "lat": 37.452955, + "long": -122.18176599999998, + "health": 0, + "numNodes": 45, + "numHPCSlivers": 12, + "siteUrl": "http://www.onlab.us/" + }, + "I2 Washington DC": { + "lat": 38.009, + "long": -77.00029999999998, + "health": 0, + "numNodes": 50, + "numHPCSlivers": 7, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Seattle": { + "lat": 47.6531, + "long": -122.31299999999999, + "health": 0, + "numNodes": 100, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Salt Lake City": { + "lat": 40.7659, + "long": -111.844, + "health": 0, + "numNodes": 35, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 New York": { + "lat": 40.72, + "long": -73.99000000000001, + "health": 0, + "numNodes": 25, + "numHPCSlivers": 4, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Los Angeles": { + "lat": 33.2505, + "long": -117.50299999999999, + "health": 0, + "numNodes": 20, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Kansas City": { + "lat": 39.0012, + "long": -94.00630000000001, + "health": 0, + "numNodes": 17, + "numHPCSlivers": 8, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Houston": { + "lat": 29.0077, + "long": -95.00369999999998, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Chicago": { + "lat": 41.0085, + "long": -87.00650000000002, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Atlanta": { + "lat": 33.0075, + "long": -84.00380000000001, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "MaxPlanck": { + "lat": 49.14, + "long": 6.588999999999942, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.mpi-sws.mpg.de/" + }, + "GeorgiaTech": { + "lat": 33.7772, + "long": -84.39760000000001, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.gatech.edu/" + }, + "Princeton": { + "lat": 40.3502, + "long": -74.6524, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://princeton.edu/" + }, + "Washington": { + "lat": 47.6531, + "long": -122.31299999999999, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "https://www.washington.edu/" + }, + "Stanford": { + "lat": 37.4294, + "long": -122.17200000000003, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.stanford.edu/" + }, + } + return cdnData + diff --git a/planetstack/core/static/js/Leaflet.MakiMarkers.js b/planetstack/core/static/js/Leaflet.MakiMarkers.js new file mode 100644 index 0000000..910bb31 --- /dev/null +++ b/planetstack/core/static/js/Leaflet.MakiMarkers.js @@ -0,0 +1,101 @@ +/* + * Leaflet plugin to create map icons using Maki Icons from MapBox. + * + * References: + * Maki Icons: https://www.mapbox.com/maki/ + * MapBox Marker API: https://www.mapbox.com/developers/api/#Stand-alone.markers + * + * Usage: + * var icon = L.MakiMarkers.icon({icon: "rocket", color: "#b0b", size: "m"}); + * + * License: + * MIT: http://jseppi.mit-license.org/ + */ +(function () { + "use strict"; + L.MakiMarkers = { + // Available Maki Icons + icons: ["circle-stroked", "circle", "square-stroked", "square", + "triangle-stroked", "triangle", "star-stroked", "star", "cross", + "marker-stroked", "marker", "religious-jewish", "religious-christian", + "religious-muslim", "cemetery", "rocket", "airport", "heliport", "rail", + "rail-metro", "rail-light", "bus", "fuel", "parking", "parking-garage", + "airfield", "roadblock", "ferry", "harbor", "bicycle", "park", "park2", + "museum", "lodging", "monument", "zoo", "garden", "campsite", "theatre", + "art-gallery", "pitch", "soccer", "america-football", "tennis", "basketball", + "baseball", "golf", "swimming", "cricket", "skiing", "school", "college", + "library", "post", "fire-station", "town-hall", "police", "prison", + "embassy", "beer", "restaurant", "cafe", "shop", "fast-food", "bar", "bank", + "grocery", "cinema", "pharmacy", "hospital", "danger", "industrial", + "warehouse", "commercial", "building", "place-of-worship", "alcohol-shop", + "logging", "oil-well", "slaughterhouse", "dam", "water", "wetland", + "disability", "telephone", "emergency-telephone", "toilets", "waste-basket", + "music", "land-use", "city", "town", "village", "farm", "bakery", "dog-park", + "lighthouse", "clothing-store", "polling-place", "playground", "entrance", + "heart", "london-underground", "minefield", "rail-underground", "rail-above", + "camera", "laundry", "car", "suitcase", "hairdresser", "chemist"], + defaultColor: "#0a0", + defaultIcon: "circle-stroked", + defaultSize: "m", + apiUrl: "https://api.tiles.mapbox.com/v3/marker/", + smallOptions: { + iconSize: [20, 50], + popupAnchor: [0,-20] + }, + mediumOptions: { + iconSize: [30,70], + popupAnchor: [0,-30] + }, + largeOptions: { + iconSize: [36,90], + popupAnchor: [0,-40] + } + }; + + L.MakiMarkers.Icon = L.Icon.extend({ + options: { + //Maki icon: any from https://www.mapbox.com/maki/ (ref: L.MakiMarkers.icons) + icon: L.MakiMarkers.defaultIcon, + //Marker color: short or long form hex color code + color: L.MakiMarkers.defaultColor, + //Marker size: "s" (small), "m" (medium), or "l" (large) + size: L.MakiMarkers.defaultSize, + shadowAnchor: null, + shadowSize: null, + shadowUrl: null, + className: 'maki-marker' + }, + + initialize: function(options) { + var pin; + + options = L.setOptions(this, options); + + switch (options.size) { + case "s": + L.extend(options, L.MakiMarkers.smallOptions); + break; + case "l": + L.extend(options, L.MakiMarkers.largeOptions); + break; + default: + options.size = "m"; + L.extend(options, L.MakiMarkers.mediumOptions); + break; + } + + if (options.color.charAt(0) === '#') { + options.color = options.color.substr(1); + } + + pin = "pin-" + options.size + "-" + options.icon + "+" + + options.color + ".png"; + + options.iconUrl = "" + L.MakiMarkers.apiUrl + pin; + } + }); + + L.MakiMarkers.icon = function(options) { + return new L.MakiMarkers.Icon(options); + }; +})(); diff --git a/planetstack/core/static/log4javascript-1.4.6/changelog.txt b/planetstack/core/static/log4javascript-1.4.6/changelog.txt new file mode 100644 index 0000000..fe10b97 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/changelog.txt @@ -0,0 +1,379 @@ +log4javascript change log +------------------------- + +1.4.6 (19/3/2013) +- Added fix to handle 1223 status code from XMLHttpRequest in IE + +1.4.5 (20/2/2013) +- Changed AjaxAppender to send raw data rather than URL-encoded form data when + content-type is not "application/x-www-form-urlencoded" + +- Exposed sendAllRemaining() method of AjaxAppender + +1.4.4 (8/2/2013) +- Fixed issue with repeated Content-Type headers in AjaxAppender + +- Improved uniqueness of PopUpAppender window name + +1.4.3 (18/9/2012) +- Added addHeader() and getHeaders() methods to AjaxAppender + +- Modified sendAllOnUnload feature of AjaxAppender. It now works in WebKit but + at the expense of popping up a confirm dialog. That being the case, it is now + disabled by default. + +- Removed leaked global variable "initialized" + +- Fixed bugs #3528265, #3560924, #3560922, #2805479, #3510639 on Sourceforge + Tracker + + +1.4.2 (13/10/2011) +- Fixed JsonLayout trailing comma issue. See + http://stackoverflow.com/questions/7735382/asmx-weirdness-deserializing-json- + blob-from-log4javascript-logging + +- Fixed bugs #3401332, #3185753, #2884623, #2817213 on Sourceforge Tracker + + +1.4.1 (23/3/2009) +- Fixed document.domain/query string bug (#2519903 on Sourceforge Tracker) + +- Added isVisible() method to PopUpAppender + +- Added check for whether the console has been closed in isVisible() method of + InPageAppender + +- Included unit tests in the distribution + + +1.4 (30/10/2008) + +- Added time() and timeEnd() methods to Logger + +- Added group() and groupEnd() methods to Logger and support for displaying + expandable groups to InPageAppender and PopUpAppender + +- Added facility to layout custom fields. A custom field value may now + optionally be a function which is passed a reference to the layout and a + logging event and run at the time the layout's format method is called + +- Added option to XmlLayout and JsonLayout to allow multiple messages to be + formatted either as one combined message or multiple messages + +- Added code to set log4javascript as a property of the window object. This + ensures that if log4javascript is loaded via eval() (e.g. Dojo's module + loading system), the log4javascript object is guaranteed to be available even + though IE does not evaluate the script in the global scope + +- Added useDocumentWrite parameter to constructors and isUseDocumentWrite() + and setUseDocumentWrite() methods for InPageAppender and PopUpAppender and + added console.html to the build so that the appender may use either the + existing document.write method or the external HTML file to build the console. + This is to allow support for setting document.domain in the main document, + which is impossible with the document.write method + +- Added milliseconds property to logging events and changed JsonLayout, + XmlLayout and HttpPostDataLayout to include milliseconds by default + +- Added layout parameter to AjaxAppender and a toString() method on each layout + +- Setting configuration properties in appenders via constructor paramaters has + been phased out. + +- Added window.unload handler for AjaxAppender to send outstanding messages. + Doesn't work in Opera + +- Implemented log4j-style hierarchical loggers with additive appenders. For + example, a logger called "app.stuff" has as its parent the logger called + "app", all of whose appenders it inherits + +- Changed XmlLayout and JsonLayout to send data as a key/value pair + +- Bugfix for inaccessible error details + +- An appender can no longer be added more than once to the same logger + +- Multiple messages may now be specified in logger methods + +- New conversion character 'a' added to PatternLayout. This is the same as 'm' + except that if the first message specified is an array then it treats each + element of the array as though it had been passed in as a message parameter + +- Command line added to console windows with configurable object expansion + depth. Command line presence and object expansion depth are configurable in + the appender via setShowCommandLine() and setCommandLineObjectExpansionDepth() + methods respectively + +- Command line history, navigated by cursor keys and stored in a session cookie + +- Firebug-inspired command line functions added: $, dir, dirxml, cd, clear, + keys, values, expansionDepth + +- Fixes for several bugs in object expansion + +- Fix for bug in initialization of InPageAppender in IE 5 + +- Fix to allow searchable HTML in log entries + +- Fix for bug which automatically displayed search next/previous buttons when + the search box is clicked regardless of whether there were any matches + +- Searches in PopUpAppender and InPageAppender now preserve formatting + +- More fixes to interaction of search and severity filters in console window + used by PopUpAppender and InPageAppender + +- Added SwitchableConsoleAppender that allows flipping from an in-page console + to a pop-up console window and back again while retaining state + +- Custom events added that are raised when PopUpAppender and InPageAppender + windows load and unload, and on the main log4javascript object when the main + page loads, when the main page is resized and when log4javascript errors occur + +- InPageAppender may now be initialized before the page loads by providing an + element id for its container, or omitting the container altogether (in which + case the appender is added as a fixed div at the bottom of the page) + +- Tweaked PopUpAppender and InPageAppender so that the formatted log message is + produced when append() is called rather than when the message is actually sent + to the console window, thus allowing reliable temporary switching of layouts + +- Much improved scrolling to current search match: scrolls only if part of the + search match is not visible and centres around it rather than putting flush to + the top left + +- Removed setReadable() method from JsonLayout - now specified only in the + constructor + +- Fixed problem in IE where copying selections of log entries would produce two + copies of each log entry + + +1.3.1 (20/11/2006) + +- Fix to interaction of search and severity filters in console window used by + PopUpAppender and InPageAppender + + +1.3 (19/10/2006) + +- Fully tested and supported in IE 7 Beta 3 + +- Added support for FireBug logging levels in BrowserConsoleAppender + +- Added optional limit to the number of log messages stored by PopUpAppender and + InPageAppender. When this limit is reached, each new message causes the oldest + message to be discarded. + +- Exceptions passed into logging methods are now displayed in logging output. + +- Added facility to pass objects as well as strings to logging methods. + Enhanced conversion character 'm' to PatternLayout to expand object properties + in the formatted output + +- Added stack trace to error reports (alerts and log entries) in Firefox. This + is turned off by default but can be switched on via the new + log4javascript.setShowStackTraces function + +- Added log4javascript_stub.js to distribution - this has stub versions of all + objects and methods in log4javascript.js and can be used as a lightweight + replacement for log4javascript.js in production systems + +- Added log4javascript_compressed.js to distribution - comments and whitespace + are removed, resulting in a 30% smaller file + +- Added custom fields to layouts + +- Added setReopenWhenClosed and isReopenWhenClosed methods to PopUpAppender to + allow log4javascript to open a new pop-up console window automatically at the + time of the next log entry after the original window was closed + +- Layout.ignoresThrowable implemented to allow Layout/Appender combinations to + decide whether to display exceptions + +- Added NullLayout that performs no formatting on the logging event + +- Lowered BrowserConsoleAppender's default threshold to DEBUG and set its + default layout to NullLayout so that unformatted objects can be passed into + FireBug + +- Renamed InlineAppender to InPageAppender (though InlineAppender still works + for the sake of backwards compatibility) + +- Cosmetic changes to InPageAppender and PopUpAppender + +- Added equals() method to Level + +- Added removeAppender() and removeAllAppenders() methods to Logger + +- Added extensive test script + +- Fixed bug where Appender.setLayout and Appender.setThreshold threw an + unhandled error if not supplied with a genuine Layout or Level respectively + +- Fixed bug where InlinePopUpAppender and PopUpAppender continue to poll their + console windows indefinitely (thus generating warnings) if the console window + is closed before it has fully loaded + +- Fixed bug in w and W symbols in SimpleDateFormat + +- Fixed bug with quotes inside messages in JsonLayout + +- Fixed bugs in PatternLayout with built-in DATE format and truncation modifiers + +- Changed execution order of callbacks in AjaxAppender so that + requestSuccessCallback is guaranteed to be called before the next request is + sent + +- Changed AjaxAppender so that log messages are formatted immediately before + a request is sent rather than when append() is called, thus guaranteeing that + changes to the layout take effect immediately + +- PopUpAppender windows now have unique names per hostname to prevent clashes + from multiple instances of log4javascript running on different servers + +- Fixed error in XmlLayout's format method when passed an object + +- Fixed errors in JsonLayout's handling of strings containing line breaks and/or + double quotes + + +1.2 (21/6/2006) + +- Tested in and added workaround for a bug in Opera 9 Beta 2 and Opera 9.0 + +- Tested in Konqueror 3.4 and 3.5 and added workarounds and fixes for browser + bugs + +- Added addErrorListener and removeErrorListener methods to log4javascript + object to allow custom error handling + +- Added close() method to PopUpAppender and InlineAppender + +- Added test directory with an HTML page containing automated tests + +- Added enable/disable logging checkbox to InlinePopUpAppender and PopUpAppender + so that unnecessary messages (for instance, from a timer) can be ignored + +- An invalid value supplied to a configuration option setter now leaves config + property unchanged rather than reverting to the default + +- Fixed bug in PopUpAppender in IE on Windows XP Service Pack 2 when accessed + via the file system. The browser by default disables JavaScript in the pop-up + window until the user opts to enable it, at which point they would previously + see an uncaught error in log4javascript. Now, a proper error message is + displayed and the appender is disabled. + +- Slight alterations to toolbar in InlineAppender and PopUpAppender - text + capitalization and title attributes added to inputs + +- toString() method added to all appenders + +- Correction to errors in XmlLayout's output + +- Documentation corrections and additions + + +1.1.1 (17/5/2006) + +- Fixed a minor bug with scrolling to the latest message and added "scroll to + latest" checkbox to console window in InlineAppender and PopUpAppender + + +1.1 (16/5/2006) + +- Added configuration option setters on Appenders and refactored to prevent + config properties being altered directly. Several configuration options + may not be altered after the appender has been initialized + +- Added scrollToLatestMessage constructor parameter, isScrollToLatestMessage + and setScrollToLatestMessage methods to InlineAppender and PopUpAppender + +- Added isVisible method to InlineAppender + +- Changed setShowOneError to setAlertAllErrors in logLog, with obvious change + in logic + +- Added layout property key configuration options to layout constructors for + JsonLayout and HttpPostDataLayout + +- Changed the default timestamp property name to "timestamp" instead of + "timeStamp" in JsonLayout and HttpPostDataLayout + +- Expanded documentation to include a section in the manual about configuring + appenders + +- Removed browser sniffing code + + +1.0.1 (30/4/2006) + +- Option to have new log messages appear at the top added to InlineAppender and + PopUpAppender. This option can be specified in the constructor and can also + be toggled via a checkbox in the console window + +- PopUpAppender changed to not focus the pop-up console window by default, and + the demo page altered to create its own logger with focussing turned on, + meaning the behaviour in the demo is essentially unchanged + + +1.0 (26/4/2006) + +- Tweaks to default values in PopUpAppender and InlineAppender + +- Bugfixes and stylistic tweaks resulting from running JSLint on + log4javascript.js + + +1.0 beta 2 + +- Show/hide button removed from InlineAppender, replaced by show() and hide() + methods on the InlineAppender object + +- batchSeparator, batchHeader and batchFooter added to Layout and applied to + JsonLayout - a batch of JSON log messages is now created as an array literal + + +1.0 beta + +- TRACE level added, since this was added to log4j in 1.2.12 + +- PopUpAppender default settings bugfix + +- getLevel method added to Logger + +- Tweak to vertical alignment of checkboxes and padding of buttons in + InlineAppender and PopUpAppender + +- Fixed getDefaultLogger and getNullLogger to return loggers other than the + root logger + +0.96 + +- Moved console.html to inline document.writes in log4javascript.js + +- Fixed getDefaultLogger to return the same object on successive calls + +- Fixed scrolling issue in Opera InlineAppender and PopUpAppender + +- Scrollbars are now automatic on InlineAppender and PopUpAppender, i.e. they + only appear when required + +- Fixed bug where regex searches were not applied to new log entries in + InlineAppender and PopUpAppender + +- Changed Safari font size in InlineAppender and PopUpAppender + +0.95 + +- AjaxAppender enhancements: + - waitForResponse added + - timer added + +- layout parameter added to all appender constructors + +0.94 +- First publicly available version +- IE 5 support added +- Full support for wrapping in IE added for InlineAppender and PopUpAppender \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/console.html b/planetstack/core/static/log4javascript-1.4.6/console.html new file mode 100644 index 0000000..476d272 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/console.html @@ -0,0 +1,263 @@ + + + +log4javascript + + + + + + + + + + +
+
+
+Filters: + + + + + + + +
+ +
+Options: + + + + + + + +
+
+
+
+
+
+ + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/console_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/console_uncompressed.html new file mode 100644 index 0000000..55679f8 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/console_uncompressed.html @@ -0,0 +1,2279 @@ + + + + log4javascript + + + + + + + + + + + +
+
+
+ Filters: + + + + + + + +
+ +
+ Options: + + + + + + + +
+
+
+
+
+
+ + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/basic.html b/planetstack/core/static/log4javascript-1.4.6/demos/basic.html new file mode 100644 index 0000000..51d5857 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/demos/basic.html @@ -0,0 +1,159 @@ + + + + + log4javascript basic demo + + + + + + + + + +
+ +
+ +

log4javascript basic demo

+

+ NB. Since the demo below uses pop-up windows, you will + need to disable any pop-up blockers you may have for it to work. +

+

+ This demo demonstrates the default logger. For more options, please see the + demos area. +

+

+ Enter a log message below and click on one of the buttons to log + your message at your desired level. You can then filter by + log level, toggle word-wrapping and perform text and regular + expression searches on the log entries. +

+
+ + + + + + +
+ + +
+ Generate random log entries + +
+ + +
+ +
+ + + +
+ + + +
+
+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/blank.html b/planetstack/core/static/log4javascript-1.4.6/demos/blank.html new file mode 100644 index 0000000..7e8ac56 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/demos/blank.html @@ -0,0 +1,4 @@ + +Blank page + + \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/index.html b/planetstack/core/static/log4javascript-1.4.6/demos/index.html new file mode 100644 index 0000000..00e84ac --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/demos/index.html @@ -0,0 +1,49 @@ + + + + + log4javascript demos + + + + + + + +
+ +
+ +

log4javascript demos

+ +
+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/inpage.html b/planetstack/core/static/log4javascript-1.4.6/demos/inpage.html new file mode 100644 index 0000000..8e47d72 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/demos/inpage.html @@ -0,0 +1,174 @@ + + + + + log4javascript in-page console demo + + + + + + + + + +
+ +
+ +

log4javascript in-page console demo

+

+ This demo demonstrates an in-page logger. The example uses the default behaviour, which + is to place the log console in a fixed area at the bottom of the page. However, the + console may be placed inside any element in the page. To do this, you may specify the ID + of the element (even if the page has not yet loaded) or a reference to the element itself. +

+

+ Enter a log message below and click on one of the buttons to log + your message at your desired level. You can then filter by + log level, toggle word-wrapping and perform text and regular + expression searches on the log entries. +

+
+ +
+ + + + + + +
+ + +
+ Generate random log entries + +
+ + +
+ +
+ + + +
+ + + +
+
+
+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/lite.html b/planetstack/core/static/log4javascript-1.4.6/demos/lite.html new file mode 100644 index 0000000..a1d2dd3 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/demos/lite.html @@ -0,0 +1,148 @@ + + + + + log4javascript lite demo + + + + + + + + + +
+ +
+ +

log4javascript lite demo

+

+ NB. Since the demo below uses pop-up windows, you will + need to disable any pop-up blockers you may have for it to work. +

+

+ This demo demonstrates the lite edition of log4javascript. +

+

+ Enter a log message below and click on one of the buttons to log + your message at your desired level. +

+
+ + + + + + + +
+ Generate random log entries + +
+ + +
+ +
+
+
+
+ +
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html b/planetstack/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html new file mode 100644 index 0000000..f212fd4 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html @@ -0,0 +1,90 @@ + + + + + log4javascript - backwards incompatibilities in version 1.4 + + + + + + + +
+ +
+ +

Backwards incompatibilities in log4javascript 1.4

+
    +
  • + Loggers are now hierarchical. This means logger names containing full stops have + special meaning. For example, from version 1.4 the logger named myapp.ajax + by default inherits all the appenders of the logger named myapp, while + prior to version 1.4 these loggers would be entirely independent; +
  • +
  • + The signature of the log method of Logger has changed. + However, you should not use this method directly; instead, use one of the level-specific + wrapper functions (debug, info, error etc.); +
  • +
  • + Appenders can no longer be configured via constructor parameters. Instead you must use + setter methods; +
  • +
  • + The format of requests sent via AjaxAppender + has changed when using JsonLayout or + XmlLayout: the formatted log messages are sent + as a name-value pair (with default name data) rather than a single unencoded string; +
  • +
  • + All timestamps returned by XmlLayout, + JsonLayout and + HttpPostDataLayout are + now measured in milliseconds since January 1st 1970 (previously they were returned + as seconds since January 1st 1970); +
  • +
  • + The constructors for JsonLayout and + HttpPostDataLayout have changed; the property names + used for the properties of the logging event are now set via setKeys rather than + in the constructor; +
  • +
  • + setReadable has been removed from JsonLayout. + The readable property should now be set via the constructor; +
  • +
  • + addErrorListener and removeErrorListener removed from + the log4javascript object and replaced with the more generic + addEventListener + and removeEventListener methods. The listener functions are passed + different parameters. +
  • +
+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/distribution.html b/planetstack/core/static/log4javascript-1.4.6/docs/distribution.html new file mode 100644 index 0000000..8f6cdfd --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/docs/distribution.html @@ -0,0 +1,87 @@ + + + + + log4javascript 1.4 distribution + + + + + + + +
+ +
+ +

log4javascript 1.4 distribution

+

+ From version 1.4 the distribution includes three different editions of log4javascript: +

+
    +
  • +
    Standard Edition
    +

    + Equivalent to log4javascript from earlier versions and suitable for general JavaScript + debugging and logging (including via Ajax). +

    +
  • +
  • +
    Production Edition
    +

    + Designed for use in production systems where the focus is solely on logging JavaScript + messages back to the server. Consequently this edition omits all appenders except + AjaxAppender, resulting in a drastically reduced + file size compared to the standard edition. +

    +
  • +
  • +
    Lite Edition
    +

    + A lightweight version of log4javascript for quick page debugging. Included is a single logger + using a basic pop-up window appender with a fixed layout. +

    +
  • +
+

+ Each edition comes in compressed and uncompressed versions. The compressed version is + functionally identical to the uncompressed version but has had whitespace and comments removed + and therefore downloads more quickly. +

+

+ Each edition also comes with a stub version. This contains dummy implementations of all + log4javacript objects and methods in the public API, making it ideal for production environments + where logging is not required. Replacing the main log4javascript script file with this file + means that log calls may be left in production code. Compressed and uncompressed versions of + each stub are included. +

+

+ Finally, each edition comes with a suite of unit tests, available as HTML pages in the + test/ directory. Note that these tests crash old versions (pre-3.1) of Safari. Sorry. +

+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/index.html b/planetstack/core/static/log4javascript-1.4.6/docs/index.html new file mode 100644 index 0000000..d3b3ac2 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/docs/index.html @@ -0,0 +1,190 @@ + + + + + log4javascript documentation + + + + + + + +
+ +
+

log4javascript 1.4 documentation

+ + +
+

What it is

+

+ log4javascript is a JavaScript logging framework based on the Java + logging framework log4j. +

+

+ log4javascript implements a subset of log4j (primarily loggers, appenders + and layouts) and has a few convenience methods of its own for + quick JavaScript development. It can be used to debug JavaScript + applications of all sizes, including Ajax applications. +

+

+ If you just want to start using it, try the quickstart + tutorial. +

+

+ Top +

+
+
+

Who it's for

+

+ log4javascript is aimed at JavaScript developers. +

+

+ Top +

+
+
+

Note on previous versions

+

+ Documentation for previous versions of log4javascript are not available here. + However, documentation is bundled with every previous version, all of which + are available to download. +

+
+
+

Features

+
    +
  • can be initialized with one JavaScript include and one line of code;
  • +
  • + by default logs to a pop-up console window with powerful search (including + regular expression) and filtering features. This console window can also + be used inline as an iframe in the main page; +
  • +
  • + can send log messages to the server via HTTP (Ajax, if you like); +
  • +
  • + highly configurable using familiar methods from log4j, including the + powerful PatternLayout + which gives the developer complete control over the format of the log messages. +
  • +
+

+ Top +

+
+
+

Browser support

+

Fully supported browsers:

+
    +
  • All versions Firefox back to 0.6
  • +
  • Other Mozilla-based browsers, as far back as Netscape 7
  • +
  • Internet Explorer 5 and higher for Windows
  • +
  • Safari 1.3 and higher (untested on earlier versions)
  • +
  • Opera 8.01 and higher (pre- version 9 browsers have a rendering + bug related to scrolling that affects searching in PopUpAppender and InPageAppender)
  • +
  • Konqueror 3.4.3 and higher (untested on earlier versions)
  • +
  • Google Chrome
  • +
+

Partially supported browsers:

+
    +
  • Older Mozilla-based browsers, e.g. Netscape 6.2 (generally OK except for + display problems searching and filtering PopUpAppender and InPageAppender)
  • +
  • Opera 7.0 - 8.0 (InPageAppender not supported until version 7.5, plus some display + problems searching PopUpAppender and InPageAppender. AjaxAppender not supported at all)
  • +
+

Unsupported browsers:

+
    +
  • + Internet Explorer for Mac. There are no plans to make log4javascript work + in this browser. +
  • +
+

+ Top +

+
+
+

Licence

+

+ log4javascript is licenced under the Apache License, + Version 2.0. The Apache website has more details. +

+

+ Top +

+
+
+

Further reading

+

+ In order to gain an understanding of the ideas behind log4j and therefore log4javascript, + I highly recommend reading the short + introduction to log4j from the log4j website. log4javascript borrows heavily from + log4j but does not carry over all its concepts - for example, Filters and Renderers are not + implemented. +

+

+ The full log4javascript manual +

+

+ Top +

+
+
+ +
+ + + \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/lite.html b/planetstack/core/static/log4javascript-1.4.6/docs/lite.html new file mode 100644 index 0000000..11b4684 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/docs/lite.html @@ -0,0 +1,182 @@ + + + + + log4javascript 1.4 Lite + + + + + + + + + + +
+ +
+ +

log4javascript 1.4 Lite

+

Contents

+ +
+

Introduction

+

+ log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It + provides functions to log messages of different severity to a pop-up window using the exactly + the same syntax as log4javascript. +

+

+ Top +

+
+
+

Code

+

+ You can copy the code for log4javascript Lite below: +

+ +

+ Press this button to copy the code to the clipboard: + +

+

+ You can either paste the above code inside a script tag: +

+
+<script type="text/javascript">
+	... [Code here]...
+</script>
+
+

+ ... or include the log4javascript_lite.js included in the distribution: +

+
+<script type="text/javascript" src="log4javascript_lite.js"></script>
+
+
+<script type="text/javascript">
+	var log = log4javascript.getDefaultLogger();
+</script>
+
+

+ Using log4javascript Lite is identical to using log4javascript with its default logger: +

+
+<script type="text/javascript">
+	var log = log4javascript.getDefaultLogger();
+	log.debug("What's going on here then?");
+</script>
+
+

+ Top +

+
+
+

API

+

+ The functions available in log4javascript Lite make up a small subset of those provided + by log4javascript proper. Each function is named and called identically to the equivalent + function in log4javascript. Full details can be found in the + log4javascript Lite manual. +

+

+ Top +

+
+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/manual.html b/planetstack/core/static/log4javascript-1.4.6/docs/manual.html new file mode 100644 index 0000000..defac9c --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/docs/manual.html @@ -0,0 +1,3198 @@ + + + + + log4javascript 1.4 manual + + + + + + + +
+ +
+ +

log4javascript 1.4 manual

+

Contents

+ +
+

Introduction

+

+ Anyone who has done a reasonable amount of JavaScript development will be + familiar with alert as a means of debugging. For + a small script, it works fine. But for anything of greater complexity than, + say, a rollover script its shortcomings become apparent. The most obvious problem + is the endless clicking of 'OK'. Another problem is that for a page + heavily reliant on events generated from user actions, alerts + can actually alter the way the page behaves. One final problem is infinite loops: + without alerts, the browser will notice that the script has messed + up and will offer the user the chance to stop the script running. With an + alert inside an infinite loop, you're forced to kill the browser. +

+

+ At the other end of the scale there is + Venkman, + a full-on JavaScript debugger for Mozilla-based browsers such as Firefox. Here + I have to confess that I simply have not put in the time to learn how to make + it work well for me and I suspect I am not alone. +

+

+ Nowadays, easily the best option for day-to-day JavaScript development is the brilliant + Firebug, a Firefox plugin with built-in debugger, console, logging, + and profiler. It's a seriously impressive tool but by its very nature as a Firefox + plugin can only be used in one of the typical target browsers for mainstream web + development. +

+

+ log4javascript was originally written as a cross-browser tool to ease the pain of JavaScript + debugging without the time investment required to use a debugger effectively. It requires + only a JavaScript include and one line of code to initialize with default settings. + Having for several years used log4j and its .NET port log4net, it was natural for me to + base it on log4j. +

+

+ log4javascript is by no means the only JavaScript logging framework out there. + It is not even the only JavaScript implementation of log4j. It turns out the name + log4javascript is used by another JavaScript logging framework, and that the name log4js is + used by at least two other pieces of software; this version of log4javascript is unrelated + to any of those. +

+

+ Top +

+
+
+

Note about the log4javascript object

+

+ All of log4javascript's instantiable classes are accessible via the log4javascript object, which + acts as a namespace. Therefore references to all class names must be preceded with "log4javascript.". + For example: +

+

+ var popUpAppender = new log4javascript.PopUpAppender(); +

+

+ Top +

+
+
+

Loggers, Appenders, Layouts and Levels

+

+ A logger in log4javascript is the object on which log calls are + made. A logger may be assigned zero or more appenders. + An appender is an object that actually does the logging: for example, + a PopUpAppender logs messages to + a pop-up console window while an AjaxAppender + uses HTTP to send log messages back to the server. Each appender is assigned + a layout, which is responsible for formatting log messages that + are passed to an appender. +

+

+ Every log message has a level. This is the severity of the message. + Available levels are TRACE, DEBUG, INFO, + WARN, ERROR and FATAL - these correspond to + the logging methods trace, debug, info, + warn, error and fatal of Logger. + Levels are ordered as follows: TRACE < DEBUG < + INFO < WARN < ERROR < + FATAL. This means the FATAL is the most severe and + TRACE the least. Also included are levels called ALL + and OFF intended to enable or disable all logging respectively. +

+

+ Both loggers and appenders also have threshold levels (by default, DEBUG + for loggers and ALL for appenders). + Setting a level to either a logger or an appender disables log messages of severity + lower than that level. For instance, if a level of INFO is set on a + logger then only log messages of severity INFO or greater will be logged, + meaning DEBUG and TRACE messages will not be logged. If the + same logger had two appenders, one of level DEBUG and one of level + WARN then the first appender will still only log messages of + INFO or greater while the second appender will only log messages of level + WARN or greater. +

+

+ This allows the developer fine control over which messages get logged where. +

+
+

Configuring appenders

+

+ From version 1.4, configuring appenders is only possible via configuration + methods. As the number of configuration options increases it becomes increasingly + undesirable to use constructor parameters, so support for it has been dropped. +

+
+
+

Example

+

+ NB. The Ajax side of this example relies on having + server-side processing in place. +

+

+ First, log4javascript is initialized, and a logger (actually the + anonymous logger) is assigned to a variable called log: +

+
+<script type="text/javascript" src="log4javascript.js"></script>
+<script type="text/javascript">
+	//<![CDATA[
+	var log = log4javascript.getLogger();
+
+

+ log does not yet have any appenders, so a call to log.debug() + will do nothing as yet. For this example we will use a + PopUpAppender for debugging purposes. + Since the lifespan of the messages displayed in the pop-up is only going to be the + same as that of the window, a PatternLayout + is used that displays the time of the message and not the date (note that this is + also true of PopUpAppender's default layout). The format of the string passed into + PatternLayout is explained below. +

+
+	var popUpAppender = new log4javascript.PopUpAppender();
+	var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");
+	popUpAppender.setLayout(popUpLayout);
+	log.addAppender(popUpAppender);
+
+

+ Suppose that we also want to send log messages to the server, but limited to + error messages only. To achieve this we use an + AjaxAppender. Note that if no layout is + specified then for convenience a default layout is used; in the case of + AjaxAppender, that is HttpPostDataLayout, + which formats log messages as a standard HTTP POST string from which a simple + server-side script (not provided with log4javascript) will be able to extract + posted parameters. This is fine for our purposes: +

+
+	var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");
+	ajaxAppender.setThreshold(log4javascript.Level.ERROR);
+	log.addAppender(ajaxAppender);
+
+

+ Finally, some test log messages and the closing script tag: +

+
+	log.debug("Debugging message (appears in pop-up)");
+	log.error("Error message (appears in pop-up and in server log)");
+	//]]>
+</script>
+
+

+ The full script: +

+
+<script type="text/javascript" src="log4javascript.js"></script>
+<script type="text/javascript">
+	//<![CDATA[
+	var log = log4javascript.getLogger();
+	var popUpAppender = new log4javascript.PopUpAppender();
+	var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");
+	popUpAppender.setLayout(popUpLayout);
+	log.addAppender(popUpAppender);
+	var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");
+	ajaxAppender.setThreshold(log4javascript.Level.ERROR);
+	log.addAppender(ajaxAppender);
+	log.debug("Debugging message (appears in pop-up)");
+	log.error("Error message (appears in pop-up and in server log)");
+	//]]>
+</script>
+
+

+ See this example in action (opens in new window) +

+
+

+ Top +

+
+
+

log4javascript static properties/methods

+

Properties

+
    +
  • +
    version
    +
    + The version number of your copy of log4javascript. +
    +
  • +
  • +
    edition
    +
    + The edition of your copy of log4javascript. +
    +
  • +
  • +
    logLog
    +
    + log4javascript's internal logging object. See below for more details. +
    +
  • +
+

Methods

+
    +
  • +
    getLogger
    +
    Logger getLogger([String loggerName])
    +
    Parameters:
    +
      +
    • + loggerName + [optional] +
    • +
    +
    +

    + Returns a logger with the specified name, creating it if a logger with that name does not + already exist. If no name is specified, a logger is returned with name [anonymous], and + subsequent calls to getLogger() (with no logger name specified) will return + this same logger object. +

    +

    + Note that the names [anonymous], [default], [null] + and root are reserved for + the anonymous logger, default logger, null logger and root logger respectively. +

    +
    +
  • +
  • +
    getDefaultLogger
    +
    Logger getDefaultLogger()
    +
    + Convenience method that returns the default logger. The default logger + has a single appender: a PopUpAppender + with the default layout, width and height, and with focusPopUp set to false + and lazyInit, useOldPopUp and + complainAboutPopUpBlocking all set to true. +
    +
  • +
  • +
    getNullLogger
    +
    Logger getNullLogger()
    +
    + Returns an empty logger with no appenders. Useful for disabling all logging. +
    +
  • +
  • +
    getRootLogger
    +
    Logger getRootLogger()
    +
    + Returns the root logger from which all other loggers derive. +
    +
  • +
  • +
    resetConfiguration
    +
    void resetConfiguration()
    +
    + Resets the all loggers to their default level. +
    +
  • +
  • +
    setEnabled
    +
    void setEnabled(Boolean enabled)
    +
    Parameters:
    +
      +
    • + enabled +
    • +
    +
    + Enables or disables all logging, depending on enabled. +
    +
  • +
  • +
    isEnabled
    +
    Boolean isEnabled()
    +
    + Returns true or false depending on whether logging is enabled. +
    +
  • +
  • +
    addEventListener
    +
    void addEventListener(String eventType, Function listener)
    +
    Parameters:
    +
      +
    • + eventType +
    • +
    • + listener +
    • +
    +
    +

    + Adds a function to be called when an event of the type specified occurs in log4javascript. + Supported event types are load (occurs once the page has loaded) and + error. +

    +

    + Each listener is pased three paramaters: +

    +
      +
    • sender. The object that raised the event (i.e. the log4javascript object);
    • +
    • eventType. The type of the event;
    • +
    • + eventArgs. An object containing of event-specific arguments. For the error event, + this is an object with properties message and exception. For the load + event this is an empty object. +
    • +
    +
    +
  • +
  • +
    removeEventListener
    +
    void removeEventListener(String eventType, Function listener)
    +
    Parameters:
    +
      +
    • + eventType +
    • +
    • + listener +
    • +
    +
    + Removes the event listener function supplied for the event of the type specified. +
    +
  • +
  • +
    dispatchEvent
    +
    void dispatchEvent(String eventType, Object eventArgs)
    +
    Parameters:
    +
      +
    • + eventType +
    • +
    • + eventArgs +
    • +
    +
    + Raises an event of type eventType on the log4javascript object. + Each of the listeners for this type of event (registered via addEventListener) + is called and passed eventArgs as the third parameter. +
    +
  • +
  • +
    setEventTypes
    +
    void setEventTypes(Array eventTypes)
    +
    Parameters:
    +
      +
    • + eventTypes +
    • +
    +
    + Used internally to specify the types of events that the log4javascript object can raise. +
    +
  • +
  • +
    setShowStackTraces
    +
    void setShowStackTraces(Boolean show)
    +
    Parameters:
    +
      +
    • + show +
    • +
    +
    + Enables or disables displaying of error stack traces, depending on show. + By default, stack traces are not displayed. (Only works in Firefox) +
    +
  • +
  • +
    evalInScope
    +
    Object evalInScope(String expr)
    +
    Parameters:
    +
      +
    • + expr +
    • +
    +
    + This evaluates the given expression in the log4javascript scope, thus allowing + scripts to access internal log4javascript variables and functions. This was written + for the purposes of automated testing but could be used by custom extensions to + log4javascript. +
    +
  • +
+

+ Top +

+
+
+

Levels

+

+ Levels are available as static properties of the log4javascript.Level + object. In ascending order of severity: +

+
    +
  1. log4javascript.Level.ALL
  2. +
  3. log4javascript.Level.TRACE
  4. +
  5. log4javascript.Level.DEBUG
  6. +
  7. log4javascript.Level.INFO
  8. +
  9. log4javascript.Level.WARN
  10. +
  11. log4javascript.Level.ERROR
  12. +
  13. log4javascript.Level.FATAL
  14. +
  15. log4javascript.Level.OFF
  16. +
+

+ Top +

+
+
+

Loggers

+

+ It is possible to have multiple loggers in log4javascript. For example, you + may wish to have a logger for debugging purposes that logs messages to a + pop-up window and a separate logger that reports any client-side application + errors to the server via Ajax. +

+
+

Logger hierarchy and appender additivity

+

+ From version 1.4, log4javascript has hierarchical loggers, implemented in the same way + as log4j. In summary, you specify a logger's parent logger by means of a dot between the + parent logger name and the child logger name. Therefore the logger tim.app.security + inherits from tim.app, which in turn inherits from tim which, + finally, inherits from the root logger. +

+

+ What inheritance means for a logger is that in the absence of a threshold level set + specifically on the logger it inherits its level from its parent; also, a logger inherits + all its parent's appenders (this is known as appender additivity in log4j. This + behaviour can be enabled or disabled via setAdditivity(). See below). In the + above example, if the root logger has a level of DEBUG and one appender, + each of the loggers tim.app.security, tim.app and tim would + inherit the root level's appender. If, say, tim.app's threshold level was set + to WARN, tim's effective level would remain at DEBUG + (inherited from the root logger) while tim.app.security's effective level would + be WARN, inherited from tim.app. The important thing to note is + that appenders accumulate down the logger hierarchy while levels are simply inherited from + the nearest ancestor with a threshold level set. +

+

+ For a detailed explanation of the logger hierarchy, see the + log4j manual. +

+
+

Notes

+
    +
  • + It is not possible to instantiate loggers directly. Instead you must use + one of the methods of the log4javascript object: getLogger, + getRootLogger, getDefaultLogger or getNullLogger. +
  • +
+

Logger methods

+
    +
  • +
    addAppender
    +
    void addAppender(Appender appender)
    +
    Parameters:
    +
      +
    • + appender +
    • +
    +
    + Adds the given appender. +
    +
  • +
  • +
    removeAppender
    +
    void removeAppender(Appender appender)
    +
    Parameters:
    +
      +
    • + appender +
    • +
    +
    + Removes the given appender. +
    +
  • +
  • +
    removeAllAppenders
    +
    void removeAllAppenders()
    +
    + Clears all appenders for the current logger. +
    +
  • +
  • +
    setLevel
    +
    void setLevel(Level level)
    +
    Parameters:
    +
      +
    • + level +
    • +
    +
    + Sets the level. Log messages of a lower level than level will not be logged. + Default value is DEBUG. +
    +
  • +
  • +
    getLevel
    +
    Level getLevel()
    +
    + Returns the level explicitly set for this logger or null if none has been set. +
    +
  • +
  • +
    getEffectiveLevel
    +
    Level getEffectiveLevel()
    +
    + Returns the level at which the logger is operating. This is either the level explicitly + set on the logger or, if no level has been set, the effective level of the logger's parent. +
    +
  • +
  • +
    setAdditivity
    +
    void setAdditivity(Boolean additivity)
    +
    Parameters:
    +
      +
    • + additivity +
    • +
    +
    +

    + Sets whether appender additivity is enabled (the default) or disabled. If set to false, this + particular logger will not inherit any appenders form its ancestors. Any descendant of this + logger, however, will inherit from its ancestors as normal, unless its own additivity is + explicitly set to false. +

    +

    + Default value is true. +

    +
    +
  • +
  • +
    getAdditivity
    +
    Level getLevel()
    +
    + Returns whether additivity is enabled for this logger. +
    +
  • +
  • +
    log
    +
    void log(Level level, Object params)
    +
    Parameters:
    +
      +
    • + level +
    • +
    • + params +
    • +
    +
    + Generic logging method used by wrapper methods such as debug, + error etc. +
    +

    Notes

    +
      +
    • + The signature of this method has changed in 1.4. +
    • +
    +
  • +
  • +
    trace
    +
    void trace(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level TRACE. +
    +

    Notes

    +
      +
    • + Logging of multiple messages in one call is new in 1.4. +
    • +
    +
  • +
  • +
    debug
    +
    void debug(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level DEBUG. +
    +

    Notes

    +
      +
    • + Logging of multiple messages in one call is new in 1.4. +
    • +
    +
  • +
  • +
    info
    +
    void info(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level INFO. +
    +

    Notes

    +
      +
    • + Logging of multiple messages in one call is new in 1.4. +
    • +
    +
  • +
  • +
    warn
    +
    void warn(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level WARN. +
    +

    Notes

    +
      +
    • + Logging of multiple messages in one call is new in 1.4. +
    • +
    +
  • +
  • +
    error
    +
    void error(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level ERROR. +
    +

    Notes

    +
      +
    • + Logging of multiple messages in one call is new in 1.4. +
    • +
    +
  • +
  • +
    fatal
    +
    void fatal(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level FATAL. +
    +

    Notes

    +
      +
    • + Logging of multiple messages in one call is new in 1.4. +
    • +
    +
  • +
  • +
    isEnabledFor
    +
    Boolean isEnabledFor(Level level, Error exception)
    +
    Parameters:
    +
      +
    • + level +
    • +
    +
    + Returns whether the logger is enabled for the specified level. +
    +
  • +
  • +
    isTraceEnabled
    +
    Boolean isTraceEnabled()
    +
    + Returns whether the logger is enabled for TRACE messages. +
    +
  • +
  • +
    isDebugEnabled
    +
    Boolean isDebugEnabled()
    +
    + Returns whether the logger is enabled for DEBUG messages. +
    +
  • +
  • +
    isInfoEnabled
    +
    Boolean isInfoEnabled()
    +
    + Returns whether the logger is enabled for INFO messages. +
    +
  • +
  • +
    isWarnEnabled
    +
    Boolean isWarnEnabled()
    +
    + Returns whether the logger is enabled for WARN messages. +
    +
  • +
  • +
    isErrorEnabled
    +
    Boolean isErrorEnabled()
    +
    + Returns whether the logger is enabled for ERROR messages. +
    +
  • +
  • +
    isFatalEnabled
    +
    Boolean isFatalEnabled()
    +
    + Returns whether the logger is enabled for FATAL messages. +
    +
  • +
  • +
    group
    +
    void group(String name, Boolean initiallyExpanded)
    +
    Parameters:
    +
      +
    • + name +
    • +
    • + initiallyExpanded + [optional] +
    • +
    +
    + Starts a new group of log messages. In appenders that support grouping (currently + PopUpAppender and + InPageAppender), a group appears as an expandable + section in the console, labelled with the name specified. + Specifying initiallyExpanded determines whether the + group starts off expanded (the default is true). Groups may be nested. +
    +
  • +
  • +
    groupEnd
    +
    void groupEnd()
    +
    + Ends the current group. If there is no group then this function has no effect. +
    +
  • +
  • +
    time
    +
    void time(String name, Level level)
    +
    Parameters:
    +
      +
    • + name +
    • +
    • + level + [optional] +
    • +
    +
    + Starts a timer with name name. When the timer is ended with a + call to timeEnd using the same name, the amount of time that + has elapsed in milliseconds since the timer was started is logged at level + level. If not level is supplied, the level defaults to INFO. +
    +
  • +
  • +
    timeEnd
    +
    void timeEnd(String name)
    +
    Parameters:
    +
      +
    • + name +
    • +
    +
    + Ends the timer with name name and logs the time elapsed. +
    +
  • +
  • +
    assert
    +
    void assert(Object expr)
    +
    Parameters:
    +
      +
    • + expr +
    • +
    +
    + Asserts the given expression is true or evaluates to true. + If so, nothing is logged. If not, an error is logged at the ERROR level. +
    +
  • +
+

+ Top +

+
+
+

Appenders

+
+

Appender

+

+ There are methods common to all appenders, as listed below. +

+

Methods

+
    +
  • +
    doAppend
    +
    void doAppend(LoggingEvent loggingEvent)
    +
    Parameters:
    +
      +
    • + loggingEvent +
    • +
    +
    +

    + Checks the logging event's level is at least as severe as the appender's + threshold and calls the appender's append method if so. +

    +

    + This method should not in general be used directly or overridden. +

    +
    +
  • +
  • +
    append
    +
    void append(LoggingEvent loggingEvent)
    +
    Parameters:
    +
      +
    • + loggingEvent +
    • +
    +
    + Appender-specific method to append a log message. Every appender object should implement + this method. +
    +
  • +
  • +
    setLayout
    +
    void setLayout(Layout layout)
    +
    Parameters:
    +
      +
    • + layout +
    • +
    +
    + Sets the appender's layout. +
    +
  • +
  • +
    getLayout
    +
    Layout getLayout()
    +
    + Returns the appender's layout. +
    +
  • +
  • +
    setThreshold
    +
    void setThreshold(Level level)
    +
    Parameters:
    +
      +
    • + level +
    • +
    +
    + Sets the appender's threshold. Log messages of level less severe than this + threshold will not be logged. +
    +
  • +
  • +
    getThreshold
    +
    Level getThreshold()
    +
    + Returns the appender's threshold. +
    +
  • +
  • +
    toString
    +
    string toString()
    +
    + Returns a string representation of the appender. Every appender object should implement + this method. +
    +
  • +
+

+ Top +

+
+
+

AlertAppender

+

Editions: Standard

+

+ Displays a log message as a JavaScript alert. +

+

Constructor

+
    +
  • +
    AlertAppender
    +
    AlertAppender()
    +
  • +
+

+ Top +

+
+
+

AjaxAppender

+

Editions: Standard, Production

+

+ A flexible appender that asynchronously sends log messages to a server via HTTP + (Ajax, if you insist, though the 'x' of Ajax only comes into play in any form if you use an + XmlLayout). +

+

+ The default configuration is to send each log message as a separate HTTP post + request to the server using an HttpPostDataLayout, + without waiting for a response before sending any subsequent requests. However, + an AjaxAppender may be configured to do any one of or combinations of the following: +

+
    +
  • + send log messages in batches (if the selected layout supports it - particularly suited + to AjaxAppender are JsonLayout and + XmlLayout, both of which allow batching); +
  • +
  • + wait for a response from a previous request before sending the next log message / batch + of messages; +
  • +
  • + send all queued log messages at timed intervals. +
  • +
+

Notes

+
    +
  • + AjaxAppender relies on the XMLHttpRequest object. It also requires + the presence of correctly implemented setRequestHeader method on + this object, which rules out Opera prior to version 8.01. If your browser does not + support the necessary objects then one alert will display to explain why it + doesn't work, after which the appender will silently switch off. +
  • +
  • + In AjaxAppender only, setLayout may not be called after the first + message has been logged. +
  • +
  • + The default layout is HttpPostDataLayout. +
  • +
  • + From version 1.4, log message data is always sent as one or more name/value pairs. + In the case of HttpPostDataLayout, data + is sent the same as in previous versions. For other layouts such as + JsonLayout and + XmlLayout, the formatted log message is posted as + the value of a parameter called data, though this may be changed via + setPostVarName. +
  • +
  • + From version 1.4, log message timestamps are sent as standard JavaScript times, i.e. + the number of milliseconds since 00:00:00 UTC on January 1, 1970. +
  • +
  • +

    + Also from version 1.4, any outstanding log messages may optionally be sent when the + main page unloads (i.e. user follows a link, closes the window or refreshes the + page). This behaviour may be enabled using setSendAllOnUnload; see + below. +

    +

    + This behaviour is dependent on window.onbeforeunload; unfortunately, + Opera does not always raise this event, so this feature does not work reliably in + Opera. +

    +
  • +
+

Constructor

+
    +
  • +
    AjaxAppender
    +
    + AjaxAppender(String url) +
    +
    Parameters:
    +
      +
    • + url +
      + The URL to which log messages should be sent. Note that this is subject + to the usual Ajax restrictions: the URL should be in the same domain as that + of the page making the request. +
      +
    • +
    +
  • +
+

Methods

+
    +
  • +
    setSendAllOnUnload
    +
    void setSendAllOnUnload(Boolean sendAllOnUnload)
    +
    +

    + [not available after first message logged] +

    +

    + Whether to send all remaining unsent log messages to the server when the page + unloads. +

    +

    + Since version 1.4.3, the default value is false. Previously the + default was true. +

    +

    Notes

    +
      +
    • + This feature was found not to work prior to version 1.4.3 in WebKit + browsers (e.g. Google Chrome, Safari). As a result, a workaround was + implemented in 1.4.3 which has the unfortunate side effect of popping up a + confirmation dialog to the user if there are any log messages to send when + the page unloads. As a result, this feature is now obtrusive for the user + and is therefore disabled by default. +
    • +
    • + This feature does not work in any version of Opera. +
    • +
    +
    +
  • +
  • +
    isSendAllOnUnload
    +
    Boolean isSendAllOnUnload()
    +
    + Returns whether all remaining unsent log messages are sent to the server when the page unloads. +
    +
  • +
  • +
    setPostVarName
    +
    void setPostVarName(String postVarName)
    +
    +

    + [not available after first message logged] +

    +

    + Sets the post variable name whose value will the formatted log message(s) for + each request. +

    +

    + Default value is data. +

    +

    Notes

    + +
    +
  • +
  • +
    getPostVarName
    +
    String getPostVarName()
    +
    + Returns the post variable name whose value will the formatted log message(s) for + each request. +
    +
  • +
  • +
    setTimed
    +
    void setTimed(Boolean timed)
    +
    +

    + [not available after first message logged] +

    +

    + Whether to send log messages to the server at regular, timed intervals. +

    +

    + Default value is false. +

    +
    +
  • +
  • +
    isTimed
    +
    Boolean isTimed()
    +
    + Returns whether log messages are sent to the server at regular, timed intervals. +
    +
  • +
  • +
    setWaitForResponse
    +
    void setWaitForResponse(Boolean waitForResponse)
    +
    +

    + [not available after first message logged] +

    +

    + Sets whether to wait for a response from a previous HTTP request from this + appender before sending the next log message / batch of messages. +

    +

    + Default value is false. +

    +
    +
  • +
  • +
    isWaitForResponse
    +
    Boolean isWaitForResponse()
    +
    + Returns whether the appender waits for a response from a previous HTTP request from this + appender before sending the next log message / batch of messages. +
    +
  • +
  • +
    setBatchSize
    +
    void setBatchSize(Number batchSize)
    +
    +

    + [not available after first message logged] +

    +

    + Sets the number of log messages to send in each request. If not specified, + defaults to 1. +

    +

    Notes

    +
      +
    • + Setting this to a number greater than 1 means that the appender will wait + until it has forwarded that many valid log messages before sending any more. + This also means that if the page unloads for any reason and sendAllOnUnload + is not set to true, any log messages waiting in the queue will not be sent. +
    • +
    • + If batching is used in conjunction with timed sending of log messages, + messages will still be sent in batches of size batchSize, + regardless of how many log messages are queued by the time the timed + sending is invoked. Incomplete batches will not be sent except when the + page unloads, if sendAllOnUnload is set to true. +
    • +
    +
    +
  • +
  • +
    getBatchSize
    +
    Number getBatchSize()
    +
    + Returns the number of log messages sent in each request. See above for more details. +
    +
  • +
  • +
    setTimerInterval
    +
    void setTimerInterval(Number timerInterval)
    +
    +

    + [not available after first message logged] +

    +

    + Sets the length of time in milliseconds between each sending of queued log + messages. +

    +

    Notes

    +
      +
    • + timerInterval only has an effect in conjunction with + timed (set by setTimed(). If timed + is set to false then timerInterval has no effect. +
    • +
    • + Each time the queue of log messages or batches of messages is cleared, + the countdown to the next sending only starts once the final request + has been sent (and, if waitForResponse is set to true, + the final response received). This means that the actual interval at + which the queue of messages is cleared cannot be fixed. +
    • +
    +
    +
  • +
  • +
    getTimerInterval
    +
    Number getTimerInterval()
    +
    + Returns the length of time in milliseconds between each sending of queued log + messages. See above for more details. +
    +
  • +
  • +
    setRequestSuccessCallback
    +
    void setRequestSuccessCallback(Function requestSuccessCallback)
    +
    +

    + Sets the function that is called whenever a successful request is made, called at the + point at which the response is received. This feature can be used to confirm + whether a request has been successful and act accordingly. +

    +

    + A single parameter, xmlHttp, is passed to the callback function. + This is the XMLHttpRequest object that performed the request. +

    +
    +
  • +
  • +
    setFailCallback
    +
    void setFailCallback(Function failCallback)
    +
    +

    + Sets the function that is called whenever any kind of failure occurs in the appender, + including browser deficiencies or configuration errors (e.g. supplying a + non-existent URL to the appender). This feature can be used to handle + AjaxAppender-specific errors. +

    +

    + A single parameter, message, is passed to the callback function. + This is the error-specific message that caused the failure. +

    +
    +
  • +
  • +
    setSessionId
    +
    void setSessionId(String sessionId)
    +
    + Sets the session id sent to the server each time a request is made. +
    +
  • +
  • +
    getSessionId
    +
    String getSessionId()
    +
    + Returns the session id sent to the server each time a request is made. +
    +
  • +
  • +
    addHeader
    +
    void addHeader(String name, + String value)
    +
    +

    + Adds an HTTP header that is sent with each request. +

    +

    + Since: 1.4.3 +

    +
    +
  • +
  • +
    getHeaders
    +
    Array getHeaders()
    +
    + Returns an array of the additional headers that are sent with each HTTP request. + Each array item is an object with properties name and + value. +

    + Since: 1.4.3 +

    +
    +
  • +
  • +
    sendAll
    +
    void sendAll()
    +
    + Sends all log messages in the queue. If log messages are batched then only completed + batches are sent. +
    +
  • +
+

+ Top +

+
+
+

PopUpAppender

+

Editions: Standard

+

+ Logs messages to a pop-up console window (note: you will need to disable pop-up + blockers to use it). The pop-up displays a list of all log messages, and has + the following features: +

+
    +
  • log messages are colour-coded by severity;
  • +
  • log messages are displayed in a monospace font to allow easy readability;
  • +
  • switchable wrap mode to allow wrapping of long lines
  • +
  • all whitespace in log messages is honoured (except in wrap mode);
  • +
  • filters to show and hide messages of a particular level;
  • +
  • + search facility that allows searching of log messages as you type, with the + following features: +
      +
    • supports regular expressions;
    • +
    • case sensitive or insensitive matching;
    • +
    • buttons to navigate through all the matches;
    • +
    • switch to highlight all matches;
    • +
    • switch to filter out all log messages that contain no matches;
    • +
    • switch to enable or disable the search;
    • +
    • search is dynamically applied to every log message as it is added to the console.
    • +
    +
  • +
  • switch to toggle between logging from the top down and from the bottom up;
  • +
  • switch to turn automatic scrolling when a new message is logged on and off;
  • +
  • switch to turn off all logging to the pop-up (useful if a timer is generating unwanted log messages);
  • +
  • optional configurable limit to the number of log message that are displayed. If + set and this limit is reached, each new log message will cause the oldest one to + be discarded;
  • +
  • grouped log messages. Groups may be nested and each has a button to show or hide the log messages in that group;
  • +
  • clear button to allow user to delete all current log messages.
  • +
  • + command prompt with up/down arrow history. Command line functions may be added + to the appender. Several command line functions are built in: +
      +
    • +
      $(String id)
      +
      + Prints a string representation of a single element with the id supplied. +
      +
    • +
    • +
      dir(Object obj)
      +
      + Prints a list of a properties of the object supplied. +
      +
    • +
    • +
      dirxml(HTMLElement el)
      +
      + Prints the XML source code of an HTML or XML element +
      +
    • +
    • +
      cd(Object win)
      +
      + Changes the scope of execution of commands to the named frame or window (either a + window/frame name or a reference to a window object may be supplied). +
      +
    • +
    • +
      clear()
      +
      + Clears the console. +
      +
    • +
    • +
      keys(Object obj)
      +
      + Prints a list of the names of all properties of the object supplied. +
      +
    • +
    • +
      values(Object obj)
      +
      + Prints a list of the values of all properties of the object supplied. +
      +
    • +
    • +
      expansionDepth(Number depth)
      +
      + Sets the number of levels of expansion of objects that are displayed by + the command line. The default value is 1. +
      +
    • +
    +
  • +
+

Notes

+
    +
  • +

    + The default layout for this appender is PatternLayout + with pattern string +

    +

    + %d{HH:mm:ss} %-5p - %m{1}%n +

    +
  • +
+

Constructor

+
    +
  • +
    PopUpAppender
    +
    + PopUpAppender([Boolean lazyInit, + Boolean initiallyMinimized, Boolean useDocumentWrite, + Number width, Number height]) +
    +
    Parameters:
    +
      +
    • + lazyInit + [optional] +
      + Set this to true to open the pop-up only when the first log + message reaches the appender. Otherwise, the pop-up window opens as soon as the + appender is created. If not specified, defaults to false. +
      +
    • +
    • + initiallyMinimized + [optional] +
      +

      + Whether the console window should start off hidden / minimized. + If not specified, defaults to false. +

      +
      +
    • +
    • + useDocumentWrite + [optional] +
      +

      + Specifies how the console window is created. By default, the console window is + created dynamically using document's write method. This has the + advantage of keeping all the code in one single JavaScript file. However, if your + page sets document.domain then the browser prevents script access to + a window unless it too has the same value set for document.domain. To + get round this issue, you can set useDocumentWrite to false + and log4javascript will instead use the external HTML file console.html + (or console_uncompressed.html if you're using an uncompressed version of + log4javascript.js), which must be placed in the same directory as your log4javascript.js file. +

      +

      + Note that if useDocumentWrite is set to true, the old pop-up + window will always be closed and a new one created whenever the page is refreshed, even + if setUseOldPopUp(true) has been called. +

      +

      + In general it's simpler to use the document.write method, so unless your + page needs to set document.domain, useDocumentWrite should + be set to true. +

      +

      + If not specified, defaults to true. +

      +
      +
    • +
    • + width + [optional] +
      + The outer width in pixels of the pop-up window. If not specified, + defaults to 600. +
      +
    • +
    • + height + [optional] +
      + The outer height in pixels of the pop-up window. If not specified, + defaults to 400. +
      +
    • +
    +
  • +
+

Methods

+
    +
  • +
    isInitiallyMinimized
    +
    Boolean isInitiallyMinimized()
    +
    + Returns whether the console window starts off hidden / minimized. +
    +
  • +
  • +
    setInitiallyMinimized
    +
    void setInitiallyMinimized(Boolean initiallyMinimized)
    +
    + [not available after initialization] +
    + Sets whether the console window should start off hidden / minimized. +
    +
  • +
  • +
    isFocusPopUp
    +
    Boolean isFocusPopUp()
    +
    + Returns whether the pop-up window is focussed (i.e. brought it to the front) + when a new log message is added. Default value is false. +
    +
  • +
  • +
    setFocusPopUp
    +
    void setFocusPopUp(Boolean focusPopUp)
    +
    + Sets whether to focus the pop-up window (i.e. bring it to the front) + when a new log message is added. +
    +
  • +
  • +
    isUseOldPopUp
    +
    Boolean isUseOldPopUp()
    +
    +

    + Returns whether the same pop-up window is used if the main page is + reloaded. If set to true, when the page is reloaded + a line is drawn in the pop-up and subsequent log messages are added + to the same pop-up. Otherwise, a new pop-up window is created that + replaces the original pop-up. If not specified, defaults to + true. +

    +

    Notes

    +
      +
    • + In Internet Explorer 5, the browser prevents this from working + properly, so a new pop-up window is always created when the main + page reloads. Also, the original pop-up does not get closed. +
    • +
    +
    +
  • +
  • +
    setUseOldPopUp
    +
    void setUseOldPopUp(Boolean useOldPopUp)
    +
    + [not available after initialization] +
    + Sets whether to use the same pop-up window if the main page is reloaded. + See isUseOldPopUp above for details. +
    +
  • +
  • +
    isComplainAboutPopUpBlocking
    +
    Boolean isComplainAboutPopUpBlocking()
    +
    + Returns whether an alert is shown to the user when the pop-up window + cannot be created as a result of a pop-up blocker. Default value is true. +
    +
  • +
  • +
    setComplainAboutPopUpBlocking
    +
    void setComplainAboutPopUpBlocking(Boolean complainAboutPopUpBlocking)
    +
    + [not available after initialization] +
    + Sets whether to announce to show an alert to the user when the pop-up window + cannot be created as a result of a pop-up blocker. +
    +
  • +
  • +
    isNewestMessageAtTop
    +
    Boolean isNewestMessageAtTop()
    +
    + Returns whether new log messages are displayed at the top of the pop-up window. + Default value is false (i.e. log messages are appended to the bottom of the window). +
    +
  • +
  • +
    setNewestMessageAtTop
    +
    void setNewestMessageAtTop(Boolean newestMessageAtTop)
    +
    + Sets whether to display new log messages at the top inside the pop-up window. +
    +
  • +
  • +
    isScrollToLatestMessage
    +
    Boolean isScrollToLatestMessage()
    +
    + Returns whether the pop-up window scrolls to display the latest log message when a new message + is logged. Default value is true. +
    +
  • +
  • +
    setScrollToLatestMessage
    +
    void setScrollToLatestMessage(Boolean scrollToLatestMessage)
    +
    + Sets whether to scroll the pop-up window to display the latest log message when a new message + is logged. +
    +
  • +
  • +
    isReopenWhenClosed
    +
    Boolean isReopenWhenClosed()
    +
    + Returns whether the pop-up window reopens automatically after being closed when a new log message is logged. + Default value is false. +
    +
  • +
  • +
    setReopenWhenClosed
    +
    void setReopenWhenClosed(Boolean reopenWhenClosed)
    +
    + Sets whether to reopen the pop-up window automatically after being closed when a new log message is logged. +
    +
  • +
  • +
    getWidth
    +
    Number getWidth()
    +
    + Returns the outer width in pixels of the pop-up window. +
    +
  • +
  • +
    setWidth
    +
    void setWidth(Number width)
    +
    + [not available after initialization] +
    + Sets the outer width in pixels of the pop-up window. +
    +
  • +
  • +
    getHeight
    +
    Number getHeight()
    +
    + [not available after initialization] +
    + Returns the outer height in pixels of the pop-up window. +
    +
  • +
  • +
    setHeight
    +
    void setHeight(Number height)
    +
    + Sets the outer height in pixels of the pop-up window. +
    +
  • +
  • +
    getMaxMessages
    +
    Number getMaxMessages()
    +
    + Returns the largest number of log messages that are displayed and stored + by the the console. Once reached, a new log message wil cause the + oldest message to be discarded. Default value is null, which means no + limit is applied. +
    +
  • +
  • +
    setMaxMessages
    +
    void setMaxMessages(Number maxMessages)
    +
    + [not available after initialization] +
    + Sets the largest number of messages displayed and stored by the console window. Set + this to null to make this number unlimited. +
    +
  • +
  • +
    isShowCommandLine
    +
    Boolean isShowCommandLine()
    +
    + Returns whether the console includes a command line. + Default value is true. +
    +
  • +
  • +
    setShowCommandLine
    +
    void setShowCommandLine(Boolean showCommandLine)
    +
    + Sets whether the console includes a command line. +
    +
  • +
  • +
    getCommandLineObjectExpansionDepth
    +
    Number getCommandLineObjectExpansionDepth()
    +
    + Returns the number of levels to expand when an object value is logged to the console. + Each property of an object above this threshold will be expanded if it is itself an object + or array, otherwise its string representation will be displayed. Default value is 1 (i.e. + the properties of the object logged will be displayed in their string representation but + not expanded). +
    +
  • +
  • +
    setCommandLineObjectExpansionDepth:
    +
    void setCommandLineObjectExpansionDepth(Number expansionDepth)
    +
    + Sets the number of levels to expand when an object value is logged to the console. +
    +
  • +
  • +
    getCommandWindow
    +
    Window getCommandWindow()
    +
    + Returns a reference to the window in which commands typed into the command line + are currently being executed. +
    +
  • +
  • +
    setCommandWindow
    +
    void setCommandWindow(Window commandWindow)
    +
    + Sets the window in which commands typed into the command line are executed. +
    +
  • +
  • +
    getCommandLayout
    +
    Number getCommandLayout()
    +
    + Returns the layout used to format the output for commands typed into the command line. + The default value is a PatternLayout with + pattern string %m +
    +
  • +
  • +
    setCommandLayout
    +
    void setCommandLayout(Layout commandLayout)
    +
    + Sets the layout used to format the output for commands typed into the command line. +
    +
  • +
  • +
    clear
    +
    void clear()
    +
    + Clears all messages from the console window. +
    +
  • +
  • +
    close
    +
    void close()
    +
    + Closes the pop-up window. +
    +
  • +
  • +
    show
    +
    void show()
    +
    + Opens the pop-up window, if not already open. +
    +
  • +
  • +
    hide
    +
    void hide()
    +
    + Closes the pop-up window. +
    +
  • +
  • +
    focus
    +
    void focus()
    +
    + Brings the console window to the top and gives it the focus. +
    +
  • +
  • +
    focusCommandLine
    +
    void focusCommandLine()
    +
    + Brings the console window to the top and gives the focus to the command line. +
    +
  • +
  • +
    focusSearch
    +
    void focusSearch()
    +
    + Brings the console window to the top and gives the focus to the search box. +
    +
  • +
  • +
    evalCommandAndAppend
    +
    void evalCommandAndAppend(String expr)
    +
    + Evaluates the expression and appends the result to the console. +
    +
  • +
  • +
    addCommandLineFunction
    +
    void addCommandLineFunction(String functionName, Function commandLineFunction)
    +
    +

    + Adds a function with the name specified to the list of functions available on the command line. + This feature may be used to add custom functions to the command line. +

    +

    + When you call the function on the command line, commandLineFunction is executed with the + following three parameters: +

    +
      +
    • appender. A reference to the appender in which the command was executed;
    • +
    • args. + An array-like list of parameters passed into the function on the command line + (actually a reference to the arguments object representing the parameters passed + into the function by the user);
    • +
    • returnValue. This is an object with two properties that allow the function to control + how the result is displayed: +
        +
      • appendResult. A boolean value that determines whether the returned value from this + function is appended to the console. The default value is true;
      • +
      • isError. A boolean value that specifies whether the output of this function + should be displayed as an error. The default value is false.
      • +
      +
    • +
    +

    + The value returned by the function is formatted by the command layout and appended to the console. +

    +
    +
  • +
+

+ Top +

+
+
+

InPageAppender

+

Editions: Standard

+

+ Logs messages to a console window in the page. The console is identical + to that used by the PopUpAppender, except + for the absence of a 'Close' button. +

+

Notes

+
    +
  • + Prior to log4javascript 1.3, InPageAppender was known as InlineAppender. + For the sake of backwards compatibility, InlineAppender is still included in + 1.3 and later as an alias for InPageAppender. +
  • +
  • +

    + The default layout for this appender is PatternLayout + with pattern string +

    +

    + %d{HH:mm:ss} %-5p - %m{1}%n +

    +
  • +
+

Constructor

+
    +
  • +
    InPageAppender
    +
    + InPageAppender(HTMLElement container[, + Boolean lazyInit, Boolean initiallyMinimized, + Boolean useDocumentWrite, String width, String height]) +
    +
    Parameters:
    +
      +
    • + container +
      + The container element for the console window. This should be an HTML element. +
      +
    • +
    • + lazyInit + [optional] +
      + Set this to true to create the console only when the first log + message reaches the appender. Otherwise, the console is initialized as soon as the + appender is created. If not specified, defaults to true. +
      +
    • +
    • + initiallyMinimized + [optional] +
      +

      + Whether the console window should start off hidden / minimized. + If not specified, defaults to false. +

      +

      Notes

      +
        +
      • + In Safari (and possibly other browsers) hiding an iframe + resets its document, thus destroying the console window. +
      • +
      +
      +
    • +
    • + useDocumentWrite + [optional] +
      +

      + Specifies how the console window is created. By default, the console window is + created dynamically using document's write method. This has the + advantage of keeping all the code in one single JavaScript file. However, if your + page sets document.domain then the browser prevents script access to + a window unless it too has the same value set for document.domain. To + get round this issue, you can set useDocumentWrite to false + and log4javascript will instead use the external HTML file console.html + (or console_uncompressed.html if you're using an uncompressed version of + log4javascript.js), which must be placed in the same directory as your log4javascript.js file. +

      +

      + In general it's simpler to use the document.write method, so unless your + page needs to set document.domain, useDocumentWrite should + be set to true. +

      +

      + If not specified, defaults to true. +

      +
      +
    • +
    • + width + [optional] +
      + The width of the console window. Any valid CSS length may be used. If not + specified, defaults to 100%. +
      +
    • +
    • + height + [optional] +
      + The height of the console window. Any valid CSS length may be used. If not + specified, defaults to 250px. +
      +
    • +
    +
  • +
+

Methods

+
    +
  • +
    addCssProperty
    +
    void addCssProperty(String name, String value)
    +
    + Sets a CSS style property on the HTML element containing the console iframe. +
    +
  • +
  • +
    isVisible
    +
    Boolean isVisible()
    +
    + Returns whether the console window is currently visible. +
    +
  • +
  • +
    isInitiallyMinimized
    +
    Boolean isInitiallyMinimized()
    +
    + Returns whether the console window starts off hidden / minimized. +
    +
  • +
  • +
    setInitiallyMinimized
    +
    void setInitiallyMinimized(Boolean initiallyMinimized)
    +
    + [not available after initialization] +
    + Sets whether the console window should start off hidden / minimized. +
    +
  • +
  • +
    isNewestMessageAtTop
    +
    Boolean isNewestMessageAtTop()
    +
    + Returns whether new log messages are displayed at the top of the console window. +
    +
  • +
  • +
    setNewestMessageAtTop
    +
    void setNewestMessageAtTop(Boolean newestMessageAtTop)
    +
    + Sets whether to display new log messages at the top inside the console window. +
    +
  • +
  • +
    isScrollToLatestMessage
    +
    Boolean isScrollToLatestMessage()
    +
    + Returns whether the pop-up window scrolls to display the latest log message when a new message + is logged. +
    +
  • +
  • +
    setScrollToLatestMessage
    +
    void setScrollToLatestMessage(Boolean scrollToLatestMessage)
    +
    + Sets whether to scroll the console window to display the latest log message when a new message + is logged. +
    +
  • +
  • +
    getWidth
    +
    String getWidth()
    +
    + Returns the outer width of the console window. +
    +
  • +
  • +
    setWidth
    +
    void setWidth(String width)
    +
    + [not available after initialization] +
    + Sets the outer width of the console window. Any valid CSS length may be used. +
    +
  • +
  • +
    getHeight
    +
    String getHeight()
    +
    + Returns the outer height of the console window. +
    +
  • +
  • +
    setHeight
    +
    void setHeight(String height)
    +
    + [not available after initialization] +
    + Sets the outer height of the console window. Any valid CSS length may be used. +
    +
  • +
  • +
    getMaxMessages
    +
    Number getMaxMessages()
    +
    + Returns the largest number of messages displayed and stored by the console window. +
    +
  • +
  • +
    setMaxMessages
    +
    void setMaxMessages(Number maxMessages)
    +
    + [not available after initialization] +
    + Sets the largest number of messages displayed and stored by the console window. Set + this to null to make this number unlimited. +
    +
  • +
  • +
    isShowCommandLine
    +
    Boolean isShowCommandLine()
    +
    + Returns whether the console includes a command line. + Default value is true. +
    +
  • +
  • +
    setShowCommandLine
    +
    void setShowCommandLine(Boolean showCommandLine)
    +
    + Sets whether the console includes a command line. +
    +
  • +
  • +
    getCommandLineObjectExpansionDepth
    +
    Number getCommandLineObjectExpansionDepth()
    +
    + Returns the number of levels to expand when an object value is logged to the console. + Each property of an object above this threshold will be expanded if it is itself an object + or array, otherwise its string representation will be displayed. Default value is 1 (i.e. + the properties of the object logged will be displayed in their string representation but + not expanded). +
    +
  • +
  • +
    setCommandLineObjectExpansionDepth:
    +
    void setCommandLineObjectExpansionDepth(Number expansionDepth)
    +
    + Sets the number of levels to expand when an object value is logged to the console. +
    +
  • +
  • +
    getCommandWindow
    +
    Window getCommandWindow()
    +
    + Returns a reference to the window in which commands typed into the command line + are currently being executed. +
    +
  • +
  • +
    setCommandWindow
    +
    void setCommandWindow(Window commandWindow)
    +
    + Sets the window in which commands typed into the command line are executed. +
    +
  • +
  • +
    getCommandLayout
    +
    Number getCommandLayout()
    +
    + Returns the layout used to format the output for commands typed into the command line. + The default value is a PatternLayout with + pattern string %m +
    +
  • +
  • +
    setCommandLayout
    +
    void setCommandLayout(Layout commandLayout)
    +
    + Sets the layout used to format the output for commands typed into the command line. +
    +
  • +
  • +
    clear
    +
    void clear()
    +
    + Clears all messages from the console window. +
    +
  • +
  • +
    show
    +
    void show()
    +
    +

    + Shows / unhides the console window. +

    +

    Notes

    +
      +
    • + In Safari (and possibly other browsers), hiding an iframe + resets its document, thus destroying the console window. +
    • +
    +
    +
  • +
  • +
    hide
    +
    void hide()
    +
    +

    + Hides / minimizes the console window. +

    +

    Notes

    +
      +
    • + In Safari (and possibly other browsers), hiding an iframe + resets its document, thus destroying the console window. +
    • +
    +
    +
  • +
  • +
    close
    +
    void close()
    +
    + Removes the console window iframe from the main document. +
    +
  • +
  • +
    focus
    +
    void focus()
    +
    + Brings the console window to the top and gives it the focus. +
    +
  • +
  • +
    focusCommandLine
    +
    void focusCommandLine()
    +
    + Brings the console window to the top and gives the focus to the command line. +
    +
  • +
  • +
    focusSearch
    +
    void focusSearch()
    +
    + Brings the console window to the top and gives the focus to the search box. +
    +
  • +
  • +
    evalCommandAndAppend
    +
    void evalCommandAndAppend(String expr)
    +
    + Evaluates the expression and appends the result to the console. +
    +
  • +
  • +
    addCommandLineFunction
    +
    void addCommandLineFunction(String functionName, Function commandLineFunction)
    +
    +

    + Adds a function with the name specified to the list of functions available on the command line. + This feature may be used to add custom functions to the command line. +

    +

    + When you call the function on the command line, commandLineFunction is executed with the + following three parameters: +

    +
      +
    • appender. A reference to the appender in which the command was executed;
    • +
    • args. + An array-like list of parameters passed into the function on the command line + (actually a reference to an arguments object);
    • +
    • returnValue. This is an object with two properties that allow the function to control + how the result is displayed: +
        +
      • appendResult. A boolean value that determines whether the returned value from this + function is appended to the console. The default value is true;
      • +
      • isError. A boolean value that specifies whether the output of this function + should be displayed as an error. The default value is false.
      • +
      +
    • +
    +

    + The value returned by the function is formatted by the command layout and appended to the console. +

    +
    +
  • +
+

+ Top +

+
+
+

BrowserConsoleAppender

+

Editions: Standardl

+

+ Writes log messages to the browser's built-in console, if present. This only works + currently in Safari, Opera and Firefox with the excellent + Firebug extension installed. +

+

Notes

+
    +
  • + As of log4javascript 1.3, the default threshold for this appender is DEBUG + as opposed to WARN as it was previously; +
  • +
  • +

    + As of version 1.3, log4javascript has explicit support for Firebug's logging. This includes + the following mapping of log4javascript's log levels onto Firebug's: +

    +
      +
    • log4javascript TRACE, DEBUG -> Firebug debug
    • +
    • log4javascript INFO -> Firebug info
    • +
    • log4javascript WARN -> Firebug warn
    • +
    • log4javascript ERROR, FATAL -> Firebug error
    • +
    +

    + ... and the ability to pass objects into Firebug and take advantage of its object inspection. + This is because the default layout is now NullLayout, + which performs no formatting on an object. +

    +
  • +
+

Constructor

+
    +
  • +
    BrowserConsoleAppender
    +
    BrowserConsoleAppender()
    +
  • +
+

+ Top +

+
+
+
+

Layouts

+
+

Layout

+

+ There are a few methods common to all layouts: +

+

Methods

+
    +
  • +
    format
    +
    String format(LoggingEvent loggingEvent)
    +
    Parameters:
    +
      +
    • + loggingEvent +
    • +
    +
    + Formats the log message. You should override this method in your own layouts. +
    +
  • +
  • +
    ignoresThrowable
    +
    Boolean ignoresThrowable()
    +
    + Returns whether the layout ignores an error object in a logging event passed + to its format method. +
    +
  • +
  • +
    getContentType
    +
    String getContentType()
    +
    + Returns the content type of the output of the layout. +
    +
  • +
  • +
    allowBatching
    +
    Boolean allowBatching()
    +
    + Returns whether the layout's output is suitable for batching. + JsonLayout and XmlLayout + are the only built-in layouts that return true for this method. +
    +
  • +
  • +
    getDataValues
    +
    Array getDataValues(LoggingEvent loggingEvent)
    +
    Parameters:
    +
      +
    • + loggingEvent +
    • +
    +
    + Used internally by log4javascript in constructing formatted output for some layouts. +
    +
  • +
  • +
    setKeys
    +
    void setKeys(String loggerKey, + String timeStampKey, String levelKey, String messageKey, + String exceptionKey, String urlKey)
    +
    Parameters:
    +
      +
    • + loggerKey +
      + Parameter to use for the log message's logger name. Default is logger. +
      +
    • +
    • + timeStampKey +
      + Parameter to use for the log message's timestamp. Default is timestamp. +
      +
    • +
    • + levelKey +
      + Parameter to use for the log message's level. Default is level. +
      +
    • +
    • + messageKey +
      + Parameter to use for the message itself. Default is message. +
      +
    • +
    • + exceptionKey +
      + Parameter to use for the log message's error (exception). Default is exception. +
      +
    • +
    • + urlKey +
      + Parameter to use for the current page URL. Default is url. +
      +
    • +
    +
    + This method is used to change the default keys used to create formatted name-value pairs + for the properties of a log message, for layouts that do this. These layouts are + JsonLayout and + HttpPostDataLayout. +
    +
  • +
  • +
    setCustomField
    +
    void setCustomField(String name, + String value)
    +
    Parameters:
    +
      +
    • + name +
      + Name of the custom property you wish to be included in the formmtted output. +
      +
    • +
    • + value +
      + Value of the custom property you wish to be included in the formatted output. +
      +
    • +
    +
    + Some layouts (JsonLayout, + HttpPostDataLayout, + PatternLayout and + XmlLayout) allow you to set + custom fields (e.g. a session id to send to the server) to the + formatted output. Use this method to set a custom field. If there + is already a custom field with the specified name, its value will + be updated with value. +
    +

    Notes

    +
      +
    • +

      + From version 1.4, the custom field value may be a function. In this + case, the function is run at the time the layout's format method is called, + with the following two parameters: +

      +
        +
      • layout. A reference to the layout being used;
      • +
      • loggingEvent. A reference to the logging event being formatted.
      • +
      +
    • +
    +
  • +
  • +
    hasCustomFields
    +
    Boolean hasCustomFields()
    +
    + Returns whether the layout has any custom fields. +
    +
  • +
+

+ Top +

+
+
+

NullLayout

+

Editions: All

+

+ The most basic layout. NullLayout's format() methods performs no + formatting at all and simply returns the message logged. +

+

Constructor

+
    +
  • +
    NullLayout
    +
    NullLayout()
    +
  • +
+

+ Top +

+
+
+

SimpleLayout

+

Editions: Standard, Production

+

+ Provides basic formatting. SimpleLayout consists of the level of the log statement, + followed by " - " and then the log message itself. For example, +

+

DEBUG - Hello world

+

Constructor

+
    +
  • +
    SimpleLayout
    +
    SimpleLayout()
    +
  • +
+

+ Top +

+
+
+

PatternLayout

+

Editions: All

+

+ Provides a flexible way of formatting a log message by means of a conversion pattern + string. The behaviour of this layout is a full implementation of PatternLayout + in log4j, with the exception of the set of conversion characters - log4javascript's is + necessarily a subset of that of log4j with a few additions of its own, since many of + the conversion characters in log4j only make sense in the context of Java. +

+

+ The conversion pattern consists of literal text interspersed with special strings starting with + a % symbol called conversion specifiers. A conversion specifier consists of the + % symbol, a conversion character (possible characters are listed below) and + format modifiers. For full documentation of the conversion pattern, see + log4j's + documentation. Below is a list of all conversion characters available in log4javascript. +

+

Conversion characters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Conversion CharacterEffect
a +

+ Outputs log messages specified as an array. +

+

+ Behaves exactly like %m, except that multiple log messages are + assumed to have been specified in the logging call as an array rather than + as multiple parameters. +

+

+ Since: 1.4 +

+
c +

+ Outputs the logger name. +

+
d +

+ Outputs the date of the logging event. The date conversion specifier + may be followed by a date format specifier enclosed between braces. For + example, %d{HH:mm:ss,SSS} or + %d{dd MMM yyyy HH:mm:ss,SSS}. If no date + format specifier is given then ISO8601 format is assumed. +

+

+ The date format specifier is the same as that used by Java's + SimpleDateFormat. log4javascript + includes a full implementation of SimpleDateFormat's + format method, with the exception of the pattern letter + 'z', (string representation of the timezone) for which the information + is not available in JavaScript. +

+
f +

+ Outputs the value of a custom field set on the layout. If present, the specifier gives + the index in the array of custom fields to use; otherwise, the first custom field in the + array is used. +

+

+ Since: 1.3 +

+
m +

+ Outputs the log messages of the logging event (i.e. the log + messages supplied by the client code). +

+

+ As of version 1.4, multiple log messages may be supplied to logging calls. + %m displays each log message (using the rules below) one after + another, separated by spaces. +

+

+ As of version 1.3, an object may be specified as the log message and will + be expanded to show its properties in the output, provided that a specifier + containing the number of levels to expand is provided. If no specifier is + provided then the message will be treated as a string regardless of its type. + For example, %m{1} will display an expansion of the object one + level deep, i.e. each property of the object will be displayed but if the + property value is itself an object it will not be expanded and will appear + as [object Object]. +

+
n +

+ Outputs a line separator. +

+
p +

+ Outputs the level of the logging event. +

+
r +

+ Outputs the number of milliseconds since log4javascript was initialized. +

+
% +

+ The sequence %% outputs a single percent sign. +

+
+

Static properties

+
    +
  • +
    TTCC_CONVERSION_PATTERN
    +
    + Built-in conversion pattern, equivalent to %r %p %c - %m%n. +
    +
  • +
  • +
    DEFAULT_CONVERSION_PATTERN
    +
    + Built-in conversion pattern, equivalent to %m%n. +
    +
  • +
  • +
    ISO8601_DATEFORMAT
    +
    + Built-in date format (and also the default), equivalent to + yyyy-MM-dd HH:mm:ss,SSS. +
    +
  • +
  • +
    DATETIME_DATEFORMAT
    +
    + Built-in date format, equivalent to dd MMM YYYY HH:mm:ss,SSS. +
    +
  • +
  • +
    ABSOLUTETIME_DATEFORMAT
    +
    + Built-in date format, equivalent to HH:mm:ss,SSS. +
    +
  • +
+

Constructor

+
    +
  • +
    PatternLayout
    +
    PatternLayout(String pattern)
    +
    Parameters:
    +
      +
    • + pattern +
      + The conversion pattern string to use. +
      +
    • +
    +
  • +
+

+ Top +

+
+
+

XmlLayout

+

Editions: Standard, Production

+

+ Based on log4j's XmlLayout, this layout formats a log message as a + fragment of XML. An example of the format of the fragment is as follows: +

+
+<log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR">
+<log4javascript:message><![CDATA[Big problem!]]></log4javascript:message>
+<log4javascript:exception><![CDATA[Nasty error on line number 1
+	in file http://log4javascript.org/test.html]]></log4javascript:exception>
+</log4javascript:event>
+
+

Notes

+
    +
  • + This layout supports batching of log messages when used in an + AjaxAppender. A batch of + messages is simply concatenated to form a string of several XML + frgaments similar to that above. +
  • +
  • + The <log4javascript:exception> element is only present if an + exception was passed into the original log call. +
  • +
  • + As of version 1.4, timestamps are returned as milliseconds since midnight of + January 1, 1970 rather than seconds as in previous versions. This allows finer + measurement of the time a logging event occurred and is also the JavaScript + Date object's standard measurement. +
  • +
  • + Also as of version 1.4, multiple messages may be specified as separate parameters + in a single logging call. In XmlLayout, multiple messages may be + formatted as a single combined message or may be formated as several + <log4javascript:message> elements inside one + <log4javascript:messages> element as shown below: +
    +
    +<log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR">
    +<log4javascript:messages>
    +	<log4javascript:message><![CDATA[Big problem!]]></log4javascript:message>
    +	<log4javascript:message><![CDATA[Value of x when this error
    +		occurred: 3]]></log4javascript:message>
    +</log4javascript:messages>
    +<log4javascript:exception><![CDATA[Nasty error on line number 1
    +	in file http://log4javascript.org/test.html]]></log4javascript:exception>
    +</log4javascript:event>
    +
    +
  • +
  • + As of version 1.3, custom fields may be added to the output. Each field will + add a tag of the following form inside the <log4javascript:event> + tag: +
    +
    +<log4javascript:customfield name="sessionid"><![CDATA[1234]]></log4javascript:customfield>
    +
    +
  • +
+

Constructor

+
    +
  • +
    XmlLayout
    +
    XmlLayout([Boolean combineMessages])
    +
      +
    • + combineMessages +
      + Whether or not to format multiple log messages as a combined single + <log4javascript:message> element + composed of each individual message separated by line breaks or to include + a <log4javascript:message> element for each message inside + one <log4javascript:messages> element. + If not specified, defaults to true. +
      +
    • +
    +
  • +
+

+ Top +

+
+
+

JsonLayout

+

Editions: Standard, Production

+

+ Formats a logging event into JavaScript Object Notation (JSON). + JSON is a subset of JavaScript's object literal syntax, meaning that log + messages formatted with this layout can be interpreted directly by JavaScript + and converted into objects. See + json.org for more details + about JSON. +

+

Example:

+
+{
+	"logger": "[default]",
+	"timeStamp": 1201048234203,
+	"level": "ERROR",
+	"url": "http://log4javascript.org/test.html",
+	"message": "Big problem!",
+	"exception": "Nasty error on line number 1 in file
+		http://log4javascript.org/test.html"
+}
+
+

+ The exception property is only present if an exception was passed + into the original log call. +

+

Notes

+
    +
  • + This layout supports batching of log messages when used in an + AjaxAppender. When sent singly + the layout formats the log message as a single JavaScript object literal; + when sent as a batch, the messages are formatted as an array literal whose + elements are log message objects. +
  • +
  • +

    + As of version 1.3, custom fields may be added to the output. Each field will + add a property of the following form to the main object literal: +

    +
    +	"sessionid": 1234
    +
    +
  • +
  • + From version 1.4, the variable names used for log event properties such as + the message, timestamp and exception are specified using the setKeys() + method of Layout. +
  • +
  • +

    + Also as of version 1.4, multiple messages may be specified as separate parameters + in a single logging call. In JsonLayout, multiple messages may be + formatted as a single combined message or may be formated as an array of messages + as shown below: +

    +
    +{
    +	"logger": "[default]",
    +	"timeStamp": 1201048234203,
    +	"level": "ERROR",
    +	"url": "http://log4javascript.org/test.html",
    +	"message": [
    +		"Big problem!",
    +		"Value of x when this error occurred: 3"
    +	],
    +	"exception": "Nasty error on line number 1 in file
    +		http://log4javascript.org/test.html"
    +}
    +
    +
  • +
+

Constructor

+
    +
  • +
    JsonLayout
    +
    JsonLayout([Boolean readable, Boolean combineMessages])
    +
    Parameters:
    +
      +
    • + readable +
      + Whether or not to format each log message with line breaks and tabs. + If not specified, defaults to false. +
      +
    • +
    • + combineMessages +
      + Whether or not to format multiple log messages as a combined single + message property composed of each individual message separated by line + breaks or to format multiple messages as an array. + If not specified, defaults to true. +
      +
    • +
    +
  • +
+

Methods

+
    +
  • +
    isReadable
    +
    Boolean isReadable()
    +
    + Returns whether or not to each log message is formatted with line breaks and tabs. +
    +

    Notes

    +
      +
    • +

      + setReadable has been removed in version 1.4. This property can + be set via the constructor. +

      +
    • +
    +
  • +
+
+
+

HttpPostDataLayout

+

Editions: Standard, Production

+

+ Formats the log message as a simple URL-encoded string from which a simple + server-side script may extract parameters such as the log message, severity + and timestamp. This is the default layout for + AjaxAppender. +

+

Constructor

+
    +
  • +
    HttpPostDataLayout
    +
    HttpPostDataLayout()
    +
  • +
+

Notes

+
    +
  • + As of version 1.3, custom fields may be added to the output. Each field will + be added as a parameter to the post data. +
  • +
  • + From version 1.4, the variable names used for log event properties such as + the message, timestamp and exception are specified using the setKeys() + method of Layout. +
  • +
+

+ Top +

+
+
+
+

Enabling / disabling log4javascript

+

+ All logging can be enabled or disabled in log4javascript in a number of ways: +

+
    +
  • + At any time, you can call + log4javascript.setEnabled(enabled). This will + enable or disable all logging, depending on whether enabled + is set to true or false. +
  • +
  • +

    + Assign a value to the global variable log4javascript_disabled. + The idea of this is so that you can enable or disable logging for a whole site by + including a JavaScript file in all your pages, and allowing this file to be + included before log4javascript.js to guarantee that no logging + can take place without having to alter log4javascript.js itself. Your included + .js file would include a single line such as the following: +

    +

    + var log4javascript_disabled = true; +

    +
  • +
  • + Assign your logger object a value of log4javascript.getNullLogger(). +
  • +
  • + Replace your copy of log4javascript_x.js with stubs/log4javascript_x.js, provided in the + distribution. This file has a stub version of each of the functions and methods + in the log4javascript API and can simply be dropped in in place of the main file. + The compressed version of the stub is typically 15 times smaller than the + compressed version of the main file. +
  • +
+

+ Top +

+
+
+

log4javascript error handling

+

+ log4javascript has a single rudimentary logger-like object of its own to handle + messages generated by log4javascript itself. This logger is called LogLog + and is accessed via log4javascript.logLog. +

+
+

Methods

+
    +
  • +
    setQuietMode
    +
    void setQuietMode(Boolean quietMode)
    +
    Parameters:
    +
      +
    • + quietMode +
      + Whether to turn quiet mode on or off. +
      +
    • +
    +
    + Sets whether LogLog is in quiet mode or not. In quiet mode, no + messages sent to LogLog have any visible effect. By default, + quiet mode is switched off. +
    +
  • +
  • +
    setAlertAllErrors
    +
    void setAlertAllErrors(Boolean alertAllErrors)
    +
    Parameters:
    +
      +
    • + showAllErrors +
      + Whether to show all errors or just the first. +
      +
    • +
    +
    + Sets how many errors LogLog will display alerts for. By default, + only the first error encountered generates an alert to the user. If you turn + all errors on by supplying true to this method then all errors + will generate alerts. +
    +
  • +
  • +
    debug
    +
    void debug(String message[, Error exception])
    +
    Parameters:
    +
      +
    • + message +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs a debugging message to an in-memory list. This implementation is new in version 1.4. +
    +
  • +
  • +
    displayDebug
    +
    void displayDebug()
    +
    + Displays an alert of all debugging messages. This method is new in version 1.4. +
    +
  • +
  • +
    warn
    +
    void warn(String message[, Error exception])
    +
    Parameters:
    +
      +
    • + message +
    • +
    • + exception + [optional] +
    • +
    +
    + Currently has no effect. +
    +
  • +
  • +
    error
    +
    void error(String message[, Error exception])
    +
    Parameters:
    +
      +
    • + message +
    • +
    • + exception + [optional] +
    • +
    +
    + Generates an alert to the user if and only if the error is the first one + encountered and setAlertAllErrors(true) has not been called. +
    +
  • +
+

+ Top +

+
+
+
+

Differences between log4javascript and log4j

+

+ For the sake of keeping log4javascript as light and useful as possible, many + of the features of log4j that seem over-complex or inappropriate for + JavaScript have not been implemented. These include: +

+
    +
  • Filters
  • +
  • Configurators
  • +
  • Renderers
  • +
+

+ Top +

+
+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/manual_lite.html b/planetstack/core/static/log4javascript-1.4.6/docs/manual_lite.html new file mode 100644 index 0000000..74e5a7d --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/docs/manual_lite.html @@ -0,0 +1,383 @@ + + + + + log4javascript 1.4 Lite manual + + + + + + + +
+ +
+ +

log4javascript 1.4 Lite manual

+

Contents

+ +
+

Introduction

+

+ log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It + provides functions to log messages of different severity to a pop-up window using the exactly + the same syntax as log4javascript. It is designed for situations when the key requirement is just + to display logging messages without needing all the features of the standard version of + log4javascript. +

+

+ Below is the complete list of functions and properties available in log4javascript Lite. + They make up a small subset of those provided by the standard version of + log4javascript. Each function is named and called identically to the equivalent + function in log4javascript. Please refer to the + log4javascript manual for a detailed explanation + of all the concepts alluded to in this document. +

+

+ Top +

+
+
+

log4javascript static properties/methods

+

Properties

+
    +
  • +
    version
    +
    + The version number of your copy of log4javascript. +
    +
  • +
  • +
    edition
    +
    + The edition of your copy of log4javascript ("log4javascript_lite" in this case"). +
    +
  • +
+

Methods

+
    +
  • +
    getDefaultLogger
    +
    Logger getDefaultLogger()
    +
    + Returns the default and only logger (apart from the null logger). The default logger + logs to a simple pop-up window. +
    +
  • +
  • +
    getNullLogger
    +
    Logger getNullLogger()
    +
    + Returns an empty logger. Useful for disabling all logging. +
    +
  • +
  • +
    setEnabled
    +
    void setEnabled(Boolean enabled)
    +
    Parameters:
    +
      +
    • + enabled +
    • +
    +
    + Enables or disables all logging, depending on enabled. +
    +
  • +
  • +
    isEnabled
    +
    Boolean isEnabled()
    +
    + Returns true or false depending on whether logging is enabled. +
    +
  • +
  • +
    setShowStackTraces
    +
    void setShowStackTraces(Boolean show)
    +
    Parameters:
    +
      +
    • + show +
    • +
    +
    + Enables or disables displaying of error stack traces, depending on show. + By default, stack traces are not displayed. (Only works in Firefox) +
    +
  • +
+

+ Top +

+
+
+

Levels

+

+ Levels are available as static properties of the log4javascript.Level + object. In ascending order of severity: +

+
    +
  1. log4javascript.Level.ALL
  2. +
  3. log4javascript.Level.TRACE
  4. +
  5. log4javascript.Level.DEBUG
  6. +
  7. log4javascript.Level.INFO
  8. +
  9. log4javascript.Level.WARN
  10. +
  11. log4javascript.Level.ERROR
  12. +
  13. log4javascript.Level.FATAL
  14. +
  15. log4javascript.Level.NONE
  16. +
+

+ Top +

+
+
+

Loggers

+

+ There are only two loggers in log4javascript Lite: the default logger obtained + by calling log4javascript.getDefaultLogger() and the empty logger + returned by log4javascript.getNullLogger(). +

+

Logger methods

+
    +
  • +
    setLevel
    +
    void setLevel(Level level)
    +
    Parameters:
    +
      +
    • + level +
    • +
    +
    + Sets the level. Log messages of a lower level than level will not be logged. + Default value is ALL (unlike in log4javascript, where the default level is + DEBUG). +
    +
  • +
  • +
    getLevel
    +
    Level getLevel()
    +
    + Returns the level for this logger. +
    +
  • +
  • +
    trace
    +
    void trace(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level TRACE. +
    +
  • +
  • +
    debug
    +
    void debug(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level DEBUG. +
    +
  • +
  • +
    info
    +
    void info(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level INFO. +
    +
  • +
  • +
    warn
    +
    void warn(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level WARN. +
    +
  • +
  • +
    error
    +
    void error(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level ERROR. +
    +
  • +
  • +
    fatal
    +
    void fatal(Object message1[, Object message2, ... ][, Error exception])
    +
    Parameters:
    +
      +
    • + message1[, message2...] +
    • +
    • + exception + [optional] +
    • +
    +
    + Logs one or more messages and optionally an error at level FATAL. +
    +
  • +
  • +
    isEnabledFor
    +
    Boolean isEnabledFor(Level level, Error exception)
    +
    Parameters:
    +
      +
    • + level +
    • +
    +
    + Returns whether the logger is enabled for the specified level. +
    +
  • +
  • +
    isTraceEnabled
    +
    Boolean isTraceEnabled()
    +
    + Returns whether the logger is enabled for TRACE messages. +
    +
  • +
  • +
    isDebugEnabled
    +
    Boolean isDebugEnabled()
    +
    + Returns whether the logger is enabled for DEBUG messages. +
    +
  • +
  • +
    isInfoEnabled
    +
    Boolean isInfoEnabled()
    +
    + Returns whether the logger is enabled for INFO messages. +
    +
  • +
  • +
    isWarnEnabled
    +
    Boolean isWarnEnabled()
    +
    + Returns whether the logger is enabled for WARN messages. +
    +
  • +
  • +
    isErrorEnabled
    +
    Boolean isErrorEnabled()
    +
    + Returns whether the logger is enabled for ERROR messages. +
    +
  • +
  • +
    isFatalEnabled
    +
    Boolean isFatalEnabled()
    +
    + Returns whether the logger is enabled for FATAL messages. +
    +
  • +
+

+ Top +

+
+
+

Enabling / disabling log4javascript Lite

+

+ All logging can be enabled or disabled in log4javascript Lite in a number of ways: +

+
    +
  • + At any time, you can call + log4javascript.setEnabled(enabled). This will + enable or disable all logging, depending on whether enabled + is set to true or false. +
  • +
  • + Assign your logger object a value of log4javascript.getNullLogger(). +
  • +
  • + Replace your copy of log4javascript_lite.js with stubs/log4javascript_lite.js, provided in the + distribution. This file has a stub version of each of the functions and methods + in the log4javascript Lite API and can simply be dropped in in place of the main file. +
  • +
+

+ Top +

+
+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/quickstart.html b/planetstack/core/static/log4javascript-1.4.6/docs/quickstart.html new file mode 100644 index 0000000..3bffff5 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/docs/quickstart.html @@ -0,0 +1,230 @@ + + + + + log4javascript quick start tutorial + + + + + + + +
+ +
+ +

log4javascript quick start tutorial

+

Three step guide

+
    +
  1. +

    Download the code

    +

    + Unzip the distribution and copy log4javascript.js into the desired + location. No other files are necessary. +

    +
  2. +
  3. +

    Initialize log4javascript in your web page

    +

    + Include log4javascript.js in your page using the code below. This + code assumes log4javascript is stored in the same directory as + your web page. +

    +
    +<script type="text/javascript" src="log4javascript.js"></script>
    +<script type="text/javascript">
    +	var log = log4javascript.getDefaultLogger();
    +</script>
    +
    +

    + The default logger uses a PopUpAppender + which opens a pop-up window. By default, this window will open when the first + log message is written. For this to work, you will need to disable any pop-up blockers + you may have. +

    +
  4. +
  5. +

    Include logging statements in your code

    +

    + You have six logging methods at your disposal, depending on the severity + of the message you wish to log. By default, all messages are logged + in the pop-up window. The logging methods are: +

    +
      +
    • log.trace(message[, message2, ... ][, exception])
    • +
    • log.debug(message[, message2, ... ][, exception])
    • +
    • log.info(message[, message2, ... ][, exception])
    • +
    • log.warn(message[, message2, ... ][, exception])
    • +
    • log.error(message[, message2, ... ][, exception])
    • +
    • log.fatal(message[, message2, ... ][, exception])
    • +
    +

    + And that's it, log away. Below are some examples of common types of logging. +

    +
  6. +
+

Logging examples

+
    +
  1. +

    A simple logging message string

    +
    +	log.info("Hello world");
    +
    +displays +
    +19:52:03 INFO  - Hello world
    +
    +
  2. +
  3. +

    Logging an error with a message

    +
    +	try {
    +		throw new Error("Faking something going wrong!");
    +	} catch (e) {
    +		log.error("An error occurred", e);
    +	}
    +
    +displays +
    +19:52:32 ERROR - An error occurred
    +Exception: Faking something going wrong! on line number 80 in file basic.html
    +
    +
  4. +
  5. +

    Logging multiple messages with one logging call

    +
    +	var a = "Hello";
    +	var b = 3;
    +	log.debug(a, b);
    +
    +displays +
    +19:53:05 DEBUG  - Hello 3
    +
    +
  6. +
  7. +

    Logging an object

    +

    Logging an object:

    +
    +	var obj = new Object();
    +	obj.name = "Octopus";
    +	obj.tentacles = 8;
    +	log.info(obj);
    +
    +displays +
    +19:53:17 INFO  - {
    +	name: Octopus,
    +	tentacles: 8
    +}
    +
    +
  8. +
+

Tweaking the default logger

+

+ The default logger is fine as a starting point, but what if you want the default logger + with a few different options (say, bringing the pop-up to the front whenever a log message is + logged, or having new log messages appear at the top of the pop-up rather than the bottom)? +

+

+ In this case, you will need to create a new logger, then create a + PopUpAppender, set options + on it, and add it to the logger: +

+
+<script type="text/javascript" src="log4javascript.js"></script>
+<script type="text/javascript">
+	// Create the logger
+	var log = log4javascript.getLogger();
+
+	// Create a PopUpAppender with default options
+	var popUpAppender = new log4javascript.PopUpAppender();
+
+	// Change the desired configuration options
+	popUpAppender.setFocusPopUp(true);
+	popUpAppender.setNewestMessageAtTop(true);
+
+	// Add the appender to the logger
+	log.addAppender(popUpAppender);
+
+	// Test the logger
+	log.debug("Hello world!");
+</script>
+
+

+ See this example in action (opens in new window) +

+

+ Refer to the manual for more information about + configuring appenders and more + details about PopUpAppender. +

+

Sending log messages to the server

+

+ For this you will need to use an AjaxAppender + as follows: +

+
+	var ajaxAppender = new log4javascript.AjaxAppender(URL);
+	log.addAppender(ajaxAppender);
+
+

+ Now your log messages will appear in the pop-up window and be sent + asynchronously to the URL you specify in the form of HTTP post parameters. + No server-side code to process these requests is provided with log4javascript. +

+

+ See AjaxAppender for more details + on formatting log messages. +

+

Changing the format of log messages

+

+ Using a Layout, you can + format log messages however you like. For example: +

+
+	var log = log4javascript.getLogger("mylogger");
+	var popUpAppender = new log4javascript.PopUpAppender();
+	var layout = new log4javascript.PatternLayout("[%-5p] %m");
+	popUpAppender.setLayout(layout);
+
+

A call to

+
+	log.debug("Hello world");
+
+

will now result in output in the pop-up window of

+
+[DEBUG] Hello world
+
+

+ See PatternLayout for more details + on formatting log messages. +

+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/whatsnew.html b/planetstack/core/static/log4javascript-1.4.6/docs/whatsnew.html new file mode 100644 index 0000000..6e4e06f --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/docs/whatsnew.html @@ -0,0 +1,86 @@ + + + + + log4javascript - what's new in version 1.4 + + + + + + + +
+ +
+ +

log4javascript - what's new in version 1.4

+
    +
  • + log4javascript now comes in three different editions: Standard, Production + and Lite. Full details here. +
  • +
  • + Loggers are now hierarchical and work exactly the same as log4j loggers. + This means that a logger with no level set on it inherits its level from its parent, + and inherits all of its parents appenders. +
  • +
  • + The logging console used by PopUpAppender and + InPageAppendernow has a command line, featuring + a command history navigated with the up and down arrow keys and a number of built-in command line + functions. +
  • +
  • + It is now possible to specify multiple messages in a single log call. +
  • +
  • + Log messages may be grouped in the logging console. +
  • +
  • + Built-in timers. +
  • +
  • + Improved AjaxAppender, with the ability + to send all pending log calls to the server when navigating away from a page. Timestamps now + include milliseconds. All log messages or batches of log messages are now posted as + name-value pairs. +
  • +
  • + Support for IE8 beta 2. +
  • +
  • + Many minor enhancements and bug fixes. See the change log for full + details. +
  • +
+

+ Please note that there are a few minor incompatibilities + with earlier versions of log4javascript. +

+
+ +
+ + + diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/demo.html b/planetstack/core/static/log4javascript-1.4.6/examples/demo.html new file mode 100644 index 0000000..118b879 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/examples/demo.html @@ -0,0 +1,16 @@ + + + + + log4javascript demo redirect + + + + + + + + This page has been replaced by the basic demo page. + Please use this link if you are not redirected automatically. + + diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/example_manual.html b/planetstack/core/static/log4javascript-1.4.6/examples/example_manual.html new file mode 100644 index 0000000..68189e3 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/examples/example_manual.html @@ -0,0 +1,31 @@ + + + + + log4javascript example from manual + + + + + + + + +

log4javascript example from manual

+ + + + diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html b/planetstack/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html new file mode 100644 index 0000000..3ae4a9f --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html @@ -0,0 +1,36 @@ + + + + + log4javascript quick start example 1 + + + + + + + + +

log4javascript quick start example 1

+ + + + diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/myloggingservlet.do b/planetstack/core/static/log4javascript-1.4.6/examples/myloggingservlet.do new file mode 100644 index 0000000..e69de29 diff --git a/planetstack/core/static/log4javascript-1.4.6/js/console.html b/planetstack/core/static/log4javascript-1.4.6/js/console.html new file mode 100644 index 0000000..476d272 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/console.html @@ -0,0 +1,263 @@ + + + +log4javascript + + + + + + + + + + +
+
+
+Filters: + + + + + + + +
+ +
+Options: + + + + + + + +
+
+
+
+
+
+ + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/js/console_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/js/console_uncompressed.html new file mode 100644 index 0000000..55679f8 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/console_uncompressed.html @@ -0,0 +1,2279 @@ + + + + log4javascript + + + + + + + + + + + +
+
+
+ Filters: + + + + + + + +
+ +
+ Options: + + + + + + + +
+
+
+
+
+
+ + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/js/liteconsole.html b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole.html new file mode 100644 index 0000000..840a59b --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole.html @@ -0,0 +1,41 @@ + + + +log4javascript + + + + + + + +
+Options: + + + +
+
+ + \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html new file mode 100644 index 0000000..df5275f --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html @@ -0,0 +1,194 @@ + + + + log4javascript + + + + + + + + +
+ Options: + + + +
+
+ + \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript.js new file mode 100644 index 0000000..042daa9 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript.js @@ -0,0 +1,274 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i0){var firstItem=this[0];for(var i=0,len=this.length-1;i2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();} +Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+ +toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i1&&isError(lastParam)){exception=lastParam;finalParamIndex--;} +var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];} +var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};} +Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+ +toStr(loggerName)+" supplied, returning anonymous logger");} +if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");} +if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;} +parentLogger.addChild(logger);} +return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);} +return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);} +return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);} +if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);} +if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+ +this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+ +this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];} +SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];} +NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];} +XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]>";} +var str=""+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+=""+newLine;for(i=0,len=loggingEvent.messages.length;i"+newLine;}} +if(loggingEvent.exception){str+=""+newLine;} +str+=""+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");} +function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];} +JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+" ";childLines=[];for(i=0,len=obj.length;i0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+" ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+ +getExceptionStringRep(ex));}} +expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}} +return doFormat(obj,depth,indentation);} +var SimpleDateFormat;(function(){var 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']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()=minimalDaysInFirstWeek){weekInMonth++;} +return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;} +switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);} +break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);} +break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}} +searchString=searchString.substr(result.index+result[0].length);} +return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;} +this.customFields=[];} +PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}} +var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";} +if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}} +break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;} +break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}} +replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}} +var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);} +replacement=val;} +break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;} +var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l=200&&xmlHttp.status<300)||xmlHttp.status==1223;} +function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;} +var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+ +configOptionName+"' may not be set after the appender has been initialized");return false;} +return true;} +this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));} +sending=false;if(timed){scheduleSending();}}}} +this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}} +if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);} +sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();} +return sendingAnything;} +this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();} +formattedMessages.push(currentFormattedMessage);} +if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+ +formattedMessages.join(appender.getLayout().batchSeparator)+ +appender.getLayout().batchFooter;} +if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";} +postData+="layout="+urlEncode(appender.getLayout().toString());} +return postData;} +function scheduleSending(){window.setTimeout(sendAll,timerInterval);} +function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}} +function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());} +xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);} +if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+ +url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}} +xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);} +xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);} +return;} +xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}} +this.append=function(loggingEvent){if(isSupported){if(!initialized){init();} +queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);} +queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();} +if(sendAllRemaining()){return"Sending log messages";}};} +if(timed){scheduleSending();}}} +AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;function setCookie(name,value,days,path){var expires;path=path?"; path="+path:"";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString();}else{expires="";} +document.cookie=escape(name)+"="+escape(value)+expires+path;} +function getCookie(name){var nameEquals=escape(name)+"=";var ca=document.cookie.split(";");for(var i=0,len=ca.length;i','','','log4javascript','','','','','','','','','','','
','
','
','Filters:','','','','','','','','
','','
','Options:','','','','','','','','
','
','
','
','
','
','','','
','
','','',''];};var defaultCommandLineFunctions=[];ConsoleAppender=function(){};var consoleAppenderIdCounter=1;ConsoleAppender.prototype=new Appender();ConsoleAppender.prototype.create=function(inPage,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,focusConsoleWindow){var appender=this;var initialized=false;var consoleWindowCreated=false;var consoleWindowLoaded=false;var consoleClosed=false;var queuedLoggingEvents=[];var isSupported=true;var consoleAppenderId=consoleAppenderIdCounter++;initiallyMinimized=extractBooleanFromParam(initiallyMinimized,this.defaults.initiallyMinimized);lazyInit=extractBooleanFromParam(lazyInit,this.defaults.lazyInit);useDocumentWrite=extractBooleanFromParam(useDocumentWrite,this.defaults.useDocumentWrite);var newestMessageAtTop=this.defaults.newestMessageAtTop;var scrollToLatestMessage=this.defaults.scrollToLatestMessage;width=width?width:this.defaults.width;height=height?height:this.defaults.height;var maxMessages=this.defaults.maxMessages;var showCommandLine=this.defaults.showCommandLine;var commandLineObjectExpansionDepth=this.defaults.commandLineObjectExpansionDepth;var showHideButton=this.defaults.showHideButton;var showCloseButton=this.defaults.showCloseButton;var showLogEntryDeleteButtons=this.defaults.showLogEntryDeleteButtons;this.setLayout(this.defaults.layout);var init,createWindow,safeToAppend,getConsoleWindow,open;var appenderName=inPage?"InPageAppender":"PopUpAppender";var checkCanConfigure=function(configOptionName){if(consoleWindowCreated){handleError(appenderName+": configuration option '"+configOptionName+"' may not be set after the appender has been initialized");return false;} +return true;};var consoleWindowExists=function(){return(consoleWindowLoaded&&isSupported&&!consoleClosed);};this.isNewestMessageAtTop=function(){return newestMessageAtTop;};this.setNewestMessageAtTop=function(newestMessageAtTopParam){newestMessageAtTop=bool(newestMessageAtTopParam);if(consoleWindowExists()){getConsoleWindow().setNewestAtTop(newestMessageAtTop);}};this.isScrollToLatestMessage=function(){return scrollToLatestMessage;};this.setScrollToLatestMessage=function(scrollToLatestMessageParam){scrollToLatestMessage=bool(scrollToLatestMessageParam);if(consoleWindowExists()){getConsoleWindow().setScrollToLatest(scrollToLatestMessage);}};this.getWidth=function(){return width;};this.setWidth=function(widthParam){if(checkCanConfigure("width")){width=extractStringFromParam(widthParam,width);}};this.getHeight=function(){return height;};this.setHeight=function(heightParam){if(checkCanConfigure("height")){height=extractStringFromParam(heightParam,height);}};this.getMaxMessages=function(){return maxMessages;};this.setMaxMessages=function(maxMessagesParam){maxMessages=extractIntFromParam(maxMessagesParam,maxMessages);if(consoleWindowExists()){getConsoleWindow().setMaxMessages(maxMessages);}};this.isShowCommandLine=function(){return showCommandLine;};this.setShowCommandLine=function(showCommandLineParam){showCommandLine=bool(showCommandLineParam);if(consoleWindowExists()){getConsoleWindow().setShowCommandLine(showCommandLine);}};this.isShowHideButton=function(){return showHideButton;};this.setShowHideButton=function(showHideButtonParam){showHideButton=bool(showHideButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowHideButton(showHideButton);}};this.isShowCloseButton=function(){return showCloseButton;};this.setShowCloseButton=function(showCloseButtonParam){showCloseButton=bool(showCloseButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowCloseButton(showCloseButton);}};this.getCommandLineObjectExpansionDepth=function(){return commandLineObjectExpansionDepth;};this.setCommandLineObjectExpansionDepth=function(commandLineObjectExpansionDepthParam){commandLineObjectExpansionDepth=extractIntFromParam(commandLineObjectExpansionDepthParam,commandLineObjectExpansionDepth);};var minimized=initiallyMinimized;this.isInitiallyMinimized=function(){return initiallyMinimized;};this.setInitiallyMinimized=function(initiallyMinimizedParam){if(checkCanConfigure("initiallyMinimized")){initiallyMinimized=bool(initiallyMinimizedParam);minimized=initiallyMinimized;}};this.isUseDocumentWrite=function(){return useDocumentWrite;};this.setUseDocumentWrite=function(useDocumentWriteParam){if(checkCanConfigure("useDocumentWrite")){useDocumentWrite=bool(useDocumentWriteParam);}};function QueuedLoggingEvent(loggingEvent,formattedMessage){this.loggingEvent=loggingEvent;this.levelName=loggingEvent.level.name;this.formattedMessage=formattedMessage;} +QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;} +QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){} +QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();} +if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();} +queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent,formattedMessage));checkAndAppend();}};this.group=function(name,initiallyExpanded){if(isSupported){queuedLoggingEvents.push(new QueuedGroup(name,initiallyExpanded));checkAndAppend();}};this.groupEnd=function(){if(isSupported){queuedLoggingEvents.push(new QueuedGroupEnd());checkAndAppend();}};var appendQueuedLoggingEvents=function(){var currentLoggingEvent;while(queuedLoggingEvents.length>0){queuedLoggingEvents.shift().append();} +if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();} +queuedLoggingEvents.length=0;};this.focus=function(){if(consoleWindowExists()){getConsoleWindow().focus();}};this.focusCommandLine=function(){if(consoleWindowExists()){getConsoleWindow().focusCommandLine();}};this.focusSearch=function(){if(consoleWindowExists()){getConsoleWindow().focusSearch();}};var commandWindow=window;this.getCommandWindow=function(){return commandWindow;};this.setCommandWindow=function(commandWindowParam){commandWindow=commandWindowParam;};this.executeLastCommand=function(){if(consoleWindowExists()){getConsoleWindow().evalLastCommand();}};var commandLayout=new PatternLayout("%m");this.getCommandLayout=function(){return commandLayout;};this.setCommandLayout=function(commandLayoutParam){commandLayout=commandLayoutParam;};this.evalCommandAndAppend=function(expr){var commandReturnValue={appendResult:true,isError:false};var commandOutput="";try{var result,i;if(!commandWindow.eval&&commandWindow.execScript){commandWindow.execScript("null");} +var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i";consoleClosed=false;var iframeDocumentExistsTest=function(win){try{return bool(win)&&bool(win.document);}catch(ex){return false;}};if(iframeDocumentExistsTest(getConsoleWindow())){writeToDocument();}else{pollConsoleWindow(iframeDocumentExistsTest,100,writeToDocument,initErrorMessage);} +consoleWindowCreated=true;};createWindow=function(show){if(show||!initiallyMinimized){var pageLoadHandler=function(){if(!container){containerElement=document.createElement("div");containerElement.style.position="fixed";containerElement.style.left="0";containerElement.style.right="0";containerElement.style.bottom="0";document.body.appendChild(containerElement);appender.addCssProperty("borderWidth","1px 0 0 0");appender.addCssProperty("zIndex",1000000);open();}else{try{var el=document.getElementById(container);if(el.nodeType==1){containerElement=el;} +open();}catch(ex){handleError("InPageAppender.init: invalid container element '"+container+"' supplied",ex);}}};if(pageLoaded&&container&&container.appendChild){containerElement=container;open();}else if(pageLoaded){pageLoadHandler();}else{log4javascript.addEventListener("load",pageLoadHandler);} +windowCreationStarted=true;}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){var iframe=window.frames[iframeId];if(iframe){return iframe;}};safeToAppend=function(){if(isSupported&&!consoleClosed){if(consoleWindowCreated&&!consoleWindowLoaded&&getConsoleWindow()&&isLoaded(getConsoleWindow())){consoleWindowLoaded=true;} +return consoleWindowLoaded;} +return false;};}else{var useOldPopUp=appender.defaults.useOldPopUp;var complainAboutPopUpBlocking=appender.defaults.complainAboutPopUpBlocking;var reopenWhenClosed=this.defaults.reopenWhenClosed;this.isUseOldPopUp=function(){return useOldPopUp;};this.setUseOldPopUp=function(useOldPopUpParam){if(checkCanConfigure("useOldPopUp")){useOldPopUp=bool(useOldPopUpParam);}};this.isComplainAboutPopUpBlocking=function(){return complainAboutPopUpBlocking;};this.setComplainAboutPopUpBlocking=function(complainAboutPopUpBlockingParam){if(checkCanConfigure("complainAboutPopUpBlocking")){complainAboutPopUpBlocking=bool(complainAboutPopUpBlockingParam);}};this.isFocusPopUp=function(){return focusConsoleWindow;};this.setFocusPopUp=function(focusPopUpParam){focusConsoleWindow=bool(focusPopUpParam);};this.isReopenWhenClosed=function(){return reopenWhenClosed;};this.setReopenWhenClosed=function(reopenWhenClosedParam){reopenWhenClosed=bool(reopenWhenClosedParam);};this.close=function(){logLog.debug("close "+this);try{popUp.close();this.unload();}catch(ex){}};this.hide=function(){logLog.debug("hide "+this);if(consoleWindowExists()){this.close();}};this.show=function(){logLog.debug("show "+this);if(!consoleWindowCreated){open();}};this.isVisible=function(){return safeToAppend();};var popUp;open=function(){var windowProperties="width="+width+",height="+height+",status,resizable";var frameInfo="";try{var frameEl=window.frameElement;if(frameEl){frameInfo="_"+frameEl.tagName+"_"+(frameEl.name||frameEl.id||"");}}catch(e){frameInfo="_inaccessibleParentFrame";} +var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;} +var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}} +return false;};var popUpClosedCallback=function(){if(!consoleClosed){appender.unload();}};function finalInit(){getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp||!useDocumentWrite);consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();pollConsoleWindow(checkPopUpClosed,500,popUpClosedCallback,"PopUpAppender.checkPopUpClosed: error checking pop-up window");} +try{popUp=window.open(getConsoleUrl(),windowName,windowProperties);consoleClosed=false;consoleWindowCreated=true;if(popUp&&popUp.document){if(useDocumentWrite&&useOldPopUp&&isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{if(useDocumentWrite){writeHtml(popUp.document);} +var popUpLoadedTest=function(win){return bool(win)&&isLoaded(win);};if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow(popUpLoadedTest,100,finalInit,"PopUpAppender.init: unable to create console window");}}}else{isSupported=false;logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");if(complainAboutPopUpBlocking){handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}}catch(ex){handleError("PopUpAppender.init: error creating pop-up",ex);}};createWindow=function(){if(!initiallyMinimized){open();}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){return popUp;};safeToAppend=function(){if(isSupported&&!isUndefined(popUp)&&!consoleClosed){if(popUp.closed||(consoleWindowLoaded&&isUndefined(popUp.closed))){appender.unload();logLog.debug("PopUpAppender: pop-up closed");return false;} +if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}} +return isSupported&&consoleWindowLoaded&&!consoleClosed;};} +this.getConsoleWindow=getConsoleWindow;};ConsoleAppender.addGlobalCommandLineFunction=function(functionName,commandLineFunction){defaultCommandLineFunctions.push([functionName,commandLineFunction]);};function PopUpAppender(lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(false,null,lazyInit,initiallyMinimized,useDocumentWrite,width,height,this.defaults.focusPopUp);} +PopUpAppender.prototype=new ConsoleAppender();PopUpAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,focusPopUp:false,lazyInit:true,useOldPopUp:true,complainAboutPopUpBlocking:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"600",height:"400",reopenWhenClosed:false,maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:true,showLogEntryDeleteButtons:true,useDocumentWrite:true};PopUpAppender.prototype.toString=function(){return"PopUpAppender";};log4javascript.PopUpAppender=PopUpAppender;function InPageAppender(container,lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(true,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,false);} +InPageAppender.prototype=new ConsoleAppender();InPageAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,lazyInit:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"100%",height:"220px",maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:false,showLogEntryDeleteButtons:true,useDocumentWrite:true};InPageAppender.prototype.toString=function(){return"InPageAppender";};log4javascript.InPageAppender=InPageAppender;log4javascript.InlineAppender=InPageAppender;})();function padWithSpaces(str,len){if(str.length]*>","i");if(regex.test(el.outerHTML)){return RegExp.$1.toLowerCase();}} +return"";} +var lt="<";var gt=">";if(includeRootNode&&rootNode.nodeType!=nodeTypes.DOCUMENT_FRAGMENT_NODE){switch(rootNode.nodeType){case nodeTypes.ELEMENT_NODE:var tagName=rootNode.tagName.toLowerCase();xhtml=startNewLine?newLine+indentation:"";xhtml+=lt;var prefix=getNamespace(rootNode);var hasPrefix=!!prefix;if(hasPrefix){xhtml+=prefix+":";} +xhtml+=tagName;for(i=0,len=rootNode.attributes.length;i"+newLine;case nodeTypes.DOCUMENT_NODE:xhtml="";for(var i=0,len=rootNode.childNodes.length;i0){var firstItem=this[0];for(var i=0,len=this.length-1;i=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Appender(){var getConsoleHtmlLines=function(){return['','','','log4javascript','','','','','','','','
','Options:','','','','
','
','',''];};var popUp=null;var popUpsBlocked=false;var popUpClosed=false;var popUpLoaded=false;var complainAboutPopUpBlocking=true;var initialized=false;var isSupported=true;var width=600;var height=400;var focusPopUp=false;var queuedLoggingEvents=new Array();function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}} +function finalInit(){popUpLoaded=true;appendQueuedLoggingEvents();} +function writeHtml(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i0){var currentLoggingEvent=queuedLoggingEvents.shift();var date=currentLoggingEvent.timeStamp;var formattedDate=padWithZeroes(date.getHours(),2)+":"+ +padWithZeroes(date.getMinutes(),2)+":"+padWithZeroes(date.getSeconds(),2);var formattedMessage=formattedDate+" "+padWithSpaces(currentLoggingEvent.level.name,5)+" - "+currentLoggingEvent.getCombinedMessages();var throwableStringRep=currentLoggingEvent.getThrowableStrRep();if(throwableStringRep){formattedMessage+=newLine+throwableStringRep;} +popUp.log(currentLoggingEvent.level,formattedMessage);} +if(focusPopUp){popUp.focus();}}}} +log4javascript.Appender=Appender;function Logger(){var appender=new Appender();var loggerLevel=Level.ALL;this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[params.length-1];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;} +var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];} +var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);appender.append(loggingEvent);}};this.setLevel=function(level){loggerLevel=level;};this.getLevel=function(){return loggerLevel;};} +Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=new Logger();} +return defaultLogger;};log4javascript.getLogger=log4javascript.getDefaultLogger;var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger();nullLogger.setLevel(Level.OFF);} +return nullLogger;};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length===1)?this.messages[0]:this.messages.join(newLine);}};log4javascript.LoggingEvent=LoggingEvent;window.log4javascript=log4javascript;})(); diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js new file mode 100644 index 0000000..12e97d8 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js @@ -0,0 +1,620 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +if (!Array.prototype.shift) { + Array.prototype.shift = function() { + if (this.length > 0) { + var firstItem = this[0]; + for (var i = 0, len = this.length - 1; i < len; i++) { + this[i] = this[i + 1]; + } + this.length--; + return firstItem; + } + }; +} + +var log4javascript; + +(function() { + var newLine = "\r\n"; + function Log4JavaScript() {} + log4javascript = new Log4JavaScript(); + log4javascript.version = "1.4.6"; + log4javascript.edition = "log4javascript_lite"; + + function getExceptionMessage(ex) { + if (ex.message) { + return ex.message; + } else if (ex.description) { + return ex.description; + } else { + return String(ex); + } + } + + // Gets the portion of the URL after the last slash + function getUrlFileName(url) { + var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\")); + return url.substr(lastSlashIndex + 1); + } + + // Returns a nicely formatted representation of an error + function getExceptionStringRep(ex) { + if (ex) { + var exStr = "Exception: " + getExceptionMessage(ex); + try { + if (ex.lineNumber) { + exStr += " on line number " + ex.lineNumber; + } + if (ex.fileName) { + exStr += " in file " + getUrlFileName(ex.fileName); + } + } catch (localEx) { + } + if (showStackTraces && ex.stack) { + exStr += newLine + "Stack trace:" + newLine + ex.stack; + } + return exStr; + } + return null; + } + + function isError(err) { + return (err instanceof Error); + } + + function bool(obj) { + return Boolean(obj); + } + + var enabled = (typeof log4javascript_disabled != "undefined") && + log4javascript_disabled ? false : true; + + log4javascript.setEnabled = function(enable) { + enabled = bool(enable); + }; + + log4javascript.isEnabled = function() { + return enabled; + }; + + var showStackTraces = false; + + log4javascript.setShowStackTraces = function(show) { + showStackTraces = bool(show); + }; + + /* ---------------------------------------------------------------------- */ + // Levels + + var Level = function(level, name) { + this.level = level; + this.name = name; + }; + + Level.prototype = { + toString: function() { + return this.name; + }, + equals: function(level) { + return this.level == level.level; + }, + isGreaterOrEqual: function(level) { + return this.level >= level.level; + } + }; + + Level.ALL = new Level(Number.MIN_VALUE, "ALL"); + Level.TRACE = new Level(10000, "TRACE"); + Level.DEBUG = new Level(20000, "DEBUG"); + Level.INFO = new Level(30000, "INFO"); + Level.WARN = new Level(40000, "WARN"); + Level.ERROR = new Level(50000, "ERROR"); + Level.FATAL = new Level(60000, "FATAL"); + Level.OFF = new Level(Number.MAX_VALUE, "OFF"); + + log4javascript.Level = Level; + + /* ---------------------------------------------------------------------- */ + // Appenders + + function Appender() { + var getConsoleHtmlLines = function() { + return [ +'', +'', +' ', +' log4javascript', +' ', +' ', +' ', +' ', +' ', +' ', +'', +' ', +'
', +' Options:', +' ', +' ', +' ', +'
', +'
', +' ', +'' +]; + }; + + var popUp = null; + var popUpsBlocked = false; + var popUpClosed = false; + var popUpLoaded = false; + var complainAboutPopUpBlocking = true; + var initialized = false; + var isSupported = true; + var width = 600; + var height = 400; + var focusPopUp = false; + var queuedLoggingEvents = new Array(); + + function isLoaded(win) { + try { + return bool(win.loaded); + } catch (ex) { + return false; + } + } + + function finalInit() { + popUpLoaded = true; + appendQueuedLoggingEvents(); + } + + function writeHtml(doc) { + var lines = getConsoleHtmlLines(); + doc.open(); + for (var i = 0, len = lines.length; i < len; i++) { + doc.writeln(lines[i]); + } + doc.close(); + } + + function pollConsoleWindow() { + function pollConsoleWindowLoaded() { + if (popUpLoaded) { + clearInterval(poll); + } else if (bool(popUp) && isLoaded(popUp)) { + clearInterval(poll); + finalInit(); + } + } + + // Poll the pop-up since the onload event is not reliable + var poll = setInterval(pollConsoleWindowLoaded, 100); + } + + function init() { + var windowProperties = "width=" + width + ",height=" + height + ",status,resizable"; + var windowName = "log4javascriptLitePopUp" + location.host.replace(/[^a-z0-9]/gi, "_"); + + popUp = window.open("", windowName, windowProperties); + popUpClosed = false; + if (popUp) { + if (isLoaded(popUp)) { + popUp.mainPageReloaded(); + finalInit(); + } else { + writeHtml(popUp.document); + + // Check if the pop-up window object is available + if (isLoaded(popUp)) { + finalInit(); + } else { + pollConsoleWindow(); + } + } + } else { + isSupported = false; + if (complainAboutPopUpBlocking) { + alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging."); + } + } + initialized = true; + } + + function safeToAppend() { + if (!popUpsBlocked && !popUpClosed) { + if (popUp.closed) { + popUpClosed = true; + return false; + } + if (!popUpLoaded && popUp.loaded) { + popUpLoaded = true; + } + } + return !popUpsBlocked && popUpLoaded && !popUpClosed; + } + + function padWithZeroes(num, len) { + var str = "" + num; + while (str.length < len) { + str = "0" + str; + } + return str; + } + + function padWithSpaces(str, len) { + while (str.length < len) { + str += " "; + } + return str; + } + + this.append = function(loggingEvent) { + if (!initialized) { + init(); + } + queuedLoggingEvents.push(loggingEvent); + if (safeToAppend()) { + appendQueuedLoggingEvents(); + } + }; + + function appendQueuedLoggingEvents() { + if (safeToAppend()) { + while (queuedLoggingEvents.length > 0) { + var currentLoggingEvent = queuedLoggingEvents.shift(); + var date = currentLoggingEvent.timeStamp; + var formattedDate = padWithZeroes(date.getHours(), 2) + ":" + + padWithZeroes(date.getMinutes(), 2) + ":" + padWithZeroes(date.getSeconds(), 2); + var formattedMessage = formattedDate + " " + padWithSpaces(currentLoggingEvent.level.name, 5) + + " - " + currentLoggingEvent.getCombinedMessages(); + var throwableStringRep = currentLoggingEvent.getThrowableStrRep(); + if (throwableStringRep) { + formattedMessage += newLine + throwableStringRep; + } + popUp.log(currentLoggingEvent.level, formattedMessage); + } + if (focusPopUp) { + popUp.focus(); + } + } + } + } + + log4javascript.Appender = Appender; + + /* ---------------------------------------------------------------------- */ + // Loggers + + function Logger() { + var appender = new Appender(); + var loggerLevel = Level.ALL; + + this.log = function(level, params) { + if (enabled && level.isGreaterOrEqual(this.getLevel())) { + // Check whether last param is an exception + var exception; + var finalParamIndex = params.length - 1; + var lastParam = params[params.length - 1]; + if (params.length > 1 && isError(lastParam)) { + exception = lastParam; + finalParamIndex--; + } + + // Construct genuine array for the params + var messages = []; + for (var i = 0; i <= finalParamIndex; i++) { + messages[i] = params[i]; + } + + var loggingEvent = new LoggingEvent( + this, new Date(), level, messages, exception); + + appender.append(loggingEvent); + } + }; + + this.setLevel = function(level) { + loggerLevel = level; + }; + + this.getLevel = function() { + return loggerLevel; + }; + } + + Logger.prototype = { + trace: function() { + this.log(Level.TRACE, arguments); + }, + + debug: function() { + this.log(Level.DEBUG, arguments); + }, + + info: function() { + this.log(Level.INFO, arguments); + }, + + warn: function() { + this.log(Level.WARN, arguments); + }, + + error: function() { + this.log(Level.ERROR, arguments); + }, + + fatal: function() { + this.log(Level.FATAL, arguments); + }, + + isEnabledFor: function(level) { + return level.isGreaterOrEqual(this.getLevel()); + }, + + isTraceEnabled: function() { + return this.isEnabledFor(Level.TRACE); + }, + + isDebugEnabled: function() { + return this.isEnabledFor(Level.DEBUG); + }, + + isInfoEnabled: function() { + return this.isEnabledFor(Level.INFO); + }, + + isWarnEnabled: function() { + return this.isEnabledFor(Level.WARN); + }, + + isErrorEnabled: function() { + return this.isEnabledFor(Level.ERROR); + }, + + isFatalEnabled: function() { + return this.isEnabledFor(Level.FATAL); + } + }; + + /* ---------------------------------------------------------------------- */ + // Logger access methods + + var defaultLogger = null; + log4javascript.getDefaultLogger = function() { + if (!defaultLogger) { + defaultLogger = new Logger(); + } + return defaultLogger; + }; + + log4javascript.getLogger = log4javascript.getDefaultLogger; + + var nullLogger = null; + log4javascript.getNullLogger = function() { + if (!nullLogger) { + nullLogger = new Logger(); + nullLogger.setLevel(Level.OFF); + } + return nullLogger; + }; + + /* ---------------------------------------------------------------------- */ + // Logging events + + var LoggingEvent = function(logger, timeStamp, level, messages, + exception) { + this.logger = logger; + this.timeStamp = timeStamp; + this.level = level; + this.messages = messages; + this.exception = exception; + }; + + LoggingEvent.prototype = { + getThrowableStrRep: function() { + return this.exception ? + getExceptionStringRep(this.exception) : ""; + }, + + getCombinedMessages: function() { + return (this.messages.length === 1) ? this.messages[0] : + this.messages.join(newLine); + } + }; + + log4javascript.LoggingEvent = LoggingEvent; + + // Ensure that the log4javascript object is available in the window. This + // is necessary for log4javascript to be available in IE if loaded using + // Dojo's module system + window.log4javascript = log4javascript; +})(); \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production.js new file mode 100644 index 0000000..1a31299 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production.js @@ -0,0 +1,188 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i0){var firstItem=this[0];for(var i=0,len=this.length-1;i2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();} +Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+ +toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i1&&isError(lastParam)){exception=lastParam;finalParamIndex--;} +var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];} +var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};} +Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+ +toStr(loggerName)+" supplied, returning anonymous logger");} +if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");} +if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;} +parentLogger.addChild(logger);} +return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);} +return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);} +return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);} +if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);} +if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+ +this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+ +this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];} +SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];} +NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];} +XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]>";} +var str=""+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+=""+newLine;for(i=0,len=loggingEvent.messages.length;i"+newLine;}} +if(loggingEvent.exception){str+=""+newLine;} +str+=""+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");} +function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];} +JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+" ";childLines=[];for(i=0,len=obj.length;i0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+" ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+ +getExceptionStringRep(ex));}} +expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}} +return doFormat(obj,depth,indentation);} +var SimpleDateFormat;(function(){var 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']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()=minimalDaysInFirstWeek){weekInMonth++;} +return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;} +switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);} +break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);} +break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}} +searchString=searchString.substr(result.index+result[0].length);} +return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;} +this.customFields=[];} +PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}} +var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";} +if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}} +break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;} +break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}} +replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}} +var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);} +replacement=val;} +break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;} +var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l=200&&xmlHttp.status<300)||xmlHttp.status==1223;} +function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;} +var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+ +configOptionName+"' may not be set after the appender has been initialized");return false;} +return true;} +this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));} +sending=false;if(timed){scheduleSending();}}}} +this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}} +if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);} +sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();} +return sendingAnything;} +this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();} +formattedMessages.push(currentFormattedMessage);} +if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+ +formattedMessages.join(appender.getLayout().batchSeparator)+ +appender.getLayout().batchFooter;} +if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";} +postData+="layout="+urlEncode(appender.getLayout().toString());} +return postData;} +function scheduleSending(){window.setTimeout(sendAll,timerInterval);} +function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}} +function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());} +xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);} +if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+ +url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}} +xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);} +xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);} +return;} +xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}} +this.append=function(loggingEvent){if(isSupported){if(!initialized){init();} +queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);} +queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();} +if(sendAllRemaining()){return"Sending log messages";}};} +if(timed){scheduleSending();}}} +AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);} +log4javascript.setDocumentReady();};}} +window.log4javascript=log4javascript;return log4javascript;})(); diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js new file mode 100644 index 0000000..1a29621 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js @@ -0,0 +1,2290 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * log4javascript + * + * log4javascript is a logging framework for JavaScript based on log4j + * for Java. This file contains all core log4javascript code and is the only + * file required to use log4javascript, unless you require support for + * document.domain, in which case you will also need console.html, which must be + * stored in the same directory as the main log4javascript.js file. + * + * Author: Tim Down + * Version: 1.4.6 + * Edition: log4javascript_production + * Build date: 19 March 2013 + * Website: http://log4javascript.org + */ + +/* -------------------------------------------------------------------------- */ +// Array-related stuff + +// Next three methods are solely for IE5, which is missing them +if (!Array.prototype.push) { + Array.prototype.push = function() { + for (var i = 0, len = arguments.length; i < len; i++){ + this[this.length] = arguments[i]; + } + return this.length; + }; +} + +if (!Array.prototype.shift) { + Array.prototype.shift = function() { + if (this.length > 0) { + var firstItem = this[0]; + for (var i = 0, len = this.length - 1; i < len; i++) { + this[i] = this[i + 1]; + } + this.length = this.length - 1; + return firstItem; + } + }; +} + +if (!Array.prototype.splice) { + Array.prototype.splice = function(startIndex, deleteCount) { + var itemsAfterDeleted = this.slice(startIndex + deleteCount); + var itemsDeleted = this.slice(startIndex, startIndex + deleteCount); + this.length = startIndex; + // Copy the arguments into a proper Array object + var argumentsArray = []; + for (var i = 0, len = arguments.length; i < len; i++) { + argumentsArray[i] = arguments[i]; + } + var itemsToAppend = (argumentsArray.length > 2) ? + itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted; + for (i = 0, len = itemsToAppend.length; i < len; i++) { + this.push(itemsToAppend[i]); + } + return itemsDeleted; + }; +} + +/* -------------------------------------------------------------------------- */ + +var log4javascript = (function() { + + function isUndefined(obj) { + return typeof obj == "undefined"; + } + + /* ---------------------------------------------------------------------- */ + // Custom event support + + function EventSupport() {} + + EventSupport.prototype = { + eventTypes: [], + eventListeners: {}, + setEventTypes: function(eventTypesParam) { + if (eventTypesParam instanceof Array) { + this.eventTypes = eventTypesParam; + this.eventListeners = {}; + for (var i = 0, len = this.eventTypes.length; i < len; i++) { + this.eventListeners[this.eventTypes[i]] = []; + } + } else { + handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array"); + } + }, + + addEventListener: function(eventType, listener) { + if (typeof listener == "function") { + if (!array_contains(this.eventTypes, eventType)) { + handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'"); + } + this.eventListeners[eventType].push(listener); + } else { + handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function"); + } + }, + + removeEventListener: function(eventType, listener) { + if (typeof listener == "function") { + if (!array_contains(this.eventTypes, eventType)) { + handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'"); + } + array_remove(this.eventListeners[eventType], listener); + } else { + handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function"); + } + }, + + dispatchEvent: function(eventType, eventArgs) { + if (array_contains(this.eventTypes, eventType)) { + var listeners = this.eventListeners[eventType]; + for (var i = 0, len = listeners.length; i < len; i++) { + listeners[i](this, eventType, eventArgs); + } + } else { + handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'"); + } + } + }; + + /* -------------------------------------------------------------------------- */ + + var applicationStartDate = new Date(); + var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" + + Math.floor(Math.random() * 100000000); + var emptyFunction = function() {}; + var newLine = "\r\n"; + var pageLoaded = false; + + // Create main log4javascript object; this will be assigned public properties + function Log4JavaScript() {} + Log4JavaScript.prototype = new EventSupport(); + + log4javascript = new Log4JavaScript(); + log4javascript.version = "1.4.6"; + log4javascript.edition = "log4javascript_production"; + + /* -------------------------------------------------------------------------- */ + // Utility functions + + function toStr(obj) { + if (obj && obj.toString) { + return obj.toString(); + } else { + return String(obj); + } + } + + function getExceptionMessage(ex) { + if (ex.message) { + return ex.message; + } else if (ex.description) { + return ex.description; + } else { + return toStr(ex); + } + } + + // Gets the portion of the URL after the last slash + function getUrlFileName(url) { + var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\")); + return url.substr(lastSlashIndex + 1); + } + + // Returns a nicely formatted representation of an error + function getExceptionStringRep(ex) { + if (ex) { + var exStr = "Exception: " + getExceptionMessage(ex); + try { + if (ex.lineNumber) { + exStr += " on line number " + ex.lineNumber; + } + if (ex.fileName) { + exStr += " in file " + getUrlFileName(ex.fileName); + } + } catch (localEx) { + logLog.warn("Unable to obtain file and line information for error"); + } + if (showStackTraces && ex.stack) { + exStr += newLine + "Stack trace:" + newLine + ex.stack; + } + return exStr; + } + return null; + } + + function bool(obj) { + return Boolean(obj); + } + + function trim(str) { + return str.replace(/^\s+/, "").replace(/\s+$/, ""); + } + + function splitIntoLines(text) { + // Ensure all line breaks are \n only + var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); + return text2.split("\n"); + } + + var urlEncode = (typeof window.encodeURIComponent != "undefined") ? + function(str) { + return encodeURIComponent(str); + }: + function(str) { + return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D"); + }; + + var urlDecode = (typeof window.decodeURIComponent != "undefined") ? + function(str) { + return decodeURIComponent(str); + }: + function(str) { + return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "="); + }; + + function array_remove(arr, val) { + var index = -1; + for (var i = 0, len = arr.length; i < len; i++) { + if (arr[i] === val) { + index = i; + break; + } + } + if (index >= 0) { + arr.splice(index, 1); + return true; + } else { + return false; + } + } + + function array_contains(arr, val) { + for(var i = 0, len = arr.length; i < len; i++) { + if (arr[i] == val) { + return true; + } + } + return false; + } + + function extractBooleanFromParam(param, defaultValue) { + if (isUndefined(param)) { + return defaultValue; + } else { + return bool(param); + } + } + + function extractStringFromParam(param, defaultValue) { + if (isUndefined(param)) { + return defaultValue; + } else { + return String(param); + } + } + + function extractIntFromParam(param, defaultValue) { + if (isUndefined(param)) { + return defaultValue; + } else { + try { + var value = parseInt(param, 10); + return isNaN(value) ? defaultValue : value; + } catch (ex) { + logLog.warn("Invalid int param " + param, ex); + return defaultValue; + } + } + } + + function extractFunctionFromParam(param, defaultValue) { + if (typeof param == "function") { + return param; + } else { + return defaultValue; + } + } + + function isError(err) { + return (err instanceof Error); + } + + if (!Function.prototype.apply){ + Function.prototype.apply = function(obj, args) { + var methodName = "__apply__"; + if (typeof obj[methodName] != "undefined") { + methodName += String(Math.random()).substr(2); + } + obj[methodName] = this; + + var argsStrings = []; + for (var i = 0, len = args.length; i < len; i++) { + argsStrings[i] = "args[" + i + "]"; + } + var script = "obj." + methodName + "(" + argsStrings.join(",") + ")"; + var returnValue = eval(script); + delete obj[methodName]; + return returnValue; + }; + } + + if (!Function.prototype.call){ + Function.prototype.call = function(obj) { + var args = []; + for (var i = 1, len = arguments.length; i < len; i++) { + args[i - 1] = arguments[i]; + } + return this.apply(obj, args); + }; + } + + function getListenersPropertyName(eventName) { + return "__log4javascript_listeners__" + eventName; + } + + function addEvent(node, eventName, listener, useCapture, win) { + win = win ? win : window; + if (node.addEventListener) { + node.addEventListener(eventName, listener, useCapture); + } else if (node.attachEvent) { + node.attachEvent("on" + eventName, listener); + } else { + var propertyName = getListenersPropertyName(eventName); + if (!node[propertyName]) { + node[propertyName] = []; + // Set event handler + node["on" + eventName] = function(evt) { + evt = getEvent(evt, win); + var listenersPropertyName = getListenersPropertyName(eventName); + + // Clone the array of listeners to leave the original untouched + var listeners = this[listenersPropertyName].concat([]); + var currentListener; + + // Call each listener in turn + while ((currentListener = listeners.shift())) { + currentListener.call(this, evt); + } + }; + } + node[propertyName].push(listener); + } + } + + function removeEvent(node, eventName, listener, useCapture) { + if (node.removeEventListener) { + node.removeEventListener(eventName, listener, useCapture); + } else if (node.detachEvent) { + node.detachEvent("on" + eventName, listener); + } else { + var propertyName = getListenersPropertyName(eventName); + if (node[propertyName]) { + array_remove(node[propertyName], listener); + } + } + } + + function getEvent(evt, win) { + win = win ? win : window; + return evt ? evt : win.event; + } + + function stopEventPropagation(evt) { + if (evt.stopPropagation) { + evt.stopPropagation(); + } else if (typeof evt.cancelBubble != "undefined") { + evt.cancelBubble = true; + } + evt.returnValue = false; + } + + /* ---------------------------------------------------------------------- */ + // Simple logging for log4javascript itself + + var logLog = { + quietMode: false, + + debugMessages: [], + + setQuietMode: function(quietMode) { + this.quietMode = bool(quietMode); + }, + + numberOfErrors: 0, + + alertAllErrors: false, + + setAlertAllErrors: function(alertAllErrors) { + this.alertAllErrors = alertAllErrors; + }, + + debug: function(message) { + this.debugMessages.push(message); + }, + + displayDebug: function() { + alert(this.debugMessages.join(newLine)); + }, + + warn: function(message, exception) { + }, + + error: function(message, exception) { + if (++this.numberOfErrors == 1 || this.alertAllErrors) { + if (!this.quietMode) { + var alertMessage = "log4javascript error: " + message; + if (exception) { + alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception); + } + alert(alertMessage); + } + } + } + }; + log4javascript.logLog = logLog; + + log4javascript.setEventTypes(["load", "error"]); + + function handleError(message, exception) { + logLog.error(message, exception); + log4javascript.dispatchEvent("error", { "message": message, "exception": exception }); + } + + log4javascript.handleError = handleError; + + /* ---------------------------------------------------------------------- */ + + var enabled = !((typeof log4javascript_disabled != "undefined") && + log4javascript_disabled); + + log4javascript.setEnabled = function(enable) { + enabled = bool(enable); + }; + + log4javascript.isEnabled = function() { + return enabled; + }; + + var useTimeStampsInMilliseconds = true; + + log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) { + useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds); + }; + + log4javascript.isTimeStampsInMilliseconds = function() { + return useTimeStampsInMilliseconds; + }; + + + // This evaluates the given expression in the current scope, thus allowing + // scripts to access private variables. Particularly useful for testing + log4javascript.evalInScope = function(expr) { + return eval(expr); + }; + + var showStackTraces = false; + + log4javascript.setShowStackTraces = function(show) { + showStackTraces = bool(show); + }; + + /* ---------------------------------------------------------------------- */ + // Levels + + var Level = function(level, name) { + this.level = level; + this.name = name; + }; + + Level.prototype = { + toString: function() { + return this.name; + }, + equals: function(level) { + return this.level == level.level; + }, + isGreaterOrEqual: function(level) { + return this.level >= level.level; + } + }; + + Level.ALL = new Level(Number.MIN_VALUE, "ALL"); + Level.TRACE = new Level(10000, "TRACE"); + Level.DEBUG = new Level(20000, "DEBUG"); + Level.INFO = new Level(30000, "INFO"); + Level.WARN = new Level(40000, "WARN"); + Level.ERROR = new Level(50000, "ERROR"); + Level.FATAL = new Level(60000, "FATAL"); + Level.OFF = new Level(Number.MAX_VALUE, "OFF"); + + log4javascript.Level = Level; + + /* ---------------------------------------------------------------------- */ + // Timers + + function Timer(name, level) { + this.name = name; + this.level = isUndefined(level) ? Level.INFO : level; + this.start = new Date(); + } + + Timer.prototype.getElapsedTime = function() { + return new Date().getTime() - this.start.getTime(); + }; + + /* ---------------------------------------------------------------------- */ + // Loggers + + var anonymousLoggerName = "[anonymous]"; + var defaultLoggerName = "[default]"; + var nullLoggerName = "[null]"; + var rootLoggerName = "root"; + + function Logger(name) { + this.name = name; + this.parent = null; + this.children = []; + + var appenders = []; + var loggerLevel = null; + var isRoot = (this.name === rootLoggerName); + var isNull = (this.name === nullLoggerName); + + var appenderCache = null; + var appenderCacheInvalidated = false; + + this.addChild = function(childLogger) { + this.children.push(childLogger); + childLogger.parent = this; + childLogger.invalidateAppenderCache(); + }; + + // Additivity + var additive = true; + this.getAdditivity = function() { + return additive; + }; + + this.setAdditivity = function(additivity) { + var valueChanged = (additive != additivity); + additive = additivity; + if (valueChanged) { + this.invalidateAppenderCache(); + } + }; + + // Create methods that use the appenders variable in this scope + this.addAppender = function(appender) { + if (isNull) { + handleError("Logger.addAppender: you may not add an appender to the null logger"); + } else { + if (appender instanceof log4javascript.Appender) { + if (!array_contains(appenders, appender)) { + appenders.push(appender); + appender.setAddedToLogger(this); + this.invalidateAppenderCache(); + } + } else { + handleError("Logger.addAppender: appender supplied ('" + + toStr(appender) + "') is not a subclass of Appender"); + } + } + }; + + this.removeAppender = function(appender) { + array_remove(appenders, appender); + appender.setRemovedFromLogger(this); + this.invalidateAppenderCache(); + }; + + this.removeAllAppenders = function() { + var appenderCount = appenders.length; + if (appenderCount > 0) { + for (var i = 0; i < appenderCount; i++) { + appenders[i].setRemovedFromLogger(this); + } + appenders.length = 0; + this.invalidateAppenderCache(); + } + }; + + this.getEffectiveAppenders = function() { + if (appenderCache === null || appenderCacheInvalidated) { + // Build appender cache + var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ? + [] : this.parent.getEffectiveAppenders(); + appenderCache = parentEffectiveAppenders.concat(appenders); + appenderCacheInvalidated = false; + } + return appenderCache; + }; + + this.invalidateAppenderCache = function() { + appenderCacheInvalidated = true; + for (var i = 0, len = this.children.length; i < len; i++) { + this.children[i].invalidateAppenderCache(); + } + }; + + this.log = function(level, params) { + if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) { + // Check whether last param is an exception + var exception; + var finalParamIndex = params.length - 1; + var lastParam = params[finalParamIndex]; + if (params.length > 1 && isError(lastParam)) { + exception = lastParam; + finalParamIndex--; + } + + // Construct genuine array for the params + var messages = []; + for (var i = 0; i <= finalParamIndex; i++) { + messages[i] = params[i]; + } + + var loggingEvent = new LoggingEvent( + this, new Date(), level, messages, exception); + + this.callAppenders(loggingEvent); + } + }; + + this.callAppenders = function(loggingEvent) { + var effectiveAppenders = this.getEffectiveAppenders(); + for (var i = 0, len = effectiveAppenders.length; i < len; i++) { + effectiveAppenders[i].doAppend(loggingEvent); + } + }; + + this.setLevel = function(level) { + // Having a level of null on the root logger would be very bad. + if (isRoot && level === null) { + handleError("Logger.setLevel: you cannot set the level of the root logger to null"); + } else if (level instanceof Level) { + loggerLevel = level; + } else { + handleError("Logger.setLevel: level supplied to logger " + + this.name + " is not an instance of log4javascript.Level"); + } + }; + + this.getLevel = function() { + return loggerLevel; + }; + + this.getEffectiveLevel = function() { + for (var logger = this; logger !== null; logger = logger.parent) { + var level = logger.getLevel(); + if (level !== null) { + return level; + } + } + }; + + this.group = function(name, initiallyExpanded) { + if (enabled) { + var effectiveAppenders = this.getEffectiveAppenders(); + for (var i = 0, len = effectiveAppenders.length; i < len; i++) { + effectiveAppenders[i].group(name, initiallyExpanded); + } + } + }; + + this.groupEnd = function() { + if (enabled) { + var effectiveAppenders = this.getEffectiveAppenders(); + for (var i = 0, len = effectiveAppenders.length; i < len; i++) { + effectiveAppenders[i].groupEnd(); + } + } + }; + + var timers = {}; + + this.time = function(name, level) { + if (enabled) { + if (isUndefined(name)) { + handleError("Logger.time: a name for the timer must be supplied"); + } else if (level && !(level instanceof Level)) { + handleError("Logger.time: level supplied to timer " + + name + " is not an instance of log4javascript.Level"); + } else { + timers[name] = new Timer(name, level); + } + } + }; + + this.timeEnd = function(name) { + if (enabled) { + if (isUndefined(name)) { + handleError("Logger.timeEnd: a name for the timer must be supplied"); + } else if (timers[name]) { + var timer = timers[name]; + var milliseconds = timer.getElapsedTime(); + this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]); + delete timers[name]; + } else { + logLog.warn("Logger.timeEnd: no timer found with name " + name); + } + } + }; + + this.assert = function(expr) { + if (enabled && !expr) { + var args = []; + for (var i = 1, len = arguments.length; i < len; i++) { + args.push(arguments[i]); + } + args = (args.length > 0) ? args : ["Assertion Failure"]; + args.push(newLine); + args.push(expr); + this.log(Level.ERROR, args); + } + }; + + this.toString = function() { + return "Logger[" + this.name + "]"; + }; + } + + Logger.prototype = { + trace: function() { + this.log(Level.TRACE, arguments); + }, + + debug: function() { + this.log(Level.DEBUG, arguments); + }, + + info: function() { + this.log(Level.INFO, arguments); + }, + + warn: function() { + this.log(Level.WARN, arguments); + }, + + error: function() { + this.log(Level.ERROR, arguments); + }, + + fatal: function() { + this.log(Level.FATAL, arguments); + }, + + isEnabledFor: function(level) { + return level.isGreaterOrEqual(this.getEffectiveLevel()); + }, + + isTraceEnabled: function() { + return this.isEnabledFor(Level.TRACE); + }, + + isDebugEnabled: function() { + return this.isEnabledFor(Level.DEBUG); + }, + + isInfoEnabled: function() { + return this.isEnabledFor(Level.INFO); + }, + + isWarnEnabled: function() { + return this.isEnabledFor(Level.WARN); + }, + + isErrorEnabled: function() { + return this.isEnabledFor(Level.ERROR); + }, + + isFatalEnabled: function() { + return this.isEnabledFor(Level.FATAL); + } + }; + + Logger.prototype.trace.isEntryPoint = true; + Logger.prototype.debug.isEntryPoint = true; + Logger.prototype.info.isEntryPoint = true; + Logger.prototype.warn.isEntryPoint = true; + Logger.prototype.error.isEntryPoint = true; + Logger.prototype.fatal.isEntryPoint = true; + + /* ---------------------------------------------------------------------- */ + // Logger access methods + + // Hashtable of loggers keyed by logger name + var loggers = {}; + var loggerNames = []; + + var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG; + var rootLogger = new Logger(rootLoggerName); + rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL); + + log4javascript.getRootLogger = function() { + return rootLogger; + }; + + log4javascript.getLogger = function(loggerName) { + // Use default logger if loggerName is not specified or invalid + if (!(typeof loggerName == "string")) { + loggerName = anonymousLoggerName; + logLog.warn("log4javascript.getLogger: non-string logger name " + + toStr(loggerName) + " supplied, returning anonymous logger"); + } + + // Do not allow retrieval of the root logger by name + if (loggerName == rootLoggerName) { + handleError("log4javascript.getLogger: root logger may not be obtained by name"); + } + + // Create the logger for this name if it doesn't already exist + if (!loggers[loggerName]) { + var logger = new Logger(loggerName); + loggers[loggerName] = logger; + loggerNames.push(loggerName); + + // Set up parent logger, if it doesn't exist + var lastDotIndex = loggerName.lastIndexOf("."); + var parentLogger; + if (lastDotIndex > -1) { + var parentLoggerName = loggerName.substring(0, lastDotIndex); + parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc. + } else { + parentLogger = rootLogger; + } + parentLogger.addChild(logger); + } + return loggers[loggerName]; + }; + + var defaultLogger = null; + log4javascript.getDefaultLogger = function() { + if (!defaultLogger) { + defaultLogger = log4javascript.getLogger(defaultLoggerName); + var a = new log4javascript.PopUpAppender(); + defaultLogger.addAppender(a); + } + return defaultLogger; + }; + + var nullLogger = null; + log4javascript.getNullLogger = function() { + if (!nullLogger) { + nullLogger = new Logger(nullLoggerName); + nullLogger.setLevel(Level.OFF); + } + return nullLogger; + }; + + // Destroys all loggers + log4javascript.resetConfiguration = function() { + rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL); + loggers = {}; + }; + + /* ---------------------------------------------------------------------- */ + // Logging events + + var LoggingEvent = function(logger, timeStamp, level, messages, + exception) { + this.logger = logger; + this.timeStamp = timeStamp; + this.timeStampInMilliseconds = timeStamp.getTime(); + this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000); + this.milliseconds = this.timeStamp.getMilliseconds(); + this.level = level; + this.messages = messages; + this.exception = exception; + }; + + LoggingEvent.prototype = { + getThrowableStrRep: function() { + return this.exception ? + getExceptionStringRep(this.exception) : ""; + }, + getCombinedMessages: function() { + return (this.messages.length == 1) ? this.messages[0] : + this.messages.join(newLine); + }, + toString: function() { + return "LoggingEvent[" + this.level + "]"; + } + }; + + log4javascript.LoggingEvent = LoggingEvent; + + /* ---------------------------------------------------------------------- */ + // Layout prototype + + var Layout = function() { + }; + + Layout.prototype = { + defaults: { + loggerKey: "logger", + timeStampKey: "timestamp", + millisecondsKey: "milliseconds", + levelKey: "level", + messageKey: "message", + exceptionKey: "exception", + urlKey: "url" + }, + loggerKey: "logger", + timeStampKey: "timestamp", + millisecondsKey: "milliseconds", + levelKey: "level", + messageKey: "message", + exceptionKey: "exception", + urlKey: "url", + batchHeader: "", + batchFooter: "", + batchSeparator: "", + returnsPostData: false, + overrideTimeStampsSetting: false, + useTimeStampsInMilliseconds: null, + + format: function() { + handleError("Layout.format: layout supplied has no format() method"); + }, + + ignoresThrowable: function() { + handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method"); + }, + + getContentType: function() { + return "text/plain"; + }, + + allowBatching: function() { + return true; + }, + + setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) { + this.overrideTimeStampsSetting = true; + this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds); + }, + + isTimeStampsInMilliseconds: function() { + return this.overrideTimeStampsSetting ? + this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds; + }, + + getTimeStampValue: function(loggingEvent) { + return this.isTimeStampsInMilliseconds() ? + loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds; + }, + + getDataValues: function(loggingEvent, combineMessages) { + var dataValues = [ + [this.loggerKey, loggingEvent.logger.name], + [this.timeStampKey, this.getTimeStampValue(loggingEvent)], + [this.levelKey, loggingEvent.level.name], + [this.urlKey, window.location.href], + [this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages] + ]; + if (!this.isTimeStampsInMilliseconds()) { + dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]); + } + if (loggingEvent.exception) { + dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]); + } + if (this.hasCustomFields()) { + for (var i = 0, len = this.customFields.length; i < len; i++) { + var val = this.customFields[i].value; + + // Check if the value is a function. If so, execute it, passing it the + // current layout and the logging event + if (typeof val === "function") { + val = val(this, loggingEvent); + } + dataValues.push([this.customFields[i].name, val]); + } + } + return dataValues; + }, + + setKeys: function(loggerKey, timeStampKey, levelKey, messageKey, + exceptionKey, urlKey, millisecondsKey) { + this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey); + this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey); + this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey); + this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey); + this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey); + this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey); + this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey); + }, + + setCustomField: function(name, value) { + var fieldUpdated = false; + for (var i = 0, len = this.customFields.length; i < len; i++) { + if (this.customFields[i].name === name) { + this.customFields[i].value = value; + fieldUpdated = true; + } + } + if (!fieldUpdated) { + this.customFields.push({"name": name, "value": value}); + } + }, + + hasCustomFields: function() { + return (this.customFields.length > 0); + }, + + toString: function() { + handleError("Layout.toString: all layouts must override this method"); + } + }; + + log4javascript.Layout = Layout; + + /* ---------------------------------------------------------------------- */ + // Appender prototype + + var Appender = function() {}; + + Appender.prototype = new EventSupport(); + + Appender.prototype.layout = new PatternLayout(); + Appender.prototype.threshold = Level.ALL; + Appender.prototype.loggers = []; + + // Performs threshold checks before delegating actual logging to the + // subclass's specific append method. + Appender.prototype.doAppend = function(loggingEvent) { + if (enabled && loggingEvent.level.level >= this.threshold.level) { + this.append(loggingEvent); + } + }; + + Appender.prototype.append = function(loggingEvent) {}; + + Appender.prototype.setLayout = function(layout) { + if (layout instanceof Layout) { + this.layout = layout; + } else { + handleError("Appender.setLayout: layout supplied to " + + this.toString() + " is not a subclass of Layout"); + } + }; + + Appender.prototype.getLayout = function() { + return this.layout; + }; + + Appender.prototype.setThreshold = function(threshold) { + if (threshold instanceof Level) { + this.threshold = threshold; + } else { + handleError("Appender.setThreshold: threshold supplied to " + + this.toString() + " is not a subclass of Level"); + } + }; + + Appender.prototype.getThreshold = function() { + return this.threshold; + }; + + Appender.prototype.setAddedToLogger = function(logger) { + this.loggers.push(logger); + }; + + Appender.prototype.setRemovedFromLogger = function(logger) { + array_remove(this.loggers, logger); + }; + + Appender.prototype.group = emptyFunction; + Appender.prototype.groupEnd = emptyFunction; + + Appender.prototype.toString = function() { + handleError("Appender.toString: all appenders must override this method"); + }; + + log4javascript.Appender = Appender; + + /* ---------------------------------------------------------------------- */ + // SimpleLayout + + function SimpleLayout() { + this.customFields = []; + } + + SimpleLayout.prototype = new Layout(); + + SimpleLayout.prototype.format = function(loggingEvent) { + return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages(); + }; + + SimpleLayout.prototype.ignoresThrowable = function() { + return true; + }; + + SimpleLayout.prototype.toString = function() { + return "SimpleLayout"; + }; + + log4javascript.SimpleLayout = SimpleLayout; + /* ----------------------------------------------------------------------- */ + // NullLayout + + function NullLayout() { + this.customFields = []; + } + + NullLayout.prototype = new Layout(); + + NullLayout.prototype.format = function(loggingEvent) { + return loggingEvent.messages; + }; + + NullLayout.prototype.ignoresThrowable = function() { + return true; + }; + + NullLayout.prototype.toString = function() { + return "NullLayout"; + }; + + log4javascript.NullLayout = NullLayout; +/* ---------------------------------------------------------------------- */ + // XmlLayout + + function XmlLayout(combineMessages) { + this.combineMessages = extractBooleanFromParam(combineMessages, true); + this.customFields = []; + } + + XmlLayout.prototype = new Layout(); + + XmlLayout.prototype.isCombinedMessages = function() { + return this.combineMessages; + }; + + XmlLayout.prototype.getContentType = function() { + return "text/xml"; + }; + + XmlLayout.prototype.escapeCdata = function(str) { + return str.replace(/\]\]>/, "]]>]]>"; + } + + var str = "" + newLine; + if (this.combineMessages) { + str += formatMessage(loggingEvent.getCombinedMessages()); + } else { + str += "" + newLine; + for (i = 0, len = loggingEvent.messages.length; i < len; i++) { + str += formatMessage(loggingEvent.messages[i]) + newLine; + } + str += "" + newLine; + } + if (this.hasCustomFields()) { + for (i = 0, len = this.customFields.length; i < len; i++) { + str += "" + newLine; + } + } + if (loggingEvent.exception) { + str += "" + newLine; + } + str += "" + newLine + newLine; + return str; + }; + + XmlLayout.prototype.ignoresThrowable = function() { + return false; + }; + + XmlLayout.prototype.toString = function() { + return "XmlLayout"; + }; + + log4javascript.XmlLayout = XmlLayout; + /* ---------------------------------------------------------------------- */ + // JsonLayout related + + function escapeNewLines(str) { + return str.replace(/\r\n|\r|\n/g, "\\r\\n"); + } + + function JsonLayout(readable, combineMessages) { + this.readable = extractBooleanFromParam(readable, false); + this.combineMessages = extractBooleanFromParam(combineMessages, true); + this.batchHeader = this.readable ? "[" + newLine : "["; + this.batchFooter = this.readable ? "]" + newLine : "]"; + this.batchSeparator = this.readable ? "," + newLine : ","; + this.setKeys(); + this.colon = this.readable ? ": " : ":"; + this.tab = this.readable ? "\t" : ""; + this.lineBreak = this.readable ? newLine : ""; + this.customFields = []; + } + + /* ---------------------------------------------------------------------- */ + // JsonLayout + + JsonLayout.prototype = new Layout(); + + JsonLayout.prototype.isReadable = function() { + return this.readable; + }; + + JsonLayout.prototype.isCombinedMessages = function() { + return this.combineMessages; + }; + + JsonLayout.prototype.format = function(loggingEvent) { + var layout = this; + var dataValues = this.getDataValues(loggingEvent, this.combineMessages); + var str = "{" + this.lineBreak; + var i, len; + + function formatValue(val, prefix, expand) { + // Check the type of the data value to decide whether quotation marks + // or expansion are required + var formattedValue; + var valType = typeof val; + if (val instanceof Date) { + formattedValue = String(val.getTime()); + } else if (expand && (val instanceof Array)) { + formattedValue = "[" + layout.lineBreak; + for (var i = 0, len = val.length; i < len; i++) { + var childPrefix = prefix + layout.tab; + formattedValue += childPrefix + formatValue(val[i], childPrefix, false); + if (i < val.length - 1) { + formattedValue += ","; + } + formattedValue += layout.lineBreak; + } + formattedValue += prefix + "]"; + } else if (valType !== "number" && valType !== "boolean") { + formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\""; + } else { + formattedValue = val; + } + return formattedValue; + } + + for (i = 0, len = dataValues.length - 1; i <= len; i++) { + str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true); + if (i < len) { + str += ","; + } + str += this.lineBreak; + } + + str += "}" + this.lineBreak; + return str; + }; + + JsonLayout.prototype.ignoresThrowable = function() { + return false; + }; + + JsonLayout.prototype.toString = function() { + return "JsonLayout"; + }; + + JsonLayout.prototype.getContentType = function() { + return "application/json"; + }; + + log4javascript.JsonLayout = JsonLayout; + /* ---------------------------------------------------------------------- */ + // HttpPostDataLayout + + function HttpPostDataLayout() { + this.setKeys(); + this.customFields = []; + this.returnsPostData = true; + } + + HttpPostDataLayout.prototype = new Layout(); + + // Disable batching + HttpPostDataLayout.prototype.allowBatching = function() { + return false; + }; + + HttpPostDataLayout.prototype.format = function(loggingEvent) { + var dataValues = this.getDataValues(loggingEvent); + var queryBits = []; + for (var i = 0, len = dataValues.length; i < len; i++) { + var val = (dataValues[i][1] instanceof Date) ? + String(dataValues[i][1].getTime()) : dataValues[i][1]; + queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val)); + } + return queryBits.join("&"); + }; + + HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) { + return false; + }; + + HttpPostDataLayout.prototype.toString = function() { + return "HttpPostDataLayout"; + }; + + log4javascript.HttpPostDataLayout = HttpPostDataLayout; + /* ---------------------------------------------------------------------- */ + // formatObjectExpansion + + function formatObjectExpansion(obj, depth, indentation) { + var objectsExpanded = []; + + function doFormat(obj, depth, indentation) { + var i, j, len, childDepth, childIndentation, childLines, expansion, + childExpansion; + + if (!indentation) { + indentation = ""; + } + + function formatString(text) { + var lines = splitIntoLines(text); + for (var j = 1, jLen = lines.length; j < jLen; j++) { + lines[j] = indentation + lines[j]; + } + return lines.join(newLine); + } + + if (obj === null) { + return "null"; + } else if (typeof obj == "undefined") { + return "undefined"; + } else if (typeof obj == "string") { + return formatString(obj); + } else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) { + try { + expansion = toStr(obj); + } catch (ex) { + expansion = "Error formatting property. Details: " + getExceptionStringRep(ex); + } + return expansion + " [already expanded]"; + } else if ((obj instanceof Array) && depth > 0) { + objectsExpanded.push(obj); + expansion = "[" + newLine; + childDepth = depth - 1; + childIndentation = indentation + " "; + childLines = []; + for (i = 0, len = obj.length; i < len; i++) { + try { + childExpansion = doFormat(obj[i], childDepth, childIndentation); + childLines.push(childIndentation + childExpansion); + } catch (ex) { + childLines.push(childIndentation + "Error formatting array member. Details: " + + getExceptionStringRep(ex) + ""); + } + } + expansion += childLines.join("," + newLine) + newLine + indentation + "]"; + return expansion; + } else if (Object.prototype.toString.call(obj) == "[object Date]") { + return obj.toString(); + } else if (typeof obj == "object" && depth > 0) { + objectsExpanded.push(obj); + expansion = "{" + newLine; + childDepth = depth - 1; + childIndentation = indentation + " "; + childLines = []; + for (i in obj) { + try { + childExpansion = doFormat(obj[i], childDepth, childIndentation); + childLines.push(childIndentation + i + ": " + childExpansion); + } catch (ex) { + childLines.push(childIndentation + i + ": Error formatting property. Details: " + + getExceptionStringRep(ex)); + } + } + expansion += childLines.join("," + newLine) + newLine + indentation + "}"; + return expansion; + } else { + return formatString(toStr(obj)); + } + } + return doFormat(obj, depth, indentation); + } + /* ---------------------------------------------------------------------- */ + // Date-related stuff + + var SimpleDateFormat; + + (function() { + var 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']+)/; + var monthNames = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"]; + var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5; + var types = { + G : TEXT2, + y : YEAR, + M : MONTH, + w : NUMBER, + W : NUMBER, + D : NUMBER, + d : NUMBER, + F : NUMBER, + E : TEXT3, + a : TEXT2, + H : NUMBER, + k : NUMBER, + K : NUMBER, + h : NUMBER, + m : NUMBER, + s : NUMBER, + S : NUMBER, + Z : TIMEZONE + }; + var ONE_DAY = 24 * 60 * 60 * 1000; + var ONE_WEEK = 7 * ONE_DAY; + var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1; + + var newDateAtMidnight = function(year, month, day) { + var d = new Date(year, month, day, 0, 0, 0); + d.setMilliseconds(0); + return d; + }; + + Date.prototype.getDifference = function(date) { + return this.getTime() - date.getTime(); + }; + + Date.prototype.isBefore = function(d) { + return this.getTime() < d.getTime(); + }; + + Date.prototype.getUTCTime = function() { + return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(), + this.getSeconds(), this.getMilliseconds()); + }; + + Date.prototype.getTimeSince = function(d) { + return this.getUTCTime() - d.getUTCTime(); + }; + + Date.prototype.getPreviousSunday = function() { + // Using midday avoids any possibility of DST messing things up + var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0); + var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY); + return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(), + previousSunday.getDate()); + }; + + Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) { + if (isUndefined(this.minimalDaysInFirstWeek)) { + minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK; + } + var previousSunday = this.getPreviousSunday(); + var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1); + var numberOfSundays = previousSunday.isBefore(startOfYear) ? + 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK); + var numberOfDaysInFirstWeek = 7 - startOfYear.getDay(); + var weekInYear = numberOfSundays; + if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) { + weekInYear--; + } + return weekInYear; + }; + + Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) { + if (isUndefined(this.minimalDaysInFirstWeek)) { + minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK; + } + var previousSunday = this.getPreviousSunday(); + var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1); + var numberOfSundays = previousSunday.isBefore(startOfMonth) ? + 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK); + var numberOfDaysInFirstWeek = 7 - startOfMonth.getDay(); + var weekInMonth = numberOfSundays; + if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) { + weekInMonth++; + } + return weekInMonth; + }; + + Date.prototype.getDayInYear = function() { + var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1); + return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY); + }; + + /* ------------------------------------------------------------------ */ + + SimpleDateFormat = function(formatString) { + this.formatString = formatString; + }; + + /** + * Sets the minimum number of days in a week in order for that week to + * be considered as belonging to a particular month or year + */ + SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) { + this.minimalDaysInFirstWeek = days; + }; + + SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() { + return isUndefined(this.minimalDaysInFirstWeek) ? + DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek; + }; + + var padWithZeroes = function(str, len) { + while (str.length < len) { + str = "0" + str; + } + return str; + }; + + var formatText = function(data, numberOfLetters, minLength) { + return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters)); + }; + + var formatNumber = function(data, numberOfLetters) { + var dataString = "" + data; + // Pad with 0s as necessary + return padWithZeroes(dataString, numberOfLetters); + }; + + SimpleDateFormat.prototype.format = function(date) { + var formattedString = ""; + var result; + var searchString = this.formatString; + while ((result = regex.exec(searchString))) { + var quotedString = result[1]; + var patternLetters = result[2]; + var otherLetters = result[3]; + var otherCharacters = result[4]; + + // If the pattern matched is quoted string, output the text between the quotes + if (quotedString) { + if (quotedString == "''") { + formattedString += "'"; + } else { + formattedString += quotedString.substring(1, quotedString.length - 1); + } + } else if (otherLetters) { + // Swallow non-pattern letters by doing nothing here + } else if (otherCharacters) { + // Simply output other characters + formattedString += otherCharacters; + } else if (patternLetters) { + // Replace pattern letters + var patternLetter = patternLetters.charAt(0); + var numberOfLetters = patternLetters.length; + var rawData = ""; + switch(patternLetter) { + case "G": + rawData = "AD"; + break; + case "y": + rawData = date.getFullYear(); + break; + case "M": + rawData = date.getMonth(); + break; + case "w": + rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek()); + break; + case "W": + rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek()); + break; + case "D": + rawData = date.getDayInYear(); + break; + case "d": + rawData = date.getDate(); + break; + case "F": + rawData = 1 + Math.floor((date.getDate() - 1) / 7); + break; + case "E": + rawData = dayNames[date.getDay()]; + break; + case "a": + rawData = (date.getHours() >= 12) ? "PM" : "AM"; + break; + case "H": + rawData = date.getHours(); + break; + case "k": + rawData = date.getHours() || 24; + break; + case "K": + rawData = date.getHours() % 12; + break; + case "h": + rawData = (date.getHours() % 12) || 12; + break; + case "m": + rawData = date.getMinutes(); + break; + case "s": + rawData = date.getSeconds(); + break; + case "S": + rawData = date.getMilliseconds(); + break; + case "Z": + rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time. + break; + } + // Format the raw data depending on the type + switch(types[patternLetter]) { + case TEXT2: + formattedString += formatText(rawData, numberOfLetters, 2); + break; + case TEXT3: + formattedString += formatText(rawData, numberOfLetters, 3); + break; + case NUMBER: + formattedString += formatNumber(rawData, numberOfLetters); + break; + case YEAR: + if (numberOfLetters <= 3) { + // Output a 2-digit year + var dataString = "" + rawData; + formattedString += dataString.substr(2, 2); + } else { + formattedString += formatNumber(rawData, numberOfLetters); + } + break; + case MONTH: + if (numberOfLetters >= 3) { + formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters); + } else { + // NB. Months returned by getMonth are zero-based + formattedString += formatNumber(rawData + 1, numberOfLetters); + } + break; + case TIMEZONE: + var isPositive = (rawData > 0); + // The following line looks like a mistake but isn't + // because of the way getTimezoneOffset measures. + var prefix = isPositive ? "-" : "+"; + var absData = Math.abs(rawData); + + // Hours + var hours = "" + Math.floor(absData / 60); + hours = padWithZeroes(hours, 2); + // Minutes + var minutes = "" + (absData % 60); + minutes = padWithZeroes(minutes, 2); + + formattedString += prefix + hours + minutes; + break; + } + } + searchString = searchString.substr(result.index + result[0].length); + } + return formattedString; + }; + })(); + + log4javascript.SimpleDateFormat = SimpleDateFormat; + + /* ---------------------------------------------------------------------- */ + // PatternLayout + + function PatternLayout(pattern) { + if (pattern) { + this.pattern = pattern; + } else { + this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN; + } + this.customFields = []; + } + + PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n"; + PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n"; + PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS"; + PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS"; + PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS"; + + PatternLayout.prototype = new Layout(); + + PatternLayout.prototype.format = function(loggingEvent) { + var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/; + var formattedString = ""; + var result; + var searchString = this.pattern; + + // Cannot use regex global flag since it doesn't work with exec in IE5 + while ((result = regex.exec(searchString))) { + var matchedString = result[0]; + var padding = result[1]; + var truncation = result[2]; + var conversionCharacter = result[3]; + var specifier = result[5]; + var text = result[6]; + + // Check if the pattern matched was just normal text + if (text) { + formattedString += "" + text; + } else { + // Create a raw replacement string based on the conversion + // character and specifier + var replacement = ""; + switch(conversionCharacter) { + case "a": // Array of messages + case "m": // Message + var depth = 0; + if (specifier) { + depth = parseInt(specifier, 10); + if (isNaN(depth)) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character '" + conversionCharacter + + "' - should be a number"); + depth = 0; + } + } + var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages; + for (var i = 0, len = messages.length; i < len; i++) { + if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) { + replacement += " "; + } + if (depth === 0) { + replacement += messages[i]; + } else { + replacement += formatObjectExpansion(messages[i], depth); + } + } + break; + case "c": // Logger name + var loggerName = loggingEvent.logger.name; + if (specifier) { + var precision = parseInt(specifier, 10); + var loggerNameBits = loggingEvent.logger.name.split("."); + if (precision >= loggerNameBits.length) { + replacement = loggerName; + } else { + replacement = loggerNameBits.slice(loggerNameBits.length - precision).join("."); + } + } else { + replacement = loggerName; + } + break; + case "d": // Date + var dateFormat = PatternLayout.ISO8601_DATEFORMAT; + if (specifier) { + dateFormat = specifier; + // Pick up special cases + if (dateFormat == "ISO8601") { + dateFormat = PatternLayout.ISO8601_DATEFORMAT; + } else if (dateFormat == "ABSOLUTE") { + dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT; + } else if (dateFormat == "DATE") { + dateFormat = PatternLayout.DATETIME_DATEFORMAT; + } + } + // Format the date + replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp); + break; + case "f": // Custom field + if (this.hasCustomFields()) { + var fieldIndex = 0; + if (specifier) { + fieldIndex = parseInt(specifier, 10); + if (isNaN(fieldIndex)) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character 'f' - should be a number"); + } else if (fieldIndex === 0) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character 'f' - must be greater than zero"); + } else if (fieldIndex > this.customFields.length) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character 'f' - there aren't that many custom fields"); + } else { + fieldIndex = fieldIndex - 1; + } + } + var val = this.customFields[fieldIndex].value; + if (typeof val == "function") { + val = val(this, loggingEvent); + } + replacement = val; + } + break; + case "n": // New line + replacement = newLine; + break; + case "p": // Level + replacement = loggingEvent.level.name; + break; + case "r": // Milliseconds since log4javascript startup + replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate); + break; + case "%": // Literal % sign + replacement = "%"; + break; + default: + replacement = matchedString; + break; + } + // Format the replacement according to any padding or + // truncation specified + var l; + + // First, truncation + if (truncation) { + l = parseInt(truncation.substr(1), 10); + var strLen = replacement.length; + if (l < strLen) { + replacement = replacement.substring(strLen - l, strLen); + } + } + // Next, padding + if (padding) { + if (padding.charAt(0) == "-") { + l = parseInt(padding.substr(1), 10); + // Right pad with spaces + while (replacement.length < l) { + replacement += " "; + } + } else { + l = parseInt(padding, 10); + // Left pad with spaces + while (replacement.length < l) { + replacement = " " + replacement; + } + } + } + formattedString += replacement; + } + searchString = searchString.substr(result.index + result[0].length); + } + return formattedString; + }; + + PatternLayout.prototype.ignoresThrowable = function() { + return true; + }; + + PatternLayout.prototype.toString = function() { + return "PatternLayout"; + }; + + log4javascript.PatternLayout = PatternLayout; + /* ---------------------------------------------------------------------- */ + // AjaxAppender related + + var xmlHttpFactories = [ + function() { return new XMLHttpRequest(); }, + function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, + function() { return new ActiveXObject("Microsoft.XMLHTTP"); } + ]; + + var getXmlHttp = function(errorHandler) { + // This is only run the first time; the value of getXmlHttp gets + // replaced with the factory that succeeds on the first run + var xmlHttp = null, factory; + for (var i = 0, len = xmlHttpFactories.length; i < len; i++) { + factory = xmlHttpFactories[i]; + try { + xmlHttp = factory(); + getXmlHttp = factory; + return xmlHttp; + } catch (e) { + } + } + // If we're here, all factories have failed, so throw an error + if (errorHandler) { + errorHandler(); + } else { + handleError("getXmlHttp: unable to obtain XMLHttpRequest object"); + } + }; + + function isHttpRequestSuccessful(xmlHttp) { + return isUndefined(xmlHttp.status) || xmlHttp.status === 0 || + (xmlHttp.status >= 200 && xmlHttp.status < 300) || + xmlHttp.status == 1223 /* Fix for IE */; + } + + /* ---------------------------------------------------------------------- */ + // AjaxAppender + + function AjaxAppender(url) { + var appender = this; + var isSupported = true; + if (!url) { + handleError("AjaxAppender: URL must be specified in constructor"); + isSupported = false; + } + + var timed = this.defaults.timed; + var waitForResponse = this.defaults.waitForResponse; + var batchSize = this.defaults.batchSize; + var timerInterval = this.defaults.timerInterval; + var requestSuccessCallback = this.defaults.requestSuccessCallback; + var failCallback = this.defaults.failCallback; + var postVarName = this.defaults.postVarName; + var sendAllOnUnload = this.defaults.sendAllOnUnload; + var contentType = this.defaults.contentType; + var sessionId = null; + + var queuedLoggingEvents = []; + var queuedRequests = []; + var headers = []; + var sending = false; + var initialized = false; + + // Configuration methods. The function scope is used to prevent + // direct alteration to the appender configuration properties. + function checkCanConfigure(configOptionName) { + if (initialized) { + handleError("AjaxAppender: configuration option '" + + configOptionName + + "' may not be set after the appender has been initialized"); + return false; + } + return true; + } + + this.getSessionId = function() { return sessionId; }; + this.setSessionId = function(sessionIdParam) { + sessionId = extractStringFromParam(sessionIdParam, null); + this.layout.setCustomField("sessionid", sessionId); + }; + + this.setLayout = function(layoutParam) { + if (checkCanConfigure("layout")) { + this.layout = layoutParam; + // Set the session id as a custom field on the layout, if not already present + if (sessionId !== null) { + this.setSessionId(sessionId); + } + } + }; + + this.isTimed = function() { return timed; }; + this.setTimed = function(timedParam) { + if (checkCanConfigure("timed")) { + timed = bool(timedParam); + } + }; + + this.getTimerInterval = function() { return timerInterval; }; + this.setTimerInterval = function(timerIntervalParam) { + if (checkCanConfigure("timerInterval")) { + timerInterval = extractIntFromParam(timerIntervalParam, timerInterval); + } + }; + + this.isWaitForResponse = function() { return waitForResponse; }; + this.setWaitForResponse = function(waitForResponseParam) { + if (checkCanConfigure("waitForResponse")) { + waitForResponse = bool(waitForResponseParam); + } + }; + + this.getBatchSize = function() { return batchSize; }; + this.setBatchSize = function(batchSizeParam) { + if (checkCanConfigure("batchSize")) { + batchSize = extractIntFromParam(batchSizeParam, batchSize); + } + }; + + this.isSendAllOnUnload = function() { return sendAllOnUnload; }; + this.setSendAllOnUnload = function(sendAllOnUnloadParam) { + if (checkCanConfigure("sendAllOnUnload")) { + sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload); + } + }; + + this.setRequestSuccessCallback = function(requestSuccessCallbackParam) { + requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback); + }; + + this.setFailCallback = function(failCallbackParam) { + failCallback = extractFunctionFromParam(failCallbackParam, failCallback); + }; + + this.getPostVarName = function() { return postVarName; }; + this.setPostVarName = function(postVarNameParam) { + if (checkCanConfigure("postVarName")) { + postVarName = extractStringFromParam(postVarNameParam, postVarName); + } + }; + + this.getHeaders = function() { return headers; }; + this.addHeader = function(name, value) { + if (name.toLowerCase() == "content-type") { + contentType = value; + } else { + headers.push( { name: name, value: value } ); + } + }; + + // Internal functions + function sendAll() { + if (isSupported && enabled) { + sending = true; + var currentRequestBatch; + if (waitForResponse) { + // Send the first request then use this function as the callback once + // the response comes back + if (queuedRequests.length > 0) { + currentRequestBatch = queuedRequests.shift(); + sendRequest(preparePostData(currentRequestBatch), sendAll); + } else { + sending = false; + if (timed) { + scheduleSending(); + } + } + } else { + // Rattle off all the requests without waiting to see the response + while ((currentRequestBatch = queuedRequests.shift())) { + sendRequest(preparePostData(currentRequestBatch)); + } + sending = false; + if (timed) { + scheduleSending(); + } + } + } + } + + this.sendAll = sendAll; + + // Called when the window unloads. At this point we're past caring about + // waiting for responses or timers or incomplete batches - everything + // must go, now + function sendAllRemaining() { + var sendingAnything = false; + if (isSupported && enabled) { + // Create requests for everything left over, batched as normal + var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1; + var currentLoggingEvent; + var batchedLoggingEvents = []; + while ((currentLoggingEvent = queuedLoggingEvents.shift())) { + batchedLoggingEvents.push(currentLoggingEvent); + if (queuedLoggingEvents.length >= actualBatchSize) { + // Queue this batch of log entries + queuedRequests.push(batchedLoggingEvents); + batchedLoggingEvents = []; + } + } + // If there's a partially completed batch, add it + if (batchedLoggingEvents.length > 0) { + queuedRequests.push(batchedLoggingEvents); + } + sendingAnything = (queuedRequests.length > 0); + waitForResponse = false; + timed = false; + sendAll(); + } + return sendingAnything; + } + + this.sendAllRemaining = sendAllRemaining; + + function preparePostData(batchedLoggingEvents) { + // Format the logging events + var formattedMessages = []; + var currentLoggingEvent; + var postData = ""; + while ((currentLoggingEvent = batchedLoggingEvents.shift())) { + var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent); + if (appender.getLayout().ignoresThrowable()) { + currentFormattedMessage += currentLoggingEvent.getThrowableStrRep(); + } + formattedMessages.push(currentFormattedMessage); + } + // Create the post data string + if (batchedLoggingEvents.length == 1) { + postData = formattedMessages.join(""); + } else { + postData = appender.getLayout().batchHeader + + formattedMessages.join(appender.getLayout().batchSeparator) + + appender.getLayout().batchFooter; + } + if (contentType == appender.defaults.contentType) { + postData = appender.getLayout().returnsPostData ? postData : + urlEncode(postVarName) + "=" + urlEncode(postData); + // Add the layout name to the post data + if (postData.length > 0) { + postData += "&"; + } + postData += "layout=" + urlEncode(appender.getLayout().toString()); + } + return postData; + } + + function scheduleSending() { + window.setTimeout(sendAll, timerInterval); + } + + function xmlHttpErrorHandler() { + var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled"; + handleError(msg); + isSupported = false; + if (failCallback) { + failCallback(msg); + } + } + + function sendRequest(postData, successCallback) { + try { + var xmlHttp = getXmlHttp(xmlHttpErrorHandler); + if (isSupported) { + if (xmlHttp.overrideMimeType) { + xmlHttp.overrideMimeType(appender.getLayout().getContentType()); + } + xmlHttp.onreadystatechange = function() { + if (xmlHttp.readyState == 4) { + if (isHttpRequestSuccessful(xmlHttp)) { + if (requestSuccessCallback) { + requestSuccessCallback(xmlHttp); + } + if (successCallback) { + successCallback(xmlHttp); + } + } else { + var msg = "AjaxAppender.append: XMLHttpRequest request to URL " + + url + " returned status code " + xmlHttp.status; + handleError(msg); + if (failCallback) { + failCallback(msg); + } + } + xmlHttp.onreadystatechange = emptyFunction; + xmlHttp = null; + } + }; + xmlHttp.open("POST", url, true); + try { + for (var i = 0, header; header = headers[i++]; ) { + xmlHttp.setRequestHeader(header.name, header.value); + } + xmlHttp.setRequestHeader("Content-Type", contentType); + } catch (headerEx) { + var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" + + " does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled"; + handleError(msg); + isSupported = false; + if (failCallback) { + failCallback(msg); + } + return; + } + xmlHttp.send(postData); + } + } catch (ex) { + var errMsg = "AjaxAppender.append: error sending log message to " + url; + handleError(errMsg, ex); + isSupported = false; + if (failCallback) { + failCallback(errMsg + ". Details: " + getExceptionStringRep(ex)); + } + } + } + + this.append = function(loggingEvent) { + if (isSupported) { + if (!initialized) { + init(); + } + queuedLoggingEvents.push(loggingEvent); + var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1; + + if (queuedLoggingEvents.length >= actualBatchSize) { + var currentLoggingEvent; + var batchedLoggingEvents = []; + while ((currentLoggingEvent = queuedLoggingEvents.shift())) { + batchedLoggingEvents.push(currentLoggingEvent); + } + // Queue this batch of log entries + queuedRequests.push(batchedLoggingEvents); + + // If using a timer, the queue of requests will be processed by the + // timer function, so nothing needs to be done here. + if (!timed && (!waitForResponse || (waitForResponse && !sending))) { + sendAll(); + } + } + } + }; + + function init() { + initialized = true; + // Add unload event to send outstanding messages + if (sendAllOnUnload) { + var oldBeforeUnload = window.onbeforeunload; + window.onbeforeunload = function() { + if (oldBeforeUnload) { + oldBeforeUnload(); + } + if (sendAllRemaining()) { + return "Sending log messages"; + } + }; + } + // Start timer + if (timed) { + scheduleSending(); + } + } + } + + AjaxAppender.prototype = new Appender(); + + AjaxAppender.prototype.defaults = { + waitForResponse: false, + timed: false, + timerInterval: 1000, + batchSize: 1, + sendAllOnUnload: false, + requestSuccessCallback: null, + failCallback: null, + postVarName: "data", + contentType: "application/x-www-form-urlencoded" + }; + + AjaxAppender.prototype.layout = new HttpPostDataLayout(); + + AjaxAppender.prototype.toString = function() { + return "AjaxAppender"; + }; + + log4javascript.AjaxAppender = AjaxAppender; + + /* ---------------------------------------------------------------------- */ + // Main load + + log4javascript.setDocumentReady = function() { + pageLoaded = true; + log4javascript.dispatchEvent("load", {}); + }; + + if (window.addEventListener) { + window.addEventListener("load", log4javascript.setDocumentReady, false); + } else if (window.attachEvent) { + window.attachEvent("onload", log4javascript.setDocumentReady); + } else { + var oldOnload = window.onload; + if (typeof window.onload != "function") { + window.onload = log4javascript.setDocumentReady; + } else { + window.onload = function(evt) { + if (oldOnload) { + oldOnload(evt); + } + log4javascript.setDocumentReady(); + }; + } + } + + // Ensure that the log4javascript object is available in the window. This + // is necessary for log4javascript to be available in IE if loaded using + // Dojo's module system + window.log4javascript = log4javascript; + + return log4javascript; +})(); \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js new file mode 100644 index 0000000..a644e3b --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js @@ -0,0 +1,5879 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * log4javascript + * + * log4javascript is a logging framework for JavaScript based on log4j + * for Java. This file contains all core log4javascript code and is the only + * file required to use log4javascript, unless you require support for + * document.domain, in which case you will also need console.html, which must be + * stored in the same directory as the main log4javascript.js file. + * + * Author: Tim Down + * Version: 1.4.6 + * Edition: log4javascript + * Build date: 19 March 2013 + * Website: http://log4javascript.org + */ + +/* -------------------------------------------------------------------------- */ +// Array-related stuff + +// Next three methods are solely for IE5, which is missing them +if (!Array.prototype.push) { + Array.prototype.push = function() { + for (var i = 0, len = arguments.length; i < len; i++){ + this[this.length] = arguments[i]; + } + return this.length; + }; +} + +if (!Array.prototype.shift) { + Array.prototype.shift = function() { + if (this.length > 0) { + var firstItem = this[0]; + for (var i = 0, len = this.length - 1; i < len; i++) { + this[i] = this[i + 1]; + } + this.length = this.length - 1; + return firstItem; + } + }; +} + +if (!Array.prototype.splice) { + Array.prototype.splice = function(startIndex, deleteCount) { + var itemsAfterDeleted = this.slice(startIndex + deleteCount); + var itemsDeleted = this.slice(startIndex, startIndex + deleteCount); + this.length = startIndex; + // Copy the arguments into a proper Array object + var argumentsArray = []; + for (var i = 0, len = arguments.length; i < len; i++) { + argumentsArray[i] = arguments[i]; + } + var itemsToAppend = (argumentsArray.length > 2) ? + itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted; + for (i = 0, len = itemsToAppend.length; i < len; i++) { + this.push(itemsToAppend[i]); + } + return itemsDeleted; + }; +} + +/* -------------------------------------------------------------------------- */ + +var log4javascript = (function() { + + function isUndefined(obj) { + return typeof obj == "undefined"; + } + + /* ---------------------------------------------------------------------- */ + // Custom event support + + function EventSupport() {} + + EventSupport.prototype = { + eventTypes: [], + eventListeners: {}, + setEventTypes: function(eventTypesParam) { + if (eventTypesParam instanceof Array) { + this.eventTypes = eventTypesParam; + this.eventListeners = {}; + for (var i = 0, len = this.eventTypes.length; i < len; i++) { + this.eventListeners[this.eventTypes[i]] = []; + } + } else { + handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array"); + } + }, + + addEventListener: function(eventType, listener) { + if (typeof listener == "function") { + if (!array_contains(this.eventTypes, eventType)) { + handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'"); + } + this.eventListeners[eventType].push(listener); + } else { + handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function"); + } + }, + + removeEventListener: function(eventType, listener) { + if (typeof listener == "function") { + if (!array_contains(this.eventTypes, eventType)) { + handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'"); + } + array_remove(this.eventListeners[eventType], listener); + } else { + handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function"); + } + }, + + dispatchEvent: function(eventType, eventArgs) { + if (array_contains(this.eventTypes, eventType)) { + var listeners = this.eventListeners[eventType]; + for (var i = 0, len = listeners.length; i < len; i++) { + listeners[i](this, eventType, eventArgs); + } + } else { + handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'"); + } + } + }; + + /* -------------------------------------------------------------------------- */ + + var applicationStartDate = new Date(); + var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" + + Math.floor(Math.random() * 100000000); + var emptyFunction = function() {}; + var newLine = "\r\n"; + var pageLoaded = false; + + // Create main log4javascript object; this will be assigned public properties + function Log4JavaScript() {} + Log4JavaScript.prototype = new EventSupport(); + + log4javascript = new Log4JavaScript(); + log4javascript.version = "1.4.6"; + log4javascript.edition = "log4javascript"; + + /* -------------------------------------------------------------------------- */ + // Utility functions + + function toStr(obj) { + if (obj && obj.toString) { + return obj.toString(); + } else { + return String(obj); + } + } + + function getExceptionMessage(ex) { + if (ex.message) { + return ex.message; + } else if (ex.description) { + return ex.description; + } else { + return toStr(ex); + } + } + + // Gets the portion of the URL after the last slash + function getUrlFileName(url) { + var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\")); + return url.substr(lastSlashIndex + 1); + } + + // Returns a nicely formatted representation of an error + function getExceptionStringRep(ex) { + if (ex) { + var exStr = "Exception: " + getExceptionMessage(ex); + try { + if (ex.lineNumber) { + exStr += " on line number " + ex.lineNumber; + } + if (ex.fileName) { + exStr += " in file " + getUrlFileName(ex.fileName); + } + } catch (localEx) { + logLog.warn("Unable to obtain file and line information for error"); + } + if (showStackTraces && ex.stack) { + exStr += newLine + "Stack trace:" + newLine + ex.stack; + } + return exStr; + } + return null; + } + + function bool(obj) { + return Boolean(obj); + } + + function trim(str) { + return str.replace(/^\s+/, "").replace(/\s+$/, ""); + } + + function splitIntoLines(text) { + // Ensure all line breaks are \n only + var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); + return text2.split("\n"); + } + + var urlEncode = (typeof window.encodeURIComponent != "undefined") ? + function(str) { + return encodeURIComponent(str); + }: + function(str) { + return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D"); + }; + + var urlDecode = (typeof window.decodeURIComponent != "undefined") ? + function(str) { + return decodeURIComponent(str); + }: + function(str) { + return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "="); + }; + + function array_remove(arr, val) { + var index = -1; + for (var i = 0, len = arr.length; i < len; i++) { + if (arr[i] === val) { + index = i; + break; + } + } + if (index >= 0) { + arr.splice(index, 1); + return true; + } else { + return false; + } + } + + function array_contains(arr, val) { + for(var i = 0, len = arr.length; i < len; i++) { + if (arr[i] == val) { + return true; + } + } + return false; + } + + function extractBooleanFromParam(param, defaultValue) { + if (isUndefined(param)) { + return defaultValue; + } else { + return bool(param); + } + } + + function extractStringFromParam(param, defaultValue) { + if (isUndefined(param)) { + return defaultValue; + } else { + return String(param); + } + } + + function extractIntFromParam(param, defaultValue) { + if (isUndefined(param)) { + return defaultValue; + } else { + try { + var value = parseInt(param, 10); + return isNaN(value) ? defaultValue : value; + } catch (ex) { + logLog.warn("Invalid int param " + param, ex); + return defaultValue; + } + } + } + + function extractFunctionFromParam(param, defaultValue) { + if (typeof param == "function") { + return param; + } else { + return defaultValue; + } + } + + function isError(err) { + return (err instanceof Error); + } + + if (!Function.prototype.apply){ + Function.prototype.apply = function(obj, args) { + var methodName = "__apply__"; + if (typeof obj[methodName] != "undefined") { + methodName += String(Math.random()).substr(2); + } + obj[methodName] = this; + + var argsStrings = []; + for (var i = 0, len = args.length; i < len; i++) { + argsStrings[i] = "args[" + i + "]"; + } + var script = "obj." + methodName + "(" + argsStrings.join(",") + ")"; + var returnValue = eval(script); + delete obj[methodName]; + return returnValue; + }; + } + + if (!Function.prototype.call){ + Function.prototype.call = function(obj) { + var args = []; + for (var i = 1, len = arguments.length; i < len; i++) { + args[i - 1] = arguments[i]; + } + return this.apply(obj, args); + }; + } + + function getListenersPropertyName(eventName) { + return "__log4javascript_listeners__" + eventName; + } + + function addEvent(node, eventName, listener, useCapture, win) { + win = win ? win : window; + if (node.addEventListener) { + node.addEventListener(eventName, listener, useCapture); + } else if (node.attachEvent) { + node.attachEvent("on" + eventName, listener); + } else { + var propertyName = getListenersPropertyName(eventName); + if (!node[propertyName]) { + node[propertyName] = []; + // Set event handler + node["on" + eventName] = function(evt) { + evt = getEvent(evt, win); + var listenersPropertyName = getListenersPropertyName(eventName); + + // Clone the array of listeners to leave the original untouched + var listeners = this[listenersPropertyName].concat([]); + var currentListener; + + // Call each listener in turn + while ((currentListener = listeners.shift())) { + currentListener.call(this, evt); + } + }; + } + node[propertyName].push(listener); + } + } + + function removeEvent(node, eventName, listener, useCapture) { + if (node.removeEventListener) { + node.removeEventListener(eventName, listener, useCapture); + } else if (node.detachEvent) { + node.detachEvent("on" + eventName, listener); + } else { + var propertyName = getListenersPropertyName(eventName); + if (node[propertyName]) { + array_remove(node[propertyName], listener); + } + } + } + + function getEvent(evt, win) { + win = win ? win : window; + return evt ? evt : win.event; + } + + function stopEventPropagation(evt) { + if (evt.stopPropagation) { + evt.stopPropagation(); + } else if (typeof evt.cancelBubble != "undefined") { + evt.cancelBubble = true; + } + evt.returnValue = false; + } + + /* ---------------------------------------------------------------------- */ + // Simple logging for log4javascript itself + + var logLog = { + quietMode: false, + + debugMessages: [], + + setQuietMode: function(quietMode) { + this.quietMode = bool(quietMode); + }, + + numberOfErrors: 0, + + alertAllErrors: false, + + setAlertAllErrors: function(alertAllErrors) { + this.alertAllErrors = alertAllErrors; + }, + + debug: function(message) { + this.debugMessages.push(message); + }, + + displayDebug: function() { + alert(this.debugMessages.join(newLine)); + }, + + warn: function(message, exception) { + }, + + error: function(message, exception) { + if (++this.numberOfErrors == 1 || this.alertAllErrors) { + if (!this.quietMode) { + var alertMessage = "log4javascript error: " + message; + if (exception) { + alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception); + } + alert(alertMessage); + } + } + } + }; + log4javascript.logLog = logLog; + + log4javascript.setEventTypes(["load", "error"]); + + function handleError(message, exception) { + logLog.error(message, exception); + log4javascript.dispatchEvent("error", { "message": message, "exception": exception }); + } + + log4javascript.handleError = handleError; + + /* ---------------------------------------------------------------------- */ + + var enabled = !((typeof log4javascript_disabled != "undefined") && + log4javascript_disabled); + + log4javascript.setEnabled = function(enable) { + enabled = bool(enable); + }; + + log4javascript.isEnabled = function() { + return enabled; + }; + + var useTimeStampsInMilliseconds = true; + + log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) { + useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds); + }; + + log4javascript.isTimeStampsInMilliseconds = function() { + return useTimeStampsInMilliseconds; + }; + + + // This evaluates the given expression in the current scope, thus allowing + // scripts to access private variables. Particularly useful for testing + log4javascript.evalInScope = function(expr) { + return eval(expr); + }; + + var showStackTraces = false; + + log4javascript.setShowStackTraces = function(show) { + showStackTraces = bool(show); + }; + + /* ---------------------------------------------------------------------- */ + // Levels + + var Level = function(level, name) { + this.level = level; + this.name = name; + }; + + Level.prototype = { + toString: function() { + return this.name; + }, + equals: function(level) { + return this.level == level.level; + }, + isGreaterOrEqual: function(level) { + return this.level >= level.level; + } + }; + + Level.ALL = new Level(Number.MIN_VALUE, "ALL"); + Level.TRACE = new Level(10000, "TRACE"); + Level.DEBUG = new Level(20000, "DEBUG"); + Level.INFO = new Level(30000, "INFO"); + Level.WARN = new Level(40000, "WARN"); + Level.ERROR = new Level(50000, "ERROR"); + Level.FATAL = new Level(60000, "FATAL"); + Level.OFF = new Level(Number.MAX_VALUE, "OFF"); + + log4javascript.Level = Level; + + /* ---------------------------------------------------------------------- */ + // Timers + + function Timer(name, level) { + this.name = name; + this.level = isUndefined(level) ? Level.INFO : level; + this.start = new Date(); + } + + Timer.prototype.getElapsedTime = function() { + return new Date().getTime() - this.start.getTime(); + }; + + /* ---------------------------------------------------------------------- */ + // Loggers + + var anonymousLoggerName = "[anonymous]"; + var defaultLoggerName = "[default]"; + var nullLoggerName = "[null]"; + var rootLoggerName = "root"; + + function Logger(name) { + this.name = name; + this.parent = null; + this.children = []; + + var appenders = []; + var loggerLevel = null; + var isRoot = (this.name === rootLoggerName); + var isNull = (this.name === nullLoggerName); + + var appenderCache = null; + var appenderCacheInvalidated = false; + + this.addChild = function(childLogger) { + this.children.push(childLogger); + childLogger.parent = this; + childLogger.invalidateAppenderCache(); + }; + + // Additivity + var additive = true; + this.getAdditivity = function() { + return additive; + }; + + this.setAdditivity = function(additivity) { + var valueChanged = (additive != additivity); + additive = additivity; + if (valueChanged) { + this.invalidateAppenderCache(); + } + }; + + // Create methods that use the appenders variable in this scope + this.addAppender = function(appender) { + if (isNull) { + handleError("Logger.addAppender: you may not add an appender to the null logger"); + } else { + if (appender instanceof log4javascript.Appender) { + if (!array_contains(appenders, appender)) { + appenders.push(appender); + appender.setAddedToLogger(this); + this.invalidateAppenderCache(); + } + } else { + handleError("Logger.addAppender: appender supplied ('" + + toStr(appender) + "') is not a subclass of Appender"); + } + } + }; + + this.removeAppender = function(appender) { + array_remove(appenders, appender); + appender.setRemovedFromLogger(this); + this.invalidateAppenderCache(); + }; + + this.removeAllAppenders = function() { + var appenderCount = appenders.length; + if (appenderCount > 0) { + for (var i = 0; i < appenderCount; i++) { + appenders[i].setRemovedFromLogger(this); + } + appenders.length = 0; + this.invalidateAppenderCache(); + } + }; + + this.getEffectiveAppenders = function() { + if (appenderCache === null || appenderCacheInvalidated) { + // Build appender cache + var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ? + [] : this.parent.getEffectiveAppenders(); + appenderCache = parentEffectiveAppenders.concat(appenders); + appenderCacheInvalidated = false; + } + return appenderCache; + }; + + this.invalidateAppenderCache = function() { + appenderCacheInvalidated = true; + for (var i = 0, len = this.children.length; i < len; i++) { + this.children[i].invalidateAppenderCache(); + } + }; + + this.log = function(level, params) { + if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) { + // Check whether last param is an exception + var exception; + var finalParamIndex = params.length - 1; + var lastParam = params[finalParamIndex]; + if (params.length > 1 && isError(lastParam)) { + exception = lastParam; + finalParamIndex--; + } + + // Construct genuine array for the params + var messages = []; + for (var i = 0; i <= finalParamIndex; i++) { + messages[i] = params[i]; + } + + var loggingEvent = new LoggingEvent( + this, new Date(), level, messages, exception); + + this.callAppenders(loggingEvent); + } + }; + + this.callAppenders = function(loggingEvent) { + var effectiveAppenders = this.getEffectiveAppenders(); + for (var i = 0, len = effectiveAppenders.length; i < len; i++) { + effectiveAppenders[i].doAppend(loggingEvent); + } + }; + + this.setLevel = function(level) { + // Having a level of null on the root logger would be very bad. + if (isRoot && level === null) { + handleError("Logger.setLevel: you cannot set the level of the root logger to null"); + } else if (level instanceof Level) { + loggerLevel = level; + } else { + handleError("Logger.setLevel: level supplied to logger " + + this.name + " is not an instance of log4javascript.Level"); + } + }; + + this.getLevel = function() { + return loggerLevel; + }; + + this.getEffectiveLevel = function() { + for (var logger = this; logger !== null; logger = logger.parent) { + var level = logger.getLevel(); + if (level !== null) { + return level; + } + } + }; + + this.group = function(name, initiallyExpanded) { + if (enabled) { + var effectiveAppenders = this.getEffectiveAppenders(); + for (var i = 0, len = effectiveAppenders.length; i < len; i++) { + effectiveAppenders[i].group(name, initiallyExpanded); + } + } + }; + + this.groupEnd = function() { + if (enabled) { + var effectiveAppenders = this.getEffectiveAppenders(); + for (var i = 0, len = effectiveAppenders.length; i < len; i++) { + effectiveAppenders[i].groupEnd(); + } + } + }; + + var timers = {}; + + this.time = function(name, level) { + if (enabled) { + if (isUndefined(name)) { + handleError("Logger.time: a name for the timer must be supplied"); + } else if (level && !(level instanceof Level)) { + handleError("Logger.time: level supplied to timer " + + name + " is not an instance of log4javascript.Level"); + } else { + timers[name] = new Timer(name, level); + } + } + }; + + this.timeEnd = function(name) { + if (enabled) { + if (isUndefined(name)) { + handleError("Logger.timeEnd: a name for the timer must be supplied"); + } else if (timers[name]) { + var timer = timers[name]; + var milliseconds = timer.getElapsedTime(); + this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]); + delete timers[name]; + } else { + logLog.warn("Logger.timeEnd: no timer found with name " + name); + } + } + }; + + this.assert = function(expr) { + if (enabled && !expr) { + var args = []; + for (var i = 1, len = arguments.length; i < len; i++) { + args.push(arguments[i]); + } + args = (args.length > 0) ? args : ["Assertion Failure"]; + args.push(newLine); + args.push(expr); + this.log(Level.ERROR, args); + } + }; + + this.toString = function() { + return "Logger[" + this.name + "]"; + }; + } + + Logger.prototype = { + trace: function() { + this.log(Level.TRACE, arguments); + }, + + debug: function() { + this.log(Level.DEBUG, arguments); + }, + + info: function() { + this.log(Level.INFO, arguments); + }, + + warn: function() { + this.log(Level.WARN, arguments); + }, + + error: function() { + this.log(Level.ERROR, arguments); + }, + + fatal: function() { + this.log(Level.FATAL, arguments); + }, + + isEnabledFor: function(level) { + return level.isGreaterOrEqual(this.getEffectiveLevel()); + }, + + isTraceEnabled: function() { + return this.isEnabledFor(Level.TRACE); + }, + + isDebugEnabled: function() { + return this.isEnabledFor(Level.DEBUG); + }, + + isInfoEnabled: function() { + return this.isEnabledFor(Level.INFO); + }, + + isWarnEnabled: function() { + return this.isEnabledFor(Level.WARN); + }, + + isErrorEnabled: function() { + return this.isEnabledFor(Level.ERROR); + }, + + isFatalEnabled: function() { + return this.isEnabledFor(Level.FATAL); + } + }; + + Logger.prototype.trace.isEntryPoint = true; + Logger.prototype.debug.isEntryPoint = true; + Logger.prototype.info.isEntryPoint = true; + Logger.prototype.warn.isEntryPoint = true; + Logger.prototype.error.isEntryPoint = true; + Logger.prototype.fatal.isEntryPoint = true; + + /* ---------------------------------------------------------------------- */ + // Logger access methods + + // Hashtable of loggers keyed by logger name + var loggers = {}; + var loggerNames = []; + + var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG; + var rootLogger = new Logger(rootLoggerName); + rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL); + + log4javascript.getRootLogger = function() { + return rootLogger; + }; + + log4javascript.getLogger = function(loggerName) { + // Use default logger if loggerName is not specified or invalid + if (!(typeof loggerName == "string")) { + loggerName = anonymousLoggerName; + logLog.warn("log4javascript.getLogger: non-string logger name " + + toStr(loggerName) + " supplied, returning anonymous logger"); + } + + // Do not allow retrieval of the root logger by name + if (loggerName == rootLoggerName) { + handleError("log4javascript.getLogger: root logger may not be obtained by name"); + } + + // Create the logger for this name if it doesn't already exist + if (!loggers[loggerName]) { + var logger = new Logger(loggerName); + loggers[loggerName] = logger; + loggerNames.push(loggerName); + + // Set up parent logger, if it doesn't exist + var lastDotIndex = loggerName.lastIndexOf("."); + var parentLogger; + if (lastDotIndex > -1) { + var parentLoggerName = loggerName.substring(0, lastDotIndex); + parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc. + } else { + parentLogger = rootLogger; + } + parentLogger.addChild(logger); + } + return loggers[loggerName]; + }; + + var defaultLogger = null; + log4javascript.getDefaultLogger = function() { + if (!defaultLogger) { + defaultLogger = log4javascript.getLogger(defaultLoggerName); + var a = new log4javascript.PopUpAppender(); + defaultLogger.addAppender(a); + } + return defaultLogger; + }; + + var nullLogger = null; + log4javascript.getNullLogger = function() { + if (!nullLogger) { + nullLogger = new Logger(nullLoggerName); + nullLogger.setLevel(Level.OFF); + } + return nullLogger; + }; + + // Destroys all loggers + log4javascript.resetConfiguration = function() { + rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL); + loggers = {}; + }; + + /* ---------------------------------------------------------------------- */ + // Logging events + + var LoggingEvent = function(logger, timeStamp, level, messages, + exception) { + this.logger = logger; + this.timeStamp = timeStamp; + this.timeStampInMilliseconds = timeStamp.getTime(); + this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000); + this.milliseconds = this.timeStamp.getMilliseconds(); + this.level = level; + this.messages = messages; + this.exception = exception; + }; + + LoggingEvent.prototype = { + getThrowableStrRep: function() { + return this.exception ? + getExceptionStringRep(this.exception) : ""; + }, + getCombinedMessages: function() { + return (this.messages.length == 1) ? this.messages[0] : + this.messages.join(newLine); + }, + toString: function() { + return "LoggingEvent[" + this.level + "]"; + } + }; + + log4javascript.LoggingEvent = LoggingEvent; + + /* ---------------------------------------------------------------------- */ + // Layout prototype + + var Layout = function() { + }; + + Layout.prototype = { + defaults: { + loggerKey: "logger", + timeStampKey: "timestamp", + millisecondsKey: "milliseconds", + levelKey: "level", + messageKey: "message", + exceptionKey: "exception", + urlKey: "url" + }, + loggerKey: "logger", + timeStampKey: "timestamp", + millisecondsKey: "milliseconds", + levelKey: "level", + messageKey: "message", + exceptionKey: "exception", + urlKey: "url", + batchHeader: "", + batchFooter: "", + batchSeparator: "", + returnsPostData: false, + overrideTimeStampsSetting: false, + useTimeStampsInMilliseconds: null, + + format: function() { + handleError("Layout.format: layout supplied has no format() method"); + }, + + ignoresThrowable: function() { + handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method"); + }, + + getContentType: function() { + return "text/plain"; + }, + + allowBatching: function() { + return true; + }, + + setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) { + this.overrideTimeStampsSetting = true; + this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds); + }, + + isTimeStampsInMilliseconds: function() { + return this.overrideTimeStampsSetting ? + this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds; + }, + + getTimeStampValue: function(loggingEvent) { + return this.isTimeStampsInMilliseconds() ? + loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds; + }, + + getDataValues: function(loggingEvent, combineMessages) { + var dataValues = [ + [this.loggerKey, loggingEvent.logger.name], + [this.timeStampKey, this.getTimeStampValue(loggingEvent)], + [this.levelKey, loggingEvent.level.name], + [this.urlKey, window.location.href], + [this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages] + ]; + if (!this.isTimeStampsInMilliseconds()) { + dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]); + } + if (loggingEvent.exception) { + dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]); + } + if (this.hasCustomFields()) { + for (var i = 0, len = this.customFields.length; i < len; i++) { + var val = this.customFields[i].value; + + // Check if the value is a function. If so, execute it, passing it the + // current layout and the logging event + if (typeof val === "function") { + val = val(this, loggingEvent); + } + dataValues.push([this.customFields[i].name, val]); + } + } + return dataValues; + }, + + setKeys: function(loggerKey, timeStampKey, levelKey, messageKey, + exceptionKey, urlKey, millisecondsKey) { + this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey); + this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey); + this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey); + this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey); + this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey); + this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey); + this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey); + }, + + setCustomField: function(name, value) { + var fieldUpdated = false; + for (var i = 0, len = this.customFields.length; i < len; i++) { + if (this.customFields[i].name === name) { + this.customFields[i].value = value; + fieldUpdated = true; + } + } + if (!fieldUpdated) { + this.customFields.push({"name": name, "value": value}); + } + }, + + hasCustomFields: function() { + return (this.customFields.length > 0); + }, + + toString: function() { + handleError("Layout.toString: all layouts must override this method"); + } + }; + + log4javascript.Layout = Layout; + + /* ---------------------------------------------------------------------- */ + // Appender prototype + + var Appender = function() {}; + + Appender.prototype = new EventSupport(); + + Appender.prototype.layout = new PatternLayout(); + Appender.prototype.threshold = Level.ALL; + Appender.prototype.loggers = []; + + // Performs threshold checks before delegating actual logging to the + // subclass's specific append method. + Appender.prototype.doAppend = function(loggingEvent) { + if (enabled && loggingEvent.level.level >= this.threshold.level) { + this.append(loggingEvent); + } + }; + + Appender.prototype.append = function(loggingEvent) {}; + + Appender.prototype.setLayout = function(layout) { + if (layout instanceof Layout) { + this.layout = layout; + } else { + handleError("Appender.setLayout: layout supplied to " + + this.toString() + " is not a subclass of Layout"); + } + }; + + Appender.prototype.getLayout = function() { + return this.layout; + }; + + Appender.prototype.setThreshold = function(threshold) { + if (threshold instanceof Level) { + this.threshold = threshold; + } else { + handleError("Appender.setThreshold: threshold supplied to " + + this.toString() + " is not a subclass of Level"); + } + }; + + Appender.prototype.getThreshold = function() { + return this.threshold; + }; + + Appender.prototype.setAddedToLogger = function(logger) { + this.loggers.push(logger); + }; + + Appender.prototype.setRemovedFromLogger = function(logger) { + array_remove(this.loggers, logger); + }; + + Appender.prototype.group = emptyFunction; + Appender.prototype.groupEnd = emptyFunction; + + Appender.prototype.toString = function() { + handleError("Appender.toString: all appenders must override this method"); + }; + + log4javascript.Appender = Appender; + + /* ---------------------------------------------------------------------- */ + // SimpleLayout + + function SimpleLayout() { + this.customFields = []; + } + + SimpleLayout.prototype = new Layout(); + + SimpleLayout.prototype.format = function(loggingEvent) { + return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages(); + }; + + SimpleLayout.prototype.ignoresThrowable = function() { + return true; + }; + + SimpleLayout.prototype.toString = function() { + return "SimpleLayout"; + }; + + log4javascript.SimpleLayout = SimpleLayout; + /* ----------------------------------------------------------------------- */ + // NullLayout + + function NullLayout() { + this.customFields = []; + } + + NullLayout.prototype = new Layout(); + + NullLayout.prototype.format = function(loggingEvent) { + return loggingEvent.messages; + }; + + NullLayout.prototype.ignoresThrowable = function() { + return true; + }; + + NullLayout.prototype.toString = function() { + return "NullLayout"; + }; + + log4javascript.NullLayout = NullLayout; +/* ---------------------------------------------------------------------- */ + // XmlLayout + + function XmlLayout(combineMessages) { + this.combineMessages = extractBooleanFromParam(combineMessages, true); + this.customFields = []; + } + + XmlLayout.prototype = new Layout(); + + XmlLayout.prototype.isCombinedMessages = function() { + return this.combineMessages; + }; + + XmlLayout.prototype.getContentType = function() { + return "text/xml"; + }; + + XmlLayout.prototype.escapeCdata = function(str) { + return str.replace(/\]\]>/, "]]>]]>"; + } + + var str = "" + newLine; + if (this.combineMessages) { + str += formatMessage(loggingEvent.getCombinedMessages()); + } else { + str += "" + newLine; + for (i = 0, len = loggingEvent.messages.length; i < len; i++) { + str += formatMessage(loggingEvent.messages[i]) + newLine; + } + str += "" + newLine; + } + if (this.hasCustomFields()) { + for (i = 0, len = this.customFields.length; i < len; i++) { + str += "" + newLine; + } + } + if (loggingEvent.exception) { + str += "" + newLine; + } + str += "" + newLine + newLine; + return str; + }; + + XmlLayout.prototype.ignoresThrowable = function() { + return false; + }; + + XmlLayout.prototype.toString = function() { + return "XmlLayout"; + }; + + log4javascript.XmlLayout = XmlLayout; + /* ---------------------------------------------------------------------- */ + // JsonLayout related + + function escapeNewLines(str) { + return str.replace(/\r\n|\r|\n/g, "\\r\\n"); + } + + function JsonLayout(readable, combineMessages) { + this.readable = extractBooleanFromParam(readable, false); + this.combineMessages = extractBooleanFromParam(combineMessages, true); + this.batchHeader = this.readable ? "[" + newLine : "["; + this.batchFooter = this.readable ? "]" + newLine : "]"; + this.batchSeparator = this.readable ? "," + newLine : ","; + this.setKeys(); + this.colon = this.readable ? ": " : ":"; + this.tab = this.readable ? "\t" : ""; + this.lineBreak = this.readable ? newLine : ""; + this.customFields = []; + } + + /* ---------------------------------------------------------------------- */ + // JsonLayout + + JsonLayout.prototype = new Layout(); + + JsonLayout.prototype.isReadable = function() { + return this.readable; + }; + + JsonLayout.prototype.isCombinedMessages = function() { + return this.combineMessages; + }; + + JsonLayout.prototype.format = function(loggingEvent) { + var layout = this; + var dataValues = this.getDataValues(loggingEvent, this.combineMessages); + var str = "{" + this.lineBreak; + var i, len; + + function formatValue(val, prefix, expand) { + // Check the type of the data value to decide whether quotation marks + // or expansion are required + var formattedValue; + var valType = typeof val; + if (val instanceof Date) { + formattedValue = String(val.getTime()); + } else if (expand && (val instanceof Array)) { + formattedValue = "[" + layout.lineBreak; + for (var i = 0, len = val.length; i < len; i++) { + var childPrefix = prefix + layout.tab; + formattedValue += childPrefix + formatValue(val[i], childPrefix, false); + if (i < val.length - 1) { + formattedValue += ","; + } + formattedValue += layout.lineBreak; + } + formattedValue += prefix + "]"; + } else if (valType !== "number" && valType !== "boolean") { + formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\""; + } else { + formattedValue = val; + } + return formattedValue; + } + + for (i = 0, len = dataValues.length - 1; i <= len; i++) { + str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true); + if (i < len) { + str += ","; + } + str += this.lineBreak; + } + + str += "}" + this.lineBreak; + return str; + }; + + JsonLayout.prototype.ignoresThrowable = function() { + return false; + }; + + JsonLayout.prototype.toString = function() { + return "JsonLayout"; + }; + + JsonLayout.prototype.getContentType = function() { + return "application/json"; + }; + + log4javascript.JsonLayout = JsonLayout; + /* ---------------------------------------------------------------------- */ + // HttpPostDataLayout + + function HttpPostDataLayout() { + this.setKeys(); + this.customFields = []; + this.returnsPostData = true; + } + + HttpPostDataLayout.prototype = new Layout(); + + // Disable batching + HttpPostDataLayout.prototype.allowBatching = function() { + return false; + }; + + HttpPostDataLayout.prototype.format = function(loggingEvent) { + var dataValues = this.getDataValues(loggingEvent); + var queryBits = []; + for (var i = 0, len = dataValues.length; i < len; i++) { + var val = (dataValues[i][1] instanceof Date) ? + String(dataValues[i][1].getTime()) : dataValues[i][1]; + queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val)); + } + return queryBits.join("&"); + }; + + HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) { + return false; + }; + + HttpPostDataLayout.prototype.toString = function() { + return "HttpPostDataLayout"; + }; + + log4javascript.HttpPostDataLayout = HttpPostDataLayout; + /* ---------------------------------------------------------------------- */ + // formatObjectExpansion + + function formatObjectExpansion(obj, depth, indentation) { + var objectsExpanded = []; + + function doFormat(obj, depth, indentation) { + var i, j, len, childDepth, childIndentation, childLines, expansion, + childExpansion; + + if (!indentation) { + indentation = ""; + } + + function formatString(text) { + var lines = splitIntoLines(text); + for (var j = 1, jLen = lines.length; j < jLen; j++) { + lines[j] = indentation + lines[j]; + } + return lines.join(newLine); + } + + if (obj === null) { + return "null"; + } else if (typeof obj == "undefined") { + return "undefined"; + } else if (typeof obj == "string") { + return formatString(obj); + } else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) { + try { + expansion = toStr(obj); + } catch (ex) { + expansion = "Error formatting property. Details: " + getExceptionStringRep(ex); + } + return expansion + " [already expanded]"; + } else if ((obj instanceof Array) && depth > 0) { + objectsExpanded.push(obj); + expansion = "[" + newLine; + childDepth = depth - 1; + childIndentation = indentation + " "; + childLines = []; + for (i = 0, len = obj.length; i < len; i++) { + try { + childExpansion = doFormat(obj[i], childDepth, childIndentation); + childLines.push(childIndentation + childExpansion); + } catch (ex) { + childLines.push(childIndentation + "Error formatting array member. Details: " + + getExceptionStringRep(ex) + ""); + } + } + expansion += childLines.join("," + newLine) + newLine + indentation + "]"; + return expansion; + } else if (Object.prototype.toString.call(obj) == "[object Date]") { + return obj.toString(); + } else if (typeof obj == "object" && depth > 0) { + objectsExpanded.push(obj); + expansion = "{" + newLine; + childDepth = depth - 1; + childIndentation = indentation + " "; + childLines = []; + for (i in obj) { + try { + childExpansion = doFormat(obj[i], childDepth, childIndentation); + childLines.push(childIndentation + i + ": " + childExpansion); + } catch (ex) { + childLines.push(childIndentation + i + ": Error formatting property. Details: " + + getExceptionStringRep(ex)); + } + } + expansion += childLines.join("," + newLine) + newLine + indentation + "}"; + return expansion; + } else { + return formatString(toStr(obj)); + } + } + return doFormat(obj, depth, indentation); + } + /* ---------------------------------------------------------------------- */ + // Date-related stuff + + var SimpleDateFormat; + + (function() { + var 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']+)/; + var monthNames = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"]; + var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5; + var types = { + G : TEXT2, + y : YEAR, + M : MONTH, + w : NUMBER, + W : NUMBER, + D : NUMBER, + d : NUMBER, + F : NUMBER, + E : TEXT3, + a : TEXT2, + H : NUMBER, + k : NUMBER, + K : NUMBER, + h : NUMBER, + m : NUMBER, + s : NUMBER, + S : NUMBER, + Z : TIMEZONE + }; + var ONE_DAY = 24 * 60 * 60 * 1000; + var ONE_WEEK = 7 * ONE_DAY; + var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1; + + var newDateAtMidnight = function(year, month, day) { + var d = new Date(year, month, day, 0, 0, 0); + d.setMilliseconds(0); + return d; + }; + + Date.prototype.getDifference = function(date) { + return this.getTime() - date.getTime(); + }; + + Date.prototype.isBefore = function(d) { + return this.getTime() < d.getTime(); + }; + + Date.prototype.getUTCTime = function() { + return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(), + this.getSeconds(), this.getMilliseconds()); + }; + + Date.prototype.getTimeSince = function(d) { + return this.getUTCTime() - d.getUTCTime(); + }; + + Date.prototype.getPreviousSunday = function() { + // Using midday avoids any possibility of DST messing things up + var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0); + var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY); + return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(), + previousSunday.getDate()); + }; + + Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) { + if (isUndefined(this.minimalDaysInFirstWeek)) { + minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK; + } + var previousSunday = this.getPreviousSunday(); + var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1); + var numberOfSundays = previousSunday.isBefore(startOfYear) ? + 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK); + var numberOfDaysInFirstWeek = 7 - startOfYear.getDay(); + var weekInYear = numberOfSundays; + if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) { + weekInYear--; + } + return weekInYear; + }; + + Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) { + if (isUndefined(this.minimalDaysInFirstWeek)) { + minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK; + } + var previousSunday = this.getPreviousSunday(); + var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1); + var numberOfSundays = previousSunday.isBefore(startOfMonth) ? + 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK); + var numberOfDaysInFirstWeek = 7 - startOfMonth.getDay(); + var weekInMonth = numberOfSundays; + if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) { + weekInMonth++; + } + return weekInMonth; + }; + + Date.prototype.getDayInYear = function() { + var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1); + return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY); + }; + + /* ------------------------------------------------------------------ */ + + SimpleDateFormat = function(formatString) { + this.formatString = formatString; + }; + + /** + * Sets the minimum number of days in a week in order for that week to + * be considered as belonging to a particular month or year + */ + SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) { + this.minimalDaysInFirstWeek = days; + }; + + SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() { + return isUndefined(this.minimalDaysInFirstWeek) ? + DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek; + }; + + var padWithZeroes = function(str, len) { + while (str.length < len) { + str = "0" + str; + } + return str; + }; + + var formatText = function(data, numberOfLetters, minLength) { + return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters)); + }; + + var formatNumber = function(data, numberOfLetters) { + var dataString = "" + data; + // Pad with 0s as necessary + return padWithZeroes(dataString, numberOfLetters); + }; + + SimpleDateFormat.prototype.format = function(date) { + var formattedString = ""; + var result; + var searchString = this.formatString; + while ((result = regex.exec(searchString))) { + var quotedString = result[1]; + var patternLetters = result[2]; + var otherLetters = result[3]; + var otherCharacters = result[4]; + + // If the pattern matched is quoted string, output the text between the quotes + if (quotedString) { + if (quotedString == "''") { + formattedString += "'"; + } else { + formattedString += quotedString.substring(1, quotedString.length - 1); + } + } else if (otherLetters) { + // Swallow non-pattern letters by doing nothing here + } else if (otherCharacters) { + // Simply output other characters + formattedString += otherCharacters; + } else if (patternLetters) { + // Replace pattern letters + var patternLetter = patternLetters.charAt(0); + var numberOfLetters = patternLetters.length; + var rawData = ""; + switch(patternLetter) { + case "G": + rawData = "AD"; + break; + case "y": + rawData = date.getFullYear(); + break; + case "M": + rawData = date.getMonth(); + break; + case "w": + rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek()); + break; + case "W": + rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek()); + break; + case "D": + rawData = date.getDayInYear(); + break; + case "d": + rawData = date.getDate(); + break; + case "F": + rawData = 1 + Math.floor((date.getDate() - 1) / 7); + break; + case "E": + rawData = dayNames[date.getDay()]; + break; + case "a": + rawData = (date.getHours() >= 12) ? "PM" : "AM"; + break; + case "H": + rawData = date.getHours(); + break; + case "k": + rawData = date.getHours() || 24; + break; + case "K": + rawData = date.getHours() % 12; + break; + case "h": + rawData = (date.getHours() % 12) || 12; + break; + case "m": + rawData = date.getMinutes(); + break; + case "s": + rawData = date.getSeconds(); + break; + case "S": + rawData = date.getMilliseconds(); + break; + case "Z": + rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time. + break; + } + // Format the raw data depending on the type + switch(types[patternLetter]) { + case TEXT2: + formattedString += formatText(rawData, numberOfLetters, 2); + break; + case TEXT3: + formattedString += formatText(rawData, numberOfLetters, 3); + break; + case NUMBER: + formattedString += formatNumber(rawData, numberOfLetters); + break; + case YEAR: + if (numberOfLetters <= 3) { + // Output a 2-digit year + var dataString = "" + rawData; + formattedString += dataString.substr(2, 2); + } else { + formattedString += formatNumber(rawData, numberOfLetters); + } + break; + case MONTH: + if (numberOfLetters >= 3) { + formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters); + } else { + // NB. Months returned by getMonth are zero-based + formattedString += formatNumber(rawData + 1, numberOfLetters); + } + break; + case TIMEZONE: + var isPositive = (rawData > 0); + // The following line looks like a mistake but isn't + // because of the way getTimezoneOffset measures. + var prefix = isPositive ? "-" : "+"; + var absData = Math.abs(rawData); + + // Hours + var hours = "" + Math.floor(absData / 60); + hours = padWithZeroes(hours, 2); + // Minutes + var minutes = "" + (absData % 60); + minutes = padWithZeroes(minutes, 2); + + formattedString += prefix + hours + minutes; + break; + } + } + searchString = searchString.substr(result.index + result[0].length); + } + return formattedString; + }; + })(); + + log4javascript.SimpleDateFormat = SimpleDateFormat; + + /* ---------------------------------------------------------------------- */ + // PatternLayout + + function PatternLayout(pattern) { + if (pattern) { + this.pattern = pattern; + } else { + this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN; + } + this.customFields = []; + } + + PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n"; + PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n"; + PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS"; + PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS"; + PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS"; + + PatternLayout.prototype = new Layout(); + + PatternLayout.prototype.format = function(loggingEvent) { + var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/; + var formattedString = ""; + var result; + var searchString = this.pattern; + + // Cannot use regex global flag since it doesn't work with exec in IE5 + while ((result = regex.exec(searchString))) { + var matchedString = result[0]; + var padding = result[1]; + var truncation = result[2]; + var conversionCharacter = result[3]; + var specifier = result[5]; + var text = result[6]; + + // Check if the pattern matched was just normal text + if (text) { + formattedString += "" + text; + } else { + // Create a raw replacement string based on the conversion + // character and specifier + var replacement = ""; + switch(conversionCharacter) { + case "a": // Array of messages + case "m": // Message + var depth = 0; + if (specifier) { + depth = parseInt(specifier, 10); + if (isNaN(depth)) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character '" + conversionCharacter + + "' - should be a number"); + depth = 0; + } + } + var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages; + for (var i = 0, len = messages.length; i < len; i++) { + if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) { + replacement += " "; + } + if (depth === 0) { + replacement += messages[i]; + } else { + replacement += formatObjectExpansion(messages[i], depth); + } + } + break; + case "c": // Logger name + var loggerName = loggingEvent.logger.name; + if (specifier) { + var precision = parseInt(specifier, 10); + var loggerNameBits = loggingEvent.logger.name.split("."); + if (precision >= loggerNameBits.length) { + replacement = loggerName; + } else { + replacement = loggerNameBits.slice(loggerNameBits.length - precision).join("."); + } + } else { + replacement = loggerName; + } + break; + case "d": // Date + var dateFormat = PatternLayout.ISO8601_DATEFORMAT; + if (specifier) { + dateFormat = specifier; + // Pick up special cases + if (dateFormat == "ISO8601") { + dateFormat = PatternLayout.ISO8601_DATEFORMAT; + } else if (dateFormat == "ABSOLUTE") { + dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT; + } else if (dateFormat == "DATE") { + dateFormat = PatternLayout.DATETIME_DATEFORMAT; + } + } + // Format the date + replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp); + break; + case "f": // Custom field + if (this.hasCustomFields()) { + var fieldIndex = 0; + if (specifier) { + fieldIndex = parseInt(specifier, 10); + if (isNaN(fieldIndex)) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character 'f' - should be a number"); + } else if (fieldIndex === 0) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character 'f' - must be greater than zero"); + } else if (fieldIndex > this.customFields.length) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character 'f' - there aren't that many custom fields"); + } else { + fieldIndex = fieldIndex - 1; + } + } + var val = this.customFields[fieldIndex].value; + if (typeof val == "function") { + val = val(this, loggingEvent); + } + replacement = val; + } + break; + case "n": // New line + replacement = newLine; + break; + case "p": // Level + replacement = loggingEvent.level.name; + break; + case "r": // Milliseconds since log4javascript startup + replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate); + break; + case "%": // Literal % sign + replacement = "%"; + break; + default: + replacement = matchedString; + break; + } + // Format the replacement according to any padding or + // truncation specified + var l; + + // First, truncation + if (truncation) { + l = parseInt(truncation.substr(1), 10); + var strLen = replacement.length; + if (l < strLen) { + replacement = replacement.substring(strLen - l, strLen); + } + } + // Next, padding + if (padding) { + if (padding.charAt(0) == "-") { + l = parseInt(padding.substr(1), 10); + // Right pad with spaces + while (replacement.length < l) { + replacement += " "; + } + } else { + l = parseInt(padding, 10); + // Left pad with spaces + while (replacement.length < l) { + replacement = " " + replacement; + } + } + } + formattedString += replacement; + } + searchString = searchString.substr(result.index + result[0].length); + } + return formattedString; + }; + + PatternLayout.prototype.ignoresThrowable = function() { + return true; + }; + + PatternLayout.prototype.toString = function() { + return "PatternLayout"; + }; + + log4javascript.PatternLayout = PatternLayout; + /* ---------------------------------------------------------------------- */ + // AlertAppender + + function AlertAppender() {} + + AlertAppender.prototype = new Appender(); + + AlertAppender.prototype.layout = new SimpleLayout(); + + AlertAppender.prototype.append = function(loggingEvent) { + var formattedMessage = this.getLayout().format(loggingEvent); + if (this.getLayout().ignoresThrowable()) { + formattedMessage += loggingEvent.getThrowableStrRep(); + } + alert(formattedMessage); + }; + + AlertAppender.prototype.toString = function() { + return "AlertAppender"; + }; + + log4javascript.AlertAppender = AlertAppender; + /* ---------------------------------------------------------------------- */ + // BrowserConsoleAppender (only works in Opera and Safari and Firefox with + // Firebug extension) + + function BrowserConsoleAppender() {} + + BrowserConsoleAppender.prototype = new log4javascript.Appender(); + BrowserConsoleAppender.prototype.layout = new NullLayout(); + BrowserConsoleAppender.prototype.threshold = Level.DEBUG; + + BrowserConsoleAppender.prototype.append = function(loggingEvent) { + var appender = this; + + var getFormattedMessage = function() { + var layout = appender.getLayout(); + var formattedMessage = layout.format(loggingEvent); + if (layout.ignoresThrowable() && loggingEvent.exception) { + formattedMessage += loggingEvent.getThrowableStrRep(); + } + return formattedMessage; + }; + + if ((typeof opera != "undefined") && opera.postError) { // Opera + opera.postError(getFormattedMessage()); + } else if (window.console && window.console.log) { // Safari and Firebug + var formattedMesage = getFormattedMessage(); + // Log to Firebug using its logging methods or revert to the console.log + // method in Safari + if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) { + window.console.debug(formattedMesage); + } else if (window.console.info && Level.INFO.equals(loggingEvent.level)) { + window.console.info(formattedMesage); + } else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) { + window.console.warn(formattedMesage); + } else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) { + window.console.error(formattedMesage); + } else { + window.console.log(formattedMesage); + } + } + }; + + BrowserConsoleAppender.prototype.group = function(name) { + if (window.console && window.console.group) { + window.console.group(name); + } + }; + + BrowserConsoleAppender.prototype.groupEnd = function() { + if (window.console && window.console.groupEnd) { + window.console.groupEnd(); + } + }; + + BrowserConsoleAppender.prototype.toString = function() { + return "BrowserConsoleAppender"; + }; + + log4javascript.BrowserConsoleAppender = BrowserConsoleAppender; + /* ---------------------------------------------------------------------- */ + // AjaxAppender related + + var xmlHttpFactories = [ + function() { return new XMLHttpRequest(); }, + function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, + function() { return new ActiveXObject("Microsoft.XMLHTTP"); } + ]; + + var getXmlHttp = function(errorHandler) { + // This is only run the first time; the value of getXmlHttp gets + // replaced with the factory that succeeds on the first run + var xmlHttp = null, factory; + for (var i = 0, len = xmlHttpFactories.length; i < len; i++) { + factory = xmlHttpFactories[i]; + try { + xmlHttp = factory(); + getXmlHttp = factory; + return xmlHttp; + } catch (e) { + } + } + // If we're here, all factories have failed, so throw an error + if (errorHandler) { + errorHandler(); + } else { + handleError("getXmlHttp: unable to obtain XMLHttpRequest object"); + } + }; + + function isHttpRequestSuccessful(xmlHttp) { + return isUndefined(xmlHttp.status) || xmlHttp.status === 0 || + (xmlHttp.status >= 200 && xmlHttp.status < 300) || + xmlHttp.status == 1223 /* Fix for IE */; + } + + /* ---------------------------------------------------------------------- */ + // AjaxAppender + + function AjaxAppender(url) { + var appender = this; + var isSupported = true; + if (!url) { + handleError("AjaxAppender: URL must be specified in constructor"); + isSupported = false; + } + + var timed = this.defaults.timed; + var waitForResponse = this.defaults.waitForResponse; + var batchSize = this.defaults.batchSize; + var timerInterval = this.defaults.timerInterval; + var requestSuccessCallback = this.defaults.requestSuccessCallback; + var failCallback = this.defaults.failCallback; + var postVarName = this.defaults.postVarName; + var sendAllOnUnload = this.defaults.sendAllOnUnload; + var contentType = this.defaults.contentType; + var sessionId = null; + + var queuedLoggingEvents = []; + var queuedRequests = []; + var headers = []; + var sending = false; + var initialized = false; + + // Configuration methods. The function scope is used to prevent + // direct alteration to the appender configuration properties. + function checkCanConfigure(configOptionName) { + if (initialized) { + handleError("AjaxAppender: configuration option '" + + configOptionName + + "' may not be set after the appender has been initialized"); + return false; + } + return true; + } + + this.getSessionId = function() { return sessionId; }; + this.setSessionId = function(sessionIdParam) { + sessionId = extractStringFromParam(sessionIdParam, null); + this.layout.setCustomField("sessionid", sessionId); + }; + + this.setLayout = function(layoutParam) { + if (checkCanConfigure("layout")) { + this.layout = layoutParam; + // Set the session id as a custom field on the layout, if not already present + if (sessionId !== null) { + this.setSessionId(sessionId); + } + } + }; + + this.isTimed = function() { return timed; }; + this.setTimed = function(timedParam) { + if (checkCanConfigure("timed")) { + timed = bool(timedParam); + } + }; + + this.getTimerInterval = function() { return timerInterval; }; + this.setTimerInterval = function(timerIntervalParam) { + if (checkCanConfigure("timerInterval")) { + timerInterval = extractIntFromParam(timerIntervalParam, timerInterval); + } + }; + + this.isWaitForResponse = function() { return waitForResponse; }; + this.setWaitForResponse = function(waitForResponseParam) { + if (checkCanConfigure("waitForResponse")) { + waitForResponse = bool(waitForResponseParam); + } + }; + + this.getBatchSize = function() { return batchSize; }; + this.setBatchSize = function(batchSizeParam) { + if (checkCanConfigure("batchSize")) { + batchSize = extractIntFromParam(batchSizeParam, batchSize); + } + }; + + this.isSendAllOnUnload = function() { return sendAllOnUnload; }; + this.setSendAllOnUnload = function(sendAllOnUnloadParam) { + if (checkCanConfigure("sendAllOnUnload")) { + sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload); + } + }; + + this.setRequestSuccessCallback = function(requestSuccessCallbackParam) { + requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback); + }; + + this.setFailCallback = function(failCallbackParam) { + failCallback = extractFunctionFromParam(failCallbackParam, failCallback); + }; + + this.getPostVarName = function() { return postVarName; }; + this.setPostVarName = function(postVarNameParam) { + if (checkCanConfigure("postVarName")) { + postVarName = extractStringFromParam(postVarNameParam, postVarName); + } + }; + + this.getHeaders = function() { return headers; }; + this.addHeader = function(name, value) { + if (name.toLowerCase() == "content-type") { + contentType = value; + } else { + headers.push( { name: name, value: value } ); + } + }; + + // Internal functions + function sendAll() { + if (isSupported && enabled) { + sending = true; + var currentRequestBatch; + if (waitForResponse) { + // Send the first request then use this function as the callback once + // the response comes back + if (queuedRequests.length > 0) { + currentRequestBatch = queuedRequests.shift(); + sendRequest(preparePostData(currentRequestBatch), sendAll); + } else { + sending = false; + if (timed) { + scheduleSending(); + } + } + } else { + // Rattle off all the requests without waiting to see the response + while ((currentRequestBatch = queuedRequests.shift())) { + sendRequest(preparePostData(currentRequestBatch)); + } + sending = false; + if (timed) { + scheduleSending(); + } + } + } + } + + this.sendAll = sendAll; + + // Called when the window unloads. At this point we're past caring about + // waiting for responses or timers or incomplete batches - everything + // must go, now + function sendAllRemaining() { + var sendingAnything = false; + if (isSupported && enabled) { + // Create requests for everything left over, batched as normal + var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1; + var currentLoggingEvent; + var batchedLoggingEvents = []; + while ((currentLoggingEvent = queuedLoggingEvents.shift())) { + batchedLoggingEvents.push(currentLoggingEvent); + if (queuedLoggingEvents.length >= actualBatchSize) { + // Queue this batch of log entries + queuedRequests.push(batchedLoggingEvents); + batchedLoggingEvents = []; + } + } + // If there's a partially completed batch, add it + if (batchedLoggingEvents.length > 0) { + queuedRequests.push(batchedLoggingEvents); + } + sendingAnything = (queuedRequests.length > 0); + waitForResponse = false; + timed = false; + sendAll(); + } + return sendingAnything; + } + + this.sendAllRemaining = sendAllRemaining; + + function preparePostData(batchedLoggingEvents) { + // Format the logging events + var formattedMessages = []; + var currentLoggingEvent; + var postData = ""; + while ((currentLoggingEvent = batchedLoggingEvents.shift())) { + var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent); + if (appender.getLayout().ignoresThrowable()) { + currentFormattedMessage += currentLoggingEvent.getThrowableStrRep(); + } + formattedMessages.push(currentFormattedMessage); + } + // Create the post data string + if (batchedLoggingEvents.length == 1) { + postData = formattedMessages.join(""); + } else { + postData = appender.getLayout().batchHeader + + formattedMessages.join(appender.getLayout().batchSeparator) + + appender.getLayout().batchFooter; + } + if (contentType == appender.defaults.contentType) { + postData = appender.getLayout().returnsPostData ? postData : + urlEncode(postVarName) + "=" + urlEncode(postData); + // Add the layout name to the post data + if (postData.length > 0) { + postData += "&"; + } + postData += "layout=" + urlEncode(appender.getLayout().toString()); + } + return postData; + } + + function scheduleSending() { + window.setTimeout(sendAll, timerInterval); + } + + function xmlHttpErrorHandler() { + var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled"; + handleError(msg); + isSupported = false; + if (failCallback) { + failCallback(msg); + } + } + + function sendRequest(postData, successCallback) { + try { + var xmlHttp = getXmlHttp(xmlHttpErrorHandler); + if (isSupported) { + if (xmlHttp.overrideMimeType) { + xmlHttp.overrideMimeType(appender.getLayout().getContentType()); + } + xmlHttp.onreadystatechange = function() { + if (xmlHttp.readyState == 4) { + if (isHttpRequestSuccessful(xmlHttp)) { + if (requestSuccessCallback) { + requestSuccessCallback(xmlHttp); + } + if (successCallback) { + successCallback(xmlHttp); + } + } else { + var msg = "AjaxAppender.append: XMLHttpRequest request to URL " + + url + " returned status code " + xmlHttp.status; + handleError(msg); + if (failCallback) { + failCallback(msg); + } + } + xmlHttp.onreadystatechange = emptyFunction; + xmlHttp = null; + } + }; + xmlHttp.open("POST", url, true); + try { + for (var i = 0, header; header = headers[i++]; ) { + xmlHttp.setRequestHeader(header.name, header.value); + } + xmlHttp.setRequestHeader("Content-Type", contentType); + } catch (headerEx) { + var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" + + " does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled"; + handleError(msg); + isSupported = false; + if (failCallback) { + failCallback(msg); + } + return; + } + xmlHttp.send(postData); + } + } catch (ex) { + var errMsg = "AjaxAppender.append: error sending log message to " + url; + handleError(errMsg, ex); + isSupported = false; + if (failCallback) { + failCallback(errMsg + ". Details: " + getExceptionStringRep(ex)); + } + } + } + + this.append = function(loggingEvent) { + if (isSupported) { + if (!initialized) { + init(); + } + queuedLoggingEvents.push(loggingEvent); + var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1; + + if (queuedLoggingEvents.length >= actualBatchSize) { + var currentLoggingEvent; + var batchedLoggingEvents = []; + while ((currentLoggingEvent = queuedLoggingEvents.shift())) { + batchedLoggingEvents.push(currentLoggingEvent); + } + // Queue this batch of log entries + queuedRequests.push(batchedLoggingEvents); + + // If using a timer, the queue of requests will be processed by the + // timer function, so nothing needs to be done here. + if (!timed && (!waitForResponse || (waitForResponse && !sending))) { + sendAll(); + } + } + } + }; + + function init() { + initialized = true; + // Add unload event to send outstanding messages + if (sendAllOnUnload) { + var oldBeforeUnload = window.onbeforeunload; + window.onbeforeunload = function() { + if (oldBeforeUnload) { + oldBeforeUnload(); + } + if (sendAllRemaining()) { + return "Sending log messages"; + } + }; + } + // Start timer + if (timed) { + scheduleSending(); + } + } + } + + AjaxAppender.prototype = new Appender(); + + AjaxAppender.prototype.defaults = { + waitForResponse: false, + timed: false, + timerInterval: 1000, + batchSize: 1, + sendAllOnUnload: false, + requestSuccessCallback: null, + failCallback: null, + postVarName: "data", + contentType: "application/x-www-form-urlencoded" + }; + + AjaxAppender.prototype.layout = new HttpPostDataLayout(); + + AjaxAppender.prototype.toString = function() { + return "AjaxAppender"; + }; + + log4javascript.AjaxAppender = AjaxAppender; + /* ---------------------------------------------------------------------- */ + // PopUpAppender and InPageAppender related + + function setCookie(name, value, days, path) { + var expires; + path = path ? "; path=" + path : ""; + if (days) { + var date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + expires = "; expires=" + date.toGMTString(); + } else { + expires = ""; + } + document.cookie = escape(name) + "=" + escape(value) + expires + path; + } + + function getCookie(name) { + var nameEquals = escape(name) + "="; + var ca = document.cookie.split(";"); + for (var i = 0, len = ca.length; i < len; i++) { + var c = ca[i]; + while (c.charAt(0) === " ") { + c = c.substring(1, c.length); + } + if (c.indexOf(nameEquals) === 0) { + return unescape(c.substring(nameEquals.length, c.length)); + } + } + return null; + } + + // Gets the base URL of the location of the log4javascript script. + // This is far from infallible. + function getBaseUrl() { + var scripts = document.getElementsByTagName("script"); + for (var i = 0, len = scripts.length; i < len; ++i) { + if (scripts[i].src.indexOf("log4javascript") != -1) { + var lastSlash = scripts[i].src.lastIndexOf("/"); + return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1); + } + } + return null; + } + + function isLoaded(win) { + try { + return bool(win.loaded); + } catch (ex) { + return false; + } + } + + /* ---------------------------------------------------------------------- */ + // ConsoleAppender (prototype for PopUpAppender and InPageAppender) + + var ConsoleAppender; + + // Create an anonymous function to protect base console methods + (function() { + var getConsoleHtmlLines = function() { + return [ +'', +'', +' ', +' log4javascript', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +'', +' ', +'
', +'
', +'
', +' Filters:', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +'
', +' ', +'
', +' Options:', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +'
', +'
', +'
', +'
', +'
', +'
', +' ', +' ', +'
', +'
', +' ', +'', +'' +]; + }; + + var defaultCommandLineFunctions = []; + + ConsoleAppender = function() {}; + + var consoleAppenderIdCounter = 1; + ConsoleAppender.prototype = new Appender(); + + ConsoleAppender.prototype.create = function(inPage, container, + lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) { + var appender = this; + + // Common properties + var initialized = false; + var consoleWindowCreated = false; + var consoleWindowLoaded = false; + var consoleClosed = false; + + var queuedLoggingEvents = []; + var isSupported = true; + var consoleAppenderId = consoleAppenderIdCounter++; + + // Local variables + initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized); + lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit); + useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite); + var newestMessageAtTop = this.defaults.newestMessageAtTop; + var scrollToLatestMessage = this.defaults.scrollToLatestMessage; + width = width ? width : this.defaults.width; + height = height ? height : this.defaults.height; + var maxMessages = this.defaults.maxMessages; + var showCommandLine = this.defaults.showCommandLine; + var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth; + var showHideButton = this.defaults.showHideButton; + var showCloseButton = this.defaults.showCloseButton; + var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons; + + this.setLayout(this.defaults.layout); + + // Functions whose implementations vary between subclasses + var init, createWindow, safeToAppend, getConsoleWindow, open; + + // Configuration methods. The function scope is used to prevent + // direct alteration to the appender configuration properties. + var appenderName = inPage ? "InPageAppender" : "PopUpAppender"; + var checkCanConfigure = function(configOptionName) { + if (consoleWindowCreated) { + handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized"); + return false; + } + return true; + }; + + var consoleWindowExists = function() { + return (consoleWindowLoaded && isSupported && !consoleClosed); + }; + + this.isNewestMessageAtTop = function() { return newestMessageAtTop; }; + this.setNewestMessageAtTop = function(newestMessageAtTopParam) { + newestMessageAtTop = bool(newestMessageAtTopParam); + if (consoleWindowExists()) { + getConsoleWindow().setNewestAtTop(newestMessageAtTop); + } + }; + + this.isScrollToLatestMessage = function() { return scrollToLatestMessage; }; + this.setScrollToLatestMessage = function(scrollToLatestMessageParam) { + scrollToLatestMessage = bool(scrollToLatestMessageParam); + if (consoleWindowExists()) { + getConsoleWindow().setScrollToLatest(scrollToLatestMessage); + } + }; + + this.getWidth = function() { return width; }; + this.setWidth = function(widthParam) { + if (checkCanConfigure("width")) { + width = extractStringFromParam(widthParam, width); + } + }; + + this.getHeight = function() { return height; }; + this.setHeight = function(heightParam) { + if (checkCanConfigure("height")) { + height = extractStringFromParam(heightParam, height); + } + }; + + this.getMaxMessages = function() { return maxMessages; }; + this.setMaxMessages = function(maxMessagesParam) { + maxMessages = extractIntFromParam(maxMessagesParam, maxMessages); + if (consoleWindowExists()) { + getConsoleWindow().setMaxMessages(maxMessages); + } + }; + + this.isShowCommandLine = function() { return showCommandLine; }; + this.setShowCommandLine = function(showCommandLineParam) { + showCommandLine = bool(showCommandLineParam); + if (consoleWindowExists()) { + getConsoleWindow().setShowCommandLine(showCommandLine); + } + }; + + this.isShowHideButton = function() { return showHideButton; }; + this.setShowHideButton = function(showHideButtonParam) { + showHideButton = bool(showHideButtonParam); + if (consoleWindowExists()) { + getConsoleWindow().setShowHideButton(showHideButton); + } + }; + + this.isShowCloseButton = function() { return showCloseButton; }; + this.setShowCloseButton = function(showCloseButtonParam) { + showCloseButton = bool(showCloseButtonParam); + if (consoleWindowExists()) { + getConsoleWindow().setShowCloseButton(showCloseButton); + } + }; + + this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; }; + this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) { + commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth); + }; + + var minimized = initiallyMinimized; + this.isInitiallyMinimized = function() { return initiallyMinimized; }; + this.setInitiallyMinimized = function(initiallyMinimizedParam) { + if (checkCanConfigure("initiallyMinimized")) { + initiallyMinimized = bool(initiallyMinimizedParam); + minimized = initiallyMinimized; + } + }; + + this.isUseDocumentWrite = function() { return useDocumentWrite; }; + this.setUseDocumentWrite = function(useDocumentWriteParam) { + if (checkCanConfigure("useDocumentWrite")) { + useDocumentWrite = bool(useDocumentWriteParam); + } + }; + + // Common methods + function QueuedLoggingEvent(loggingEvent, formattedMessage) { + this.loggingEvent = loggingEvent; + this.levelName = loggingEvent.level.name; + this.formattedMessage = formattedMessage; + } + + QueuedLoggingEvent.prototype.append = function() { + getConsoleWindow().log(this.levelName, this.formattedMessage); + }; + + function QueuedGroup(name, initiallyExpanded) { + this.name = name; + this.initiallyExpanded = initiallyExpanded; + } + + QueuedGroup.prototype.append = function() { + getConsoleWindow().group(this.name, this.initiallyExpanded); + }; + + function QueuedGroupEnd() {} + + QueuedGroupEnd.prototype.append = function() { + getConsoleWindow().groupEnd(); + }; + + var checkAndAppend = function() { + // Next line forces a check of whether the window has been closed + safeToAppend(); + if (!initialized) { + init(); + } else if (consoleClosed && reopenWhenClosed) { + createWindow(); + } + if (safeToAppend()) { + appendQueuedLoggingEvents(); + } + }; + + this.append = function(loggingEvent) { + if (isSupported) { + // Format the message + var formattedMessage = appender.getLayout().format(loggingEvent); + if (this.getLayout().ignoresThrowable()) { + formattedMessage += loggingEvent.getThrowableStrRep(); + } + queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage)); + checkAndAppend(); + } + }; + + this.group = function(name, initiallyExpanded) { + if (isSupported) { + queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded)); + checkAndAppend(); + } + }; + + this.groupEnd = function() { + if (isSupported) { + queuedLoggingEvents.push(new QueuedGroupEnd()); + checkAndAppend(); + } + }; + + var appendQueuedLoggingEvents = function() { + var currentLoggingEvent; + while (queuedLoggingEvents.length > 0) { + queuedLoggingEvents.shift().append(); + } + if (focusConsoleWindow) { + getConsoleWindow().focus(); + } + }; + + this.setAddedToLogger = function(logger) { + this.loggers.push(logger); + if (enabled && !lazyInit) { + init(); + } + }; + + this.clear = function() { + if (consoleWindowExists()) { + getConsoleWindow().clearLog(); + } + queuedLoggingEvents.length = 0; + }; + + this.focus = function() { + if (consoleWindowExists()) { + getConsoleWindow().focus(); + } + }; + + this.focusCommandLine = function() { + if (consoleWindowExists()) { + getConsoleWindow().focusCommandLine(); + } + }; + + this.focusSearch = function() { + if (consoleWindowExists()) { + getConsoleWindow().focusSearch(); + } + }; + + var commandWindow = window; + + this.getCommandWindow = function() { return commandWindow; }; + this.setCommandWindow = function(commandWindowParam) { + commandWindow = commandWindowParam; + }; + + this.executeLastCommand = function() { + if (consoleWindowExists()) { + getConsoleWindow().evalLastCommand(); + } + }; + + var commandLayout = new PatternLayout("%m"); + this.getCommandLayout = function() { return commandLayout; }; + this.setCommandLayout = function(commandLayoutParam) { + commandLayout = commandLayoutParam; + }; + + this.evalCommandAndAppend = function(expr) { + var commandReturnValue = { appendResult: true, isError: false }; + var commandOutput = ""; + // Evaluate the command + try { + var result, i; + // The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no + // eval method on the window object initially, but once execScript has been called on + // it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25 + if (!commandWindow.eval && commandWindow.execScript) { + commandWindow.execScript("null"); + } + + var commandLineFunctionsHash = {}; + for (i = 0, len = commandLineFunctions.length; i < len; i++) { + commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1]; + } + + // Keep an array of variables that are being changed in the command window so that they + // can be restored to their original values afterwards + var objectsToRestore = []; + var addObjectToRestore = function(name) { + objectsToRestore.push([name, commandWindow[name]]); + }; + + addObjectToRestore("appender"); + commandWindow.appender = appender; + + addObjectToRestore("commandReturnValue"); + commandWindow.commandReturnValue = commandReturnValue; + + addObjectToRestore("commandLineFunctionsHash"); + commandWindow.commandLineFunctionsHash = commandLineFunctionsHash; + + var addFunctionToWindow = function(name) { + addObjectToRestore(name); + commandWindow[name] = function() { + return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue); + }; + }; + + for (i = 0, len = commandLineFunctions.length; i < len; i++) { + addFunctionToWindow(commandLineFunctions[i][0]); + } + + // Another bizarre workaround to get IE to eval in the global scope + if (commandWindow === window && commandWindow.execScript) { + addObjectToRestore("evalExpr"); + addObjectToRestore("result"); + window.evalExpr = expr; + commandWindow.execScript("window.result=eval(window.evalExpr);"); + result = window.result; + } else { + result = commandWindow.eval(expr); + } + commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth); + + // Restore variables in the command window to their original state + for (i = 0, len = objectsToRestore.length; i < len; i++) { + commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1]; + } + } catch (ex) { + commandOutput = "Error evaluating command: " + getExceptionStringRep(ex); + commandReturnValue.isError = true; + } + // Append command output + if (commandReturnValue.appendResult) { + var message = ">>> " + expr; + if (!isUndefined(commandOutput)) { + message += newLine + commandOutput; + } + var level = commandReturnValue.isError ? Level.ERROR : Level.INFO; + var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null); + var mainLayout = this.getLayout(); + this.setLayout(commandLayout); + this.append(loggingEvent); + this.setLayout(mainLayout); + } + }; + + var commandLineFunctions = defaultCommandLineFunctions.concat([]); + + this.addCommandLineFunction = function(functionName, commandLineFunction) { + commandLineFunctions.push([functionName, commandLineFunction]); + }; + + var commandHistoryCookieName = "log4javascriptCommandHistory"; + this.storeCommandHistory = function(commandHistory) { + setCookie(commandHistoryCookieName, commandHistory.join(",")); + }; + + var writeHtml = function(doc) { + var lines = getConsoleHtmlLines(); + doc.open(); + for (var i = 0, len = lines.length; i < len; i++) { + doc.writeln(lines[i]); + } + doc.close(); + }; + + // Set up event listeners + this.setEventTypes(["load", "unload"]); + + var consoleWindowLoadHandler = function() { + var win = getConsoleWindow(); + win.setAppender(appender); + win.setNewestAtTop(newestMessageAtTop); + win.setScrollToLatest(scrollToLatestMessage); + win.setMaxMessages(maxMessages); + win.setShowCommandLine(showCommandLine); + win.setShowHideButton(showHideButton); + win.setShowCloseButton(showCloseButton); + win.setMainWindow(window); + + // Restore command history stored in cookie + var storedValue = getCookie(commandHistoryCookieName); + if (storedValue) { + win.commandHistory = storedValue.split(","); + win.currentCommandIndex = win.commandHistory.length; + } + + appender.dispatchEvent("load", { "win" : win }); + }; + + this.unload = function() { + logLog.debug("unload " + this + ", caller: " + this.unload.caller); + if (!consoleClosed) { + logLog.debug("really doing unload " + this); + consoleClosed = true; + consoleWindowLoaded = false; + consoleWindowCreated = false; + appender.dispatchEvent("unload", {}); + } + }; + + var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) { + function doPoll() { + try { + // Test if the console has been closed while polling + if (consoleClosed) { + clearInterval(poll); + } + if (windowTest(getConsoleWindow())) { + clearInterval(poll); + successCallback(); + } + } catch (ex) { + clearInterval(poll); + isSupported = false; + handleError(errorMessage, ex); + } + } + + // Poll the pop-up since the onload event is not reliable + var poll = setInterval(doPoll, interval); + }; + + var getConsoleUrl = function() { + var documentDomainSet = (document.domain != location.hostname); + return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" + + (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : ""); + }; + + // Define methods and properties that vary between subclasses + if (inPage) { + // InPageAppender + + var containerElement = null; + + // Configuration methods. The function scope is used to prevent + // direct alteration to the appender configuration properties. + var cssProperties = []; + this.addCssProperty = function(name, value) { + if (checkCanConfigure("cssProperties")) { + cssProperties.push([name, value]); + } + }; + + // Define useful variables + var windowCreationStarted = false; + var iframeContainerDiv; + var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId; + + this.hide = function() { + if (initialized && consoleWindowCreated) { + if (consoleWindowExists()) { + getConsoleWindow().$("command").blur(); + } + iframeContainerDiv.style.display = "none"; + minimized = true; + } + }; + + this.show = function() { + if (initialized) { + if (consoleWindowCreated) { + iframeContainerDiv.style.display = "block"; + this.setShowCommandLine(showCommandLine); // Force IE to update + minimized = false; + } else if (!windowCreationStarted) { + createWindow(true); + } + } + }; + + this.isVisible = function() { + return !minimized && !consoleClosed; + }; + + this.close = function(fromButton) { + if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) { + iframeContainerDiv.parentNode.removeChild(iframeContainerDiv); + this.unload(); + } + }; + + // Create open, init, getConsoleWindow and safeToAppend functions + open = function() { + var initErrorMessage = "InPageAppender.open: unable to create console iframe"; + + function finalInit() { + try { + if (!initiallyMinimized) { + appender.show(); + } + consoleWindowLoadHandler(); + consoleWindowLoaded = true; + appendQueuedLoggingEvents(); + } catch (ex) { + isSupported = false; + handleError(initErrorMessage, ex); + } + } + + function writeToDocument() { + try { + var windowTest = function(win) { return isLoaded(win); }; + if (useDocumentWrite) { + writeHtml(getConsoleWindow().document); + } + if (windowTest(getConsoleWindow())) { + finalInit(); + } else { + pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage); + } + } catch (ex) { + isSupported = false; + handleError(initErrorMessage, ex); + } + } + + minimized = false; + iframeContainerDiv = containerElement.appendChild(document.createElement("div")); + + iframeContainerDiv.style.width = width; + iframeContainerDiv.style.height = height; + iframeContainerDiv.style.border = "solid gray 1px"; + + for (var i = 0, len = cssProperties.length; i < len; i++) { + iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1]; + } + + var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'"; + + // Adding an iframe using the DOM would be preferable, but it doesn't work + // in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror + // it creates the iframe fine but I haven't been able to find a way to obtain + // the iframe's window object + iframeContainerDiv.innerHTML = ""; + consoleClosed = false; + + // Write the console HTML to the iframe + var iframeDocumentExistsTest = function(win) { + try { + return bool(win) && bool(win.document); + } catch (ex) { + return false; + } + }; + if (iframeDocumentExistsTest(getConsoleWindow())) { + writeToDocument(); + } else { + pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage); + } + consoleWindowCreated = true; + }; + + createWindow = function(show) { + if (show || !initiallyMinimized) { + var pageLoadHandler = function() { + if (!container) { + // Set up default container element + containerElement = document.createElement("div"); + containerElement.style.position = "fixed"; + containerElement.style.left = "0"; + containerElement.style.right = "0"; + containerElement.style.bottom = "0"; + document.body.appendChild(containerElement); + appender.addCssProperty("borderWidth", "1px 0 0 0"); + appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be + open(); + } else { + try { + var el = document.getElementById(container); + if (el.nodeType == 1) { + containerElement = el; + } + open(); + } catch (ex) { + handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex); + } + } + }; + + // Test the type of the container supplied. First, check if it's an element + if (pageLoaded && container && container.appendChild) { + containerElement = container; + open(); + } else if (pageLoaded) { + pageLoadHandler(); + } else { + log4javascript.addEventListener("load", pageLoadHandler); + } + windowCreationStarted = true; + } + }; + + init = function() { + createWindow(); + initialized = true; + }; + + getConsoleWindow = function() { + var iframe = window.frames[iframeId]; + if (iframe) { + return iframe; + } + }; + + safeToAppend = function() { + if (isSupported && !consoleClosed) { + if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) { + consoleWindowLoaded = true; + } + return consoleWindowLoaded; + } + return false; + }; + } else { + // PopUpAppender + + // Extract params + var useOldPopUp = appender.defaults.useOldPopUp; + var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking; + var reopenWhenClosed = this.defaults.reopenWhenClosed; + + // Configuration methods. The function scope is used to prevent + // direct alteration to the appender configuration properties. + this.isUseOldPopUp = function() { return useOldPopUp; }; + this.setUseOldPopUp = function(useOldPopUpParam) { + if (checkCanConfigure("useOldPopUp")) { + useOldPopUp = bool(useOldPopUpParam); + } + }; + + this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; }; + this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) { + if (checkCanConfigure("complainAboutPopUpBlocking")) { + complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam); + } + }; + + this.isFocusPopUp = function() { return focusConsoleWindow; }; + this.setFocusPopUp = function(focusPopUpParam) { + // This property can be safely altered after logging has started + focusConsoleWindow = bool(focusPopUpParam); + }; + + this.isReopenWhenClosed = function() { return reopenWhenClosed; }; + this.setReopenWhenClosed = function(reopenWhenClosedParam) { + // This property can be safely altered after logging has started + reopenWhenClosed = bool(reopenWhenClosedParam); + }; + + this.close = function() { + logLog.debug("close " + this); + try { + popUp.close(); + this.unload(); + } catch (ex) { + // Do nothing + } + }; + + this.hide = function() { + logLog.debug("hide " + this); + if (consoleWindowExists()) { + this.close(); + } + }; + + this.show = function() { + logLog.debug("show " + this); + if (!consoleWindowCreated) { + open(); + } + }; + + this.isVisible = function() { + return safeToAppend(); + }; + + // Define useful variables + var popUp; + + // Create open, init, getConsoleWindow and safeToAppend functions + open = function() { + var windowProperties = "width=" + width + ",height=" + height + ",status,resizable"; + var frameInfo = ""; + try { + var frameEl = window.frameElement; + if (frameEl) { + frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || ""); + } + } catch (e) { + frameInfo = "_inaccessibleParentFrame"; + } + var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo; + if (!useOldPopUp || !useDocumentWrite) { + // Ensure a previous window isn't used by using a unique name + windowName = windowName + "_" + uniqueId; + } + + var checkPopUpClosed = function(win) { + if (consoleClosed) { + return true; + } else { + try { + return bool(win) && win.closed; + } catch(ex) {} + } + return false; + }; + + var popUpClosedCallback = function() { + if (!consoleClosed) { + appender.unload(); + } + }; + + function finalInit() { + getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite); + consoleWindowLoadHandler(); + consoleWindowLoaded = true; + appendQueuedLoggingEvents(); + pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback, + "PopUpAppender.checkPopUpClosed: error checking pop-up window"); + } + + try { + popUp = window.open(getConsoleUrl(), windowName, windowProperties); + consoleClosed = false; + consoleWindowCreated = true; + if (popUp && popUp.document) { + if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) { + popUp.mainPageReloaded(); + finalInit(); + } else { + if (useDocumentWrite) { + writeHtml(popUp.document); + } + // Check if the pop-up window object is available + var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); }; + if (isLoaded(popUp)) { + finalInit(); + } else { + pollConsoleWindow(popUpLoadedTest, 100, finalInit, + "PopUpAppender.init: unable to create console window"); + } + } + } else { + isSupported = false; + logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender"); + if (complainAboutPopUpBlocking) { + handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging."); + } + } + } catch (ex) { + handleError("PopUpAppender.init: error creating pop-up", ex); + } + }; + + createWindow = function() { + if (!initiallyMinimized) { + open(); + } + }; + + init = function() { + createWindow(); + initialized = true; + }; + + getConsoleWindow = function() { + return popUp; + }; + + safeToAppend = function() { + if (isSupported && !isUndefined(popUp) && !consoleClosed) { + if (popUp.closed || + (consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera + appender.unload(); + logLog.debug("PopUpAppender: pop-up closed"); + return false; + } + if (!consoleWindowLoaded && isLoaded(popUp)) { + consoleWindowLoaded = true; + } + } + return isSupported && consoleWindowLoaded && !consoleClosed; + }; + } + + // Expose getConsoleWindow so that automated tests can check the DOM + this.getConsoleWindow = getConsoleWindow; + }; + + ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) { + defaultCommandLineFunctions.push([functionName, commandLineFunction]); + }; + + /* ------------------------------------------------------------------ */ + + function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite, + width, height) { + this.create(false, null, lazyInit, initiallyMinimized, + useDocumentWrite, width, height, this.defaults.focusPopUp); + } + + PopUpAppender.prototype = new ConsoleAppender(); + + PopUpAppender.prototype.defaults = { + layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"), + initiallyMinimized: false, + focusPopUp: false, + lazyInit: true, + useOldPopUp: true, + complainAboutPopUpBlocking: true, + newestMessageAtTop: false, + scrollToLatestMessage: true, + width: "600", + height: "400", + reopenWhenClosed: false, + maxMessages: null, + showCommandLine: true, + commandLineObjectExpansionDepth: 1, + showHideButton: false, + showCloseButton: true, + showLogEntryDeleteButtons: true, + useDocumentWrite: true + }; + + PopUpAppender.prototype.toString = function() { + return "PopUpAppender"; + }; + + log4javascript.PopUpAppender = PopUpAppender; + + /* ------------------------------------------------------------------ */ + + function InPageAppender(container, lazyInit, initiallyMinimized, + useDocumentWrite, width, height) { + this.create(true, container, lazyInit, initiallyMinimized, + useDocumentWrite, width, height, false); + } + + InPageAppender.prototype = new ConsoleAppender(); + + InPageAppender.prototype.defaults = { + layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"), + initiallyMinimized: false, + lazyInit: true, + newestMessageAtTop: false, + scrollToLatestMessage: true, + width: "100%", + height: "220px", + maxMessages: null, + showCommandLine: true, + commandLineObjectExpansionDepth: 1, + showHideButton: false, + showCloseButton: false, + showLogEntryDeleteButtons: true, + useDocumentWrite: true + }; + + InPageAppender.prototype.toString = function() { + return "InPageAppender"; + }; + + log4javascript.InPageAppender = InPageAppender; + + // Next line for backwards compatibility + log4javascript.InlineAppender = InPageAppender; + })(); + /* ---------------------------------------------------------------------- */ + // Console extension functions + + function padWithSpaces(str, len) { + if (str.length < len) { + var spaces = []; + var numberOfSpaces = Math.max(0, len - str.length); + for (var i = 0; i < numberOfSpaces; i++) { + spaces[i] = " "; + } + str += spaces.join(""); + } + return str; + } + + (function() { + function dir(obj) { + var maxLen = 0; + // Obtain the length of the longest property name + for (var p in obj) { + maxLen = Math.max(toStr(p).length, maxLen); + } + // Create the nicely formatted property list + var propList = []; + for (p in obj) { + var propNameStr = " " + padWithSpaces(toStr(p), maxLen + 2); + var propVal; + try { + propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6)); + } catch (ex) { + propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]"; + } + propList.push(propNameStr + propVal); + } + return propList.join(newLine); + } + + var nodeTypes = { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }; + + var preFormattedElements = ["script", "pre"]; + + // This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD + var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"]; + var indentationUnit = " "; + + // Create and return an XHTML string from the node specified + function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) { + includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode; + if (typeof indentation != "string") { + indentation = ""; + } + startNewLine = !!startNewLine; + preformatted = !!preformatted; + var xhtml; + + function isWhitespace(node) { + return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue)); + } + + function fixAttributeValue(attrValue) { + return attrValue.toString().replace(/&/g, "&").replace(/]*>", "i"); + if (regex.test(el.outerHTML)) { + return RegExp.$1.toLowerCase(); + } + } + return ""; + } + + var lt = "<"; + var gt = ">"; + + if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) { + switch (rootNode.nodeType) { + case nodeTypes.ELEMENT_NODE: + var tagName = rootNode.tagName.toLowerCase(); + xhtml = startNewLine ? newLine + indentation : ""; + xhtml += lt; + // Allow for namespaces, where present + var prefix = getNamespace(rootNode); + var hasPrefix = !!prefix; + if (hasPrefix) { + xhtml += prefix + ":"; + } + xhtml += tagName; + for (i = 0, len = rootNode.attributes.length; i < len; i++) { + var currentAttr = rootNode.attributes[i]; + // Check the attribute is valid. + if (! currentAttr.specified || + currentAttr.nodeValue === null || + currentAttr.nodeName.toLowerCase() === "style" || + typeof currentAttr.nodeValue !== "string" || + currentAttr.nodeName.indexOf("_moz") === 0) { + continue; + } + xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\""; + xhtml += fixAttributeValue(currentAttr.nodeValue); + xhtml += "\""; + } + // Style needs to be done separately as it is not reported as an + // attribute in IE + if (rootNode.style.cssText) { + var styleValue = getStyleAttributeValue(rootNode); + if (styleValue !== "") { + xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\""; + } + } + if (array_contains(emptyElements, tagName) || + (hasPrefix && !rootNode.hasChildNodes())) { + xhtml += "/" + gt; + } else { + xhtml += gt; + // Add output for childNodes collection (which doesn't include attribute nodes) + var childStartNewLine = !(rootNode.childNodes.length === 1 && + rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE); + var childPreformatted = array_contains(preFormattedElements, tagName); + for (var i = 0, len = rootNode.childNodes.length; i < len; i++) { + xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit, + childStartNewLine, childPreformatted); + } + // Add the end tag + var endTag = lt + "/" + tagName + gt; + xhtml += childStartNewLine ? newLine + indentation + endTag : endTag; + } + return xhtml; + case nodeTypes.TEXT_NODE: + if (isWhitespace(rootNode)) { + xhtml = ""; + } else { + if (preformatted) { + xhtml = rootNode.nodeValue; + } else { + // Trim whitespace from each line of the text node + var lines = splitIntoLines(trim(rootNode.nodeValue)); + var trimmedLines = []; + for (var i = 0, len = lines.length; i < len; i++) { + trimmedLines[i] = trim(lines[i]); + } + xhtml = trimmedLines.join(newLine + indentation); + } + if (startNewLine) { + xhtml = newLine + indentation + xhtml; + } + } + return xhtml; + case nodeTypes.CDATA_SECTION_NODE: + return "" + newLine; + case nodeTypes.DOCUMENT_NODE: + xhtml = ""; + // Add output for childNodes collection (which doesn't include attribute nodes) + for (var i = 0, len = rootNode.childNodes.length; i < len; i++) { + xhtml += getXhtml(rootNode.childNodes[i], true, indentation); + } + return xhtml; + default: + return ""; + } + } else { + xhtml = ""; + // Add output for childNodes collection (which doesn't include attribute nodes) + for (var i = 0, len = rootNode.childNodes.length; i < len; i++) { + xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit); + } + return xhtml; + } + } + + function createCommandLineFunctions() { + ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) { + return document.getElementById(args[0]); + }); + + ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) { + var lines = []; + for (var i = 0, len = args.length; i < len; i++) { + lines[i] = dir(args[i]); + } + return lines.join(newLine + newLine); + }); + + ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) { + var lines = []; + for (var i = 0, len = args.length; i < len; i++) { + var win = appender.getCommandWindow(); + lines[i] = getXhtml(args[i]); + } + return lines.join(newLine + newLine); + }); + + ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) { + var win, message; + if (args.length === 0 || args[0] === "") { + win = window; + message = "Command line set to run in main window"; + } else { + if (args[0].window == args[0]) { + win = args[0]; + message = "Command line set to run in frame '" + args[0].name + "'"; + } else { + win = window.frames[args[0]]; + if (win) { + message = "Command line set to run in frame '" + args[0] + "'"; + } else { + returnValue.isError = true; + message = "Frame '" + args[0] + "' does not exist"; + win = appender.getCommandWindow(); + } + } + } + appender.setCommandWindow(win); + return message; + }); + + ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) { + returnValue.appendResult = false; + appender.clear(); + }); + + ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) { + var keys = []; + for (var k in args[0]) { + keys.push(k); + } + return keys; + }); + + ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) { + var values = []; + for (var k in args[0]) { + try { + values.push(args[0][k]); + } catch (ex) { + logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex)); + } + } + return values; + }); + + ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) { + var expansionDepth = parseInt(args[0], 10); + if (isNaN(expansionDepth) || expansionDepth < 0) { + returnValue.isError = true; + return "" + args[0] + " is not a valid expansion depth"; + } else { + appender.setCommandLineObjectExpansionDepth(expansionDepth); + return "Object expansion depth set to " + expansionDepth; + } + }); + } + + function init() { + // Add command line functions + createCommandLineFunctions(); + } + + /* ------------------------------------------------------------------ */ + + init(); + })(); + + /* ---------------------------------------------------------------------- */ + // Main load + + log4javascript.setDocumentReady = function() { + pageLoaded = true; + log4javascript.dispatchEvent("load", {}); + }; + + if (window.addEventListener) { + window.addEventListener("load", log4javascript.setDocumentReady, false); + } else if (window.attachEvent) { + window.attachEvent("onload", log4javascript.setDocumentReady); + } else { + var oldOnload = window.onload; + if (typeof window.onload != "function") { + window.onload = log4javascript.setDocumentReady; + } else { + window.onload = function(evt) { + if (oldOnload) { + oldOnload(evt); + } + log4javascript.setDocumentReady(); + }; + } + } + + // Ensure that the log4javascript object is available in the window. This + // is necessary for log4javascript to be available in IE if loaded using + // Dojo's module system + window.log4javascript = log4javascript; + + return log4javascript; +})(); \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js new file mode 100644 index 0000000..eae582b --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js @@ -0,0 +1,23 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};} +function copy(obj,props){for(var i in props){obj[i]=props[i];}} +var f=ff();var Logger=ff();copy(Logger.prototype,{addChild:f,getEffectiveAppenders:f,invalidateAppenderCache:f,getAdditivity:f,setAdditivity:f,addAppender:f,removeAppender:f,removeAllAppenders:f,log:f,setLevel:f,getLevel:f,getEffectiveLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f,callAppenders:f,group:f,groupEnd:f,time:f,timeEnd:f,assert:f,parent:new Logger()});var getLogger=function(){return new Logger();};function EventSupport(){} +copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){} +Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript",setDocumentReady:f,setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{},logLog:{setQuietMode:f,setAlertAllErrors:f,debug:f,displayDebug:f,warn:f,error:f},handleError:f,setEnabled:f,isEnabled:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,evalInScope:f,setShowStackTraces:f,getLogger:getLogger,getDefaultLogger:getLogger,getNullLogger:getLogger,getRootLogger:getLogger,resetConfiguration:f,Level:ff(),LoggingEvent:ff(),Layout:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Layout.prototype={defaults:{},format:f,ignoresThrowable:f,getContentType:f,allowBatching:f,getDataValues:f,setKeys:f,setCustomField:f,hasCustomFields:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,getTimeStampValue:f,toString:f};log4javascript.SimpleDateFormat=ff();log4javascript.SimpleDateFormat.prototype={setMinimalDaysInFirstWeek:f,getMinimalDaysInFirstWeek:f,format:f};log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.Appender=ff();log4javascript.Appender.prototype=new EventSupport();copy(log4javascript.Appender.prototype,{layout:new log4javascript.PatternLayout(),threshold:log4javascript.Level.ALL,loggers:[],doAppend:f,append:f,setLayout:f,getLayout:f,setThreshold:f,getThreshold:f,setAddedToLogger:f,setRemovedFromLogger:f,group:f,groupEnd:f,toString:f});log4javascript.SimpleLayout=ff();log4javascript.SimpleLayout.prototype=new log4javascript.Layout();log4javascript.NullLayout=ff();log4javascript.NullLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout=ff();log4javascript.XmlLayout.prototype=new log4javascript.Layout();copy(log4javascript.XmlLayout.prototype,{escapeCdata:f,isCombinedMessages:f});log4javascript.JsonLayout=ff();log4javascript.JsonLayout.prototype=new log4javascript.Layout();copy(log4javascript.JsonLayout.prototype,{isReadable:f,isCombinedMessages:f});log4javascript.HttpPostDataLayout=ff();log4javascript.HttpPostDataLayout.prototype=new log4javascript.Layout();log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.AlertAppender=ff();log4javascript.AlertAppender.prototype=new log4javascript.Appender();log4javascript.BrowserConsoleAppender=ff();log4javascript.BrowserConsoleAppender.prototype=new log4javascript.Appender();log4javascript.AjaxAppender=ff();log4javascript.AjaxAppender.prototype=new log4javascript.Appender();copy(log4javascript.AjaxAppender.prototype,{getSessionId:f,setSessionId:f,isTimed:f,setTimed:f,getTimerInterval:f,setTimerInterval:f,isWaitForResponse:f,setWaitForResponse:f,getBatchSize:f,setBatchSize:f,isSendAllOnUnload:f,setSendAllOnUnload:f,setRequestSuccessCallback:f,setFailCallback:f,getPostVarName:f,setPostVarName:f,sendAll:f,sendAllRemaining:f,defaults:{requestSuccessCallback:null,failCallback:null}});function ConsoleAppender(){} +ConsoleAppender.prototype=new log4javascript.Appender();copy(ConsoleAppender.prototype,{create:f,isNewestMessageAtTop:f,setNewestMessageAtTop:f,isScrollToLatestMessage:f,setScrollToLatestMessage:f,getWidth:f,setWidth:f,getHeight:f,setHeight:f,getMaxMessages:f,setMaxMessages:f,isShowCommandLine:f,setShowCommandLine:f,isShowHideButton:f,setShowHideButton:f,isShowCloseButton:f,setShowCloseButton:f,getCommandLineObjectExpansionDepth:f,setCommandLineObjectExpansionDepth:f,isInitiallyMinimized:f,setInitiallyMinimized:f,isUseDocumentWrite:f,setUseDocumentWrite:f,group:f,groupEnd:f,clear:f,focus:f,focusCommandLine:f,focusSearch:f,getCommandWindow:f,setCommandWindow:f,executeLastCommand:f,getCommandLayout:f,setCommandLayout:f,evalCommandAndAppend:f,addCommandLineFunction:f,storeCommandHistory:f,unload:f});ConsoleAppender.addGlobalCommandLineFunction=f;log4javascript.InPageAppender=ff();log4javascript.InPageAppender.prototype=new ConsoleAppender();copy(log4javascript.InPageAppender.prototype,{addCssProperty:f,hide:f,show:f,isVisible:f,close:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});log4javascript.InlineAppender=log4javascript.InPageAppender;log4javascript.PopUpAppender=ff();log4javascript.PopUpAppender.prototype=new ConsoleAppender();copy(log4javascript.PopUpAppender.prototype,{isUseOldPopUp:f,setUseOldPopUp:f,isComplainAboutPopUpBlocking:f,setComplainAboutPopUpBlocking:f,isFocusPopUp:f,setFocusPopUp:f,isReopenWhenClosed:f,setReopenWhenClosed:f,close:f,hide:f,show:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;} diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js new file mode 100644 index 0000000..7d2ea14 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js @@ -0,0 +1,21 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};} +function copy(obj,props){for(var i in props){obj[i]=props[i];}} +var f=ff();var Logger=ff();copy(Logger.prototype,{setLevel:f,getLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f});var getLogger=function(){return new Logger();};function Log4JavaScript(){} +log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript_lite",setEnabled:f,isEnabled:f,setShowStackTraces:f,getDefaultLogger:getLogger,getLogger:getLogger,getNullLogger:getLogger,Level:ff(),LoggingEvent:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Appender.prototype.append=f;return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;} diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js new file mode 100644 index 0000000..afb9ba7 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js @@ -0,0 +1,102 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var log4javascript_stub = (function() { + var log4javascript; + + function ff() { + return function() {}; + } + function copy(obj, props) { + for (var i in props) { + obj[i] = props[i]; + } + } + var f = ff(); + + // Loggers + var Logger = ff(); + copy(Logger.prototype, { + setLevel: f, + getLevel: f, + trace: f, + debug: f, + info: f, + warn: f, + error: f, + fatal: f, + isEnabledFor: f, + isTraceEnabled: f, + isDebugEnabled: f, + isInfoEnabled: f, + isWarnEnabled: f, + isErrorEnabled: f, + isFatalEnabled: f + }); + + var getLogger = function() { + return new Logger(); + }; + + function Log4JavaScript() {} + log4javascript = new Log4JavaScript(); + + log4javascript = { + isStub: true, + version: "1.4.6", + edition: "log4javascript_lite", + setEnabled: f, + isEnabled: f, + setShowStackTraces: f, + getDefaultLogger: getLogger, + getLogger: getLogger, + getNullLogger: getLogger, + Level: ff(), + LoggingEvent: ff(), + Appender: ff() + }; + + // LoggingEvents + log4javascript.LoggingEvent.prototype = { + getThrowableStrRep: f, + getCombinedMessages: f + }; + + // Levels + log4javascript.Level.prototype = { + toString: f, + equals: f, + isGreaterOrEqual: f + }; + var level = new log4javascript.Level(); + copy(log4javascript.Level, { + ALL: level, + TRACE: level, + DEBUG: level, + INFO: level, + WARN: level, + ERROR: level, + FATAL: level, + OFF: level + }); + + log4javascript.Appender.prototype.append = f; + + return log4javascript; +})(); +if (typeof window.log4javascript == "undefined") { + var log4javascript = log4javascript_stub; +} diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js new file mode 100644 index 0000000..69a90a8 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js @@ -0,0 +1,22 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};} +function copy(obj,props){for(var i in props){obj[i]=props[i];}} +var f=ff();var Logger=ff();copy(Logger.prototype,{addChild:f,getEffectiveAppenders:f,invalidateAppenderCache:f,getAdditivity:f,setAdditivity:f,addAppender:f,removeAppender:f,removeAllAppenders:f,log:f,setLevel:f,getLevel:f,getEffectiveLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f,callAppenders:f,group:f,groupEnd:f,time:f,timeEnd:f,assert:f,parent:new Logger()});var getLogger=function(){return new Logger();};function EventSupport(){} +copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){} +Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript_production",setDocumentReady:f,setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{},logLog:{setQuietMode:f,setAlertAllErrors:f,debug:f,displayDebug:f,warn:f,error:f},handleError:f,setEnabled:f,isEnabled:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,evalInScope:f,setShowStackTraces:f,getLogger:getLogger,getDefaultLogger:getLogger,getNullLogger:getLogger,getRootLogger:getLogger,resetConfiguration:f,Level:ff(),LoggingEvent:ff(),Layout:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Layout.prototype={defaults:{},format:f,ignoresThrowable:f,getContentType:f,allowBatching:f,getDataValues:f,setKeys:f,setCustomField:f,hasCustomFields:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,getTimeStampValue:f,toString:f};log4javascript.SimpleDateFormat=ff();log4javascript.SimpleDateFormat.prototype={setMinimalDaysInFirstWeek:f,getMinimalDaysInFirstWeek:f,format:f};log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.Appender=ff();log4javascript.Appender.prototype=new EventSupport();copy(log4javascript.Appender.prototype,{layout:new log4javascript.PatternLayout(),threshold:log4javascript.Level.ALL,loggers:[],doAppend:f,append:f,setLayout:f,getLayout:f,setThreshold:f,getThreshold:f,setAddedToLogger:f,setRemovedFromLogger:f,group:f,groupEnd:f,toString:f});log4javascript.SimpleLayout=ff();log4javascript.SimpleLayout.prototype=new log4javascript.Layout();log4javascript.NullLayout=ff();log4javascript.NullLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout=ff();log4javascript.XmlLayout.prototype=new log4javascript.Layout();copy(log4javascript.XmlLayout.prototype,{escapeCdata:f,isCombinedMessages:f});log4javascript.JsonLayout=ff();log4javascript.JsonLayout.prototype=new log4javascript.Layout();copy(log4javascript.JsonLayout.prototype,{isReadable:f,isCombinedMessages:f});log4javascript.HttpPostDataLayout=ff();log4javascript.HttpPostDataLayout.prototype=new log4javascript.Layout();log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.AjaxAppender=ff();log4javascript.AjaxAppender.prototype=new log4javascript.Appender();copy(log4javascript.AjaxAppender.prototype,{getSessionId:f,setSessionId:f,isTimed:f,setTimed:f,getTimerInterval:f,setTimerInterval:f,isWaitForResponse:f,setWaitForResponse:f,getBatchSize:f,setBatchSize:f,isSendAllOnUnload:f,setSendAllOnUnload:f,setRequestSuccessCallback:f,setFailCallback:f,getPostVarName:f,setPostVarName:f,sendAll:f,sendAllRemaining:f,defaults:{requestSuccessCallback:null,failCallback:null}});return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;} diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js new file mode 100644 index 0000000..79eb7ca --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js @@ -0,0 +1,253 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var log4javascript_stub = (function() { + var log4javascript; + + function ff() { + return function() {}; + } + function copy(obj, props) { + for (var i in props) { + obj[i] = props[i]; + } + } + var f = ff(); + + // Loggers + var Logger = ff(); + copy(Logger.prototype, { + addChild: f, + getEffectiveAppenders: f, + invalidateAppenderCache: f, + getAdditivity: f, + setAdditivity: f, + addAppender: f, + removeAppender: f, + removeAllAppenders: f, + log: f, + setLevel: f, + getLevel: f, + getEffectiveLevel: f, + trace: f, + debug: f, + info: f, + warn: f, + error: f, + fatal: f, + isEnabledFor: f, + isTraceEnabled: f, + isDebugEnabled: f, + isInfoEnabled: f, + isWarnEnabled: f, + isErrorEnabled: f, + isFatalEnabled: f, + callAppenders: f, + group: f, + groupEnd: f, + time: f, + timeEnd: f, + assert: f, + parent: new Logger() + }); + + var getLogger = function() { + return new Logger(); + }; + + function EventSupport() {} + + copy(EventSupport.prototype, { + setEventTypes: f, + addEventListener: f, + removeEventListener: f, + dispatchEvent: f, + eventTypes: [], + eventListeners: {} + }); + + function Log4JavaScript() {} + Log4JavaScript.prototype = new EventSupport(); + log4javascript = new Log4JavaScript(); + + log4javascript = { + isStub: true, + version: "1.4.6", + edition: "log4javascript_production", + setDocumentReady: f, + setEventTypes: f, + addEventListener: f, + removeEventListener: f, + dispatchEvent: f, + eventTypes: [], + eventListeners: {}, + logLog: { + setQuietMode: f, + setAlertAllErrors: f, + debug: f, + displayDebug: f, + warn: f, + error: f + }, + handleError: f, + setEnabled: f, + isEnabled: f, + setTimeStampsInMilliseconds: f, + isTimeStampsInMilliseconds: f, + evalInScope: f, + setShowStackTraces: f, + getLogger: getLogger, + getDefaultLogger: getLogger, + getNullLogger: getLogger, + getRootLogger: getLogger, + resetConfiguration: f, + Level: ff(), + LoggingEvent: ff(), + Layout: ff(), + Appender: ff() + }; + + // LoggingEvents + log4javascript.LoggingEvent.prototype = { + getThrowableStrRep: f, + getCombinedMessages: f + }; + + // Levels + log4javascript.Level.prototype = { + toString: f, + equals: f, + isGreaterOrEqual: f + }; + var level = new log4javascript.Level(); + copy(log4javascript.Level, { + ALL: level, + TRACE: level, + DEBUG: level, + INFO: level, + WARN: level, + ERROR: level, + FATAL: level, + OFF: level + }); + + // Layouts + log4javascript.Layout.prototype = { + defaults: {}, + format: f, + ignoresThrowable: f, + getContentType: f, + allowBatching: f, + getDataValues: f, + setKeys: f, + setCustomField: f, + hasCustomFields: f, + setTimeStampsInMilliseconds: f, + isTimeStampsInMilliseconds: f, + getTimeStampValue: f, + toString: f + }; + + // PatternLayout related + log4javascript.SimpleDateFormat = ff(); + log4javascript.SimpleDateFormat.prototype = { + setMinimalDaysInFirstWeek: f, + getMinimalDaysInFirstWeek: f, + format: f + }; + + // PatternLayout + log4javascript.PatternLayout = ff(); + log4javascript.PatternLayout.prototype = new log4javascript.Layout(); + + // Appenders + log4javascript.Appender = ff(); + log4javascript.Appender.prototype = new EventSupport(); + + copy(log4javascript.Appender.prototype, { + layout: new log4javascript.PatternLayout(), + threshold: log4javascript.Level.ALL, + loggers: [], + doAppend: f, + append: f, + setLayout: f, + getLayout: f, + setThreshold: f, + getThreshold: f, + setAddedToLogger: f, + setRemovedFromLogger: f, + group: f, + groupEnd: f, + toString: f + }); + // SimpleLayout + log4javascript.SimpleLayout = ff(); + log4javascript.SimpleLayout.prototype = new log4javascript.Layout(); + // NullLayout + log4javascript.NullLayout = ff(); + log4javascript.NullLayout.prototype = new log4javascript.Layout(); + // ZmlLayout + log4javascript.XmlLayout = ff(); + log4javascript.XmlLayout.prototype = new log4javascript.Layout(); + copy(log4javascript.XmlLayout.prototype, { + escapeCdata: f, + isCombinedMessages: f + }); + // JsonLayout + log4javascript.JsonLayout = ff(); + log4javascript.JsonLayout.prototype = new log4javascript.Layout(); + copy(log4javascript.JsonLayout.prototype, { + isReadable: f, + isCombinedMessages: f + }); + // HttpPostDataLayout + log4javascript.HttpPostDataLayout = ff(); + log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout(); + // PatternLayout + log4javascript.PatternLayout = ff(); + log4javascript.PatternLayout.prototype = new log4javascript.Layout(); + // AjaxAppender + log4javascript.AjaxAppender = ff(); + log4javascript.AjaxAppender.prototype = new log4javascript.Appender(); + copy(log4javascript.AjaxAppender.prototype, { + getSessionId: f, + setSessionId: f, + isTimed: f, + setTimed: f, + getTimerInterval: f, + setTimerInterval: f, + isWaitForResponse: f, + setWaitForResponse: f, + getBatchSize: f, + setBatchSize: f, + isSendAllOnUnload: f, + setSendAllOnUnload: f, + setRequestSuccessCallback: f, + setFailCallback: f, + getPostVarName: f, + setPostVarName: f, + sendAll: f, + sendAllRemaining: f, + defaults: { + requestSuccessCallback: null, + failCallback: null + } + }); + return log4javascript; +})(); +if (typeof window.log4javascript == "undefined") { + var log4javascript = log4javascript_stub; +} diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js new file mode 100644 index 0000000..1976fbc --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js @@ -0,0 +1,341 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var log4javascript_stub = (function() { + var log4javascript; + + function ff() { + return function() {}; + } + function copy(obj, props) { + for (var i in props) { + obj[i] = props[i]; + } + } + var f = ff(); + + // Loggers + var Logger = ff(); + copy(Logger.prototype, { + addChild: f, + getEffectiveAppenders: f, + invalidateAppenderCache: f, + getAdditivity: f, + setAdditivity: f, + addAppender: f, + removeAppender: f, + removeAllAppenders: f, + log: f, + setLevel: f, + getLevel: f, + getEffectiveLevel: f, + trace: f, + debug: f, + info: f, + warn: f, + error: f, + fatal: f, + isEnabledFor: f, + isTraceEnabled: f, + isDebugEnabled: f, + isInfoEnabled: f, + isWarnEnabled: f, + isErrorEnabled: f, + isFatalEnabled: f, + callAppenders: f, + group: f, + groupEnd: f, + time: f, + timeEnd: f, + assert: f, + parent: new Logger() + }); + + var getLogger = function() { + return new Logger(); + }; + + function EventSupport() {} + + copy(EventSupport.prototype, { + setEventTypes: f, + addEventListener: f, + removeEventListener: f, + dispatchEvent: f, + eventTypes: [], + eventListeners: {} + }); + + function Log4JavaScript() {} + Log4JavaScript.prototype = new EventSupport(); + log4javascript = new Log4JavaScript(); + + log4javascript = { + isStub: true, + version: "1.4.6", + edition: "log4javascript", + setDocumentReady: f, + setEventTypes: f, + addEventListener: f, + removeEventListener: f, + dispatchEvent: f, + eventTypes: [], + eventListeners: {}, + logLog: { + setQuietMode: f, + setAlertAllErrors: f, + debug: f, + displayDebug: f, + warn: f, + error: f + }, + handleError: f, + setEnabled: f, + isEnabled: f, + setTimeStampsInMilliseconds: f, + isTimeStampsInMilliseconds: f, + evalInScope: f, + setShowStackTraces: f, + getLogger: getLogger, + getDefaultLogger: getLogger, + getNullLogger: getLogger, + getRootLogger: getLogger, + resetConfiguration: f, + Level: ff(), + LoggingEvent: ff(), + Layout: ff(), + Appender: ff() + }; + + // LoggingEvents + log4javascript.LoggingEvent.prototype = { + getThrowableStrRep: f, + getCombinedMessages: f + }; + + // Levels + log4javascript.Level.prototype = { + toString: f, + equals: f, + isGreaterOrEqual: f + }; + var level = new log4javascript.Level(); + copy(log4javascript.Level, { + ALL: level, + TRACE: level, + DEBUG: level, + INFO: level, + WARN: level, + ERROR: level, + FATAL: level, + OFF: level + }); + + // Layouts + log4javascript.Layout.prototype = { + defaults: {}, + format: f, + ignoresThrowable: f, + getContentType: f, + allowBatching: f, + getDataValues: f, + setKeys: f, + setCustomField: f, + hasCustomFields: f, + setTimeStampsInMilliseconds: f, + isTimeStampsInMilliseconds: f, + getTimeStampValue: f, + toString: f + }; + + // PatternLayout related + log4javascript.SimpleDateFormat = ff(); + log4javascript.SimpleDateFormat.prototype = { + setMinimalDaysInFirstWeek: f, + getMinimalDaysInFirstWeek: f, + format: f + }; + + // PatternLayout + log4javascript.PatternLayout = ff(); + log4javascript.PatternLayout.prototype = new log4javascript.Layout(); + + // Appenders + log4javascript.Appender = ff(); + log4javascript.Appender.prototype = new EventSupport(); + + copy(log4javascript.Appender.prototype, { + layout: new log4javascript.PatternLayout(), + threshold: log4javascript.Level.ALL, + loggers: [], + doAppend: f, + append: f, + setLayout: f, + getLayout: f, + setThreshold: f, + getThreshold: f, + setAddedToLogger: f, + setRemovedFromLogger: f, + group: f, + groupEnd: f, + toString: f + }); + // SimpleLayout + log4javascript.SimpleLayout = ff(); + log4javascript.SimpleLayout.prototype = new log4javascript.Layout(); + // NullLayout + log4javascript.NullLayout = ff(); + log4javascript.NullLayout.prototype = new log4javascript.Layout(); + // ZmlLayout + log4javascript.XmlLayout = ff(); + log4javascript.XmlLayout.prototype = new log4javascript.Layout(); + copy(log4javascript.XmlLayout.prototype, { + escapeCdata: f, + isCombinedMessages: f + }); + // JsonLayout + log4javascript.JsonLayout = ff(); + log4javascript.JsonLayout.prototype = new log4javascript.Layout(); + copy(log4javascript.JsonLayout.prototype, { + isReadable: f, + isCombinedMessages: f + }); + // HttpPostDataLayout + log4javascript.HttpPostDataLayout = ff(); + log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout(); + // PatternLayout + log4javascript.PatternLayout = ff(); + log4javascript.PatternLayout.prototype = new log4javascript.Layout(); + // AlertAppender + log4javascript.AlertAppender = ff(); + log4javascript.AlertAppender.prototype = new log4javascript.Appender(); + // BrowserConsoleAppender + log4javascript.BrowserConsoleAppender = ff(); + log4javascript.BrowserConsoleAppender.prototype = new log4javascript.Appender(); + // AjaxAppender + log4javascript.AjaxAppender = ff(); + log4javascript.AjaxAppender.prototype = new log4javascript.Appender(); + copy(log4javascript.AjaxAppender.prototype, { + getSessionId: f, + setSessionId: f, + isTimed: f, + setTimed: f, + getTimerInterval: f, + setTimerInterval: f, + isWaitForResponse: f, + setWaitForResponse: f, + getBatchSize: f, + setBatchSize: f, + isSendAllOnUnload: f, + setSendAllOnUnload: f, + setRequestSuccessCallback: f, + setFailCallback: f, + getPostVarName: f, + setPostVarName: f, + sendAll: f, + sendAllRemaining: f, + defaults: { + requestSuccessCallback: null, + failCallback: null + } + }); + // ConsoleAppender + function ConsoleAppender() {} + ConsoleAppender.prototype = new log4javascript.Appender(); + copy(ConsoleAppender.prototype, { + create: f, + isNewestMessageAtTop: f, + setNewestMessageAtTop: f, + isScrollToLatestMessage: f, + setScrollToLatestMessage: f, + getWidth: f, + setWidth: f, + getHeight: f, + setHeight: f, + getMaxMessages: f, + setMaxMessages: f, + isShowCommandLine: f, + setShowCommandLine: f, + isShowHideButton: f, + setShowHideButton: f, + isShowCloseButton: f, + setShowCloseButton: f, + getCommandLineObjectExpansionDepth: f, + setCommandLineObjectExpansionDepth: f, + isInitiallyMinimized: f, + setInitiallyMinimized: f, + isUseDocumentWrite: f, + setUseDocumentWrite: f, + group: f, + groupEnd: f, + clear: f, + focus: f, + focusCommandLine: f, + focusSearch: f, + getCommandWindow: f, + setCommandWindow: f, + executeLastCommand: f, + getCommandLayout: f, + setCommandLayout: f, + evalCommandAndAppend: f, + addCommandLineFunction: f, + storeCommandHistory: f, + unload: f + }); + + ConsoleAppender.addGlobalCommandLineFunction = f; + + // InPageAppender + log4javascript.InPageAppender = ff(); + log4javascript.InPageAppender.prototype = new ConsoleAppender(); + copy(log4javascript.InPageAppender.prototype, { + addCssProperty: f, + hide: f, + show: f, + isVisible: f, + close: f, + defaults: { + layout: new log4javascript.PatternLayout(), + maxMessages: null + } + }); + log4javascript.InlineAppender = log4javascript.InPageAppender; + + // PopUpAppender + log4javascript.PopUpAppender = ff(); + log4javascript.PopUpAppender.prototype = new ConsoleAppender(); + copy(log4javascript.PopUpAppender.prototype, { + isUseOldPopUp: f, + setUseOldPopUp: f, + isComplainAboutPopUpBlocking: f, + setComplainAboutPopUpBlocking: f, + isFocusPopUp: f, + setFocusPopUp: f, + isReopenWhenClosed: f, + setReopenWhenClosed: f, + close: f, + hide: f, + show: f, + defaults: { + layout: new log4javascript.PatternLayout(), + maxMessages: null + } + }); + return log4javascript; +})(); +if (typeof window.log4javascript == "undefined") { + var log4javascript = log4javascript_stub; +} diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript.js new file mode 100644 index 0000000..89fd903 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript.js @@ -0,0 +1,32 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +function array_contains(arr,val){for(var i=0;i\s*<\/log4javascript:message>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});s.test("XmlLayout with exception test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^\s*<\/log4javascript:message>\s*\s*<\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});var setUpXmlLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.XmlLayout();} +s.test("XmlLayout seconds/milliseconds test 1",function(t){setUpXmlLayoutMillisecondsTest(t);var regex=new RegExp('^\\s*\\s*\\s*$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("XmlLayout seconds/milliseconds test 2",function(t){setUpXmlLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^\\s*\\s*\\s*$');t.assertRegexMatches(regex,formatted);});s.test("XmlLayout seconds/milliseconds test 3",function(t){setUpXmlLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^\\s*\\s*\\s*$');t.assertRegexMatches(regex,formatted);});s.test("escapeNewLines test",function(t){var escapeNewLines=log4javascript.evalInScope("escapeNewLines");var str="1\r2\n3\n4\r\n5\r6\r\n7";t.assertEquals(escapeNewLines(str),"1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");});s.test("JsonLayout format test",function(t){var layout=new log4javascript.JsonLayout();testLayoutWithVariables(layout,t);});s.test("JsonLayout test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/,t.appender.logMessages[0]);});s.test("JsonLayout JSON validity test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");eval("var o = "+t.appender.logMessages[0]);t.assertEquals(o.message,"TEST");});s.test("JsonLayout with number type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(15);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/,t.appender.logMessages[0]);});s.test("JsonLayout with object type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug({});t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with boolean type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(false);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/,t.appender.logMessages[0]);});s.test("JsonLayout with quote test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TE\"S\"T");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with exception test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/,t.appender.logMessages[0]);});var setUpJsonLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.JsonLayout();};s.test("JsonLayout seconds/milliseconds test 1",function(t){setUpJsonLayoutMillisecondsTest(t);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInMilliseconds+',"level":"DEBUG","url":".*","message":"TEST"}$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("JsonLayout seconds/milliseconds test 2",function(t){setUpJsonLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("JsonLayout seconds/milliseconds test 3",function(t){setUpJsonLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("HttpPostDataLayout format test",function(t){var layout=new log4javascript.HttpPostDataLayout();testLayoutWithVariables(layout,t);});s.test("HttpPostDataLayout test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST");t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout URL encoding test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST +\"1\"");t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout with exception test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/,t.appender.logMessages[0]);});(function(){var formatObjectExpansion=log4javascript.evalInScope("formatObjectExpansion");var newLine=log4javascript.evalInScope("newLine");var arr=[null,undefined,1.2,"A string",[1,"test"],{a:{b:1}}];s.test("Basic formatObjectExpansion array test (depth: 1)",function(t){t.assertEquals(formatObjectExpansion(arr,1),"["+newLine+" null,"+newLine+" undefined,"+newLine+" 1.2,"+newLine+" A string,"+newLine+" 1,test,"+newLine+" [object Object]"+newLine+"]");});s.test("Basic formatObjectExpansion array test (depth: 2)",function(t){t.assertEquals(formatObjectExpansion(arr,2),"["+newLine+" null,"+newLine+" undefined,"+newLine+" 1.2,"+newLine+" A string,"+newLine+" ["+newLine+" 1,"+newLine+" test"+newLine+" ],"+newLine+" {"+newLine+" a: [object Object]"+newLine+" }"+newLine+"]");});s.test("formatObjectExpansion simple object test",function(t){var obj={STRING:"A string"};t.assertEquals(formatObjectExpansion(obj,1),"{"+newLine+" STRING: A string"+newLine+"}");});s.test("formatObjectExpansion simple circular object test",function(t){var obj={};obj.a=obj;t.assertEquals(formatObjectExpansion(obj,2),"{"+newLine+" a: [object Object] [already expanded]"+newLine+"}");});})();var getSampleDate=function(){var date=new Date();date.setFullYear(2006);date.setMonth(7);date.setDate(30);date.setHours(15);date.setMinutes(38);date.setSeconds(45);return date;};s.test("String.replace test",function(t){t.assertEquals("Hello world".replace(/o/g,"Z"),"HellZ wZrld");});s.test("PatternLayout format test",function(t){var layout=new log4javascript.PatternLayout();testLayoutWithVariables(layout,t);});s.test("PatternLayout dates test",function(t){var layout=new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/,t.appender.logMessages[0]);});s.test("PatternLayout modifiers test",function(t){var layout=new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST|TEST|TEST| TEST|TEST |ST|ST| TEST|ST|TEST |");});s.test("PatternLayout conversion characters test",function(t){var layout=new log4javascript.PatternLayout("%c %n %p %r literal %%");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/,t.appender.logMessages[0]);});s.test("PatternLayout message test",function(t){var layout=new log4javascript.PatternLayout("%m{1} %m{2}");t.appender.setLayout(layout);var testObj={strikers:{quick:"Marlon"}};t.logger.debug(testObj);t.assertEquals("{\r\n strikers: [object Object]\r\n} {\r\n\ strikers: {\r\n quick: Marlon\r\n }\r\n}",t.appender.logMessages[0]);});s.test("Logging/grouping test",function(t){var browserConsoleAppender=new log4javascript.BrowserConsoleAppender();t.logger.addAppender(browserConsoleAppender);t.logger.trace("TEST TRACE");t.logger.debug("TEST DEBUG");t.logger.info("TEST INFO");t.logger.warn("TEST WARN");t.logger.error("TEST ERROR");t.logger.fatal("TEST FATAL");t.logger.fatal("TEST FATAL",new Error("Fake error"));t.logger.info("TEST INFO","Second message",["a","b","c"]);t.logger.group("TEST GROUP");t.logger.info("TEST INFO");t.logger.groupEnd("TEST GROUP");t.logger.info("TEST INFO");t.logger.removeAppender(browserConsoleAppender);});var testConsoleAppender=function(t,appender){var timeoutCallback=function(){return(windowLoaded?"Timed out while waiting for messages to appear":"Timed out while waiting for window to load")+". Debug messages: "+ +log4javascript.logLog.debugMessages.join("\r\n");} +t.async(60000,timeoutCallback);var windowLoaded=false;var domChecked=false;var onLoadHandler=function(){log4javascript.logLog.debug("onLoadHandler");windowLoaded=true;var win=appender.getConsoleWindow();if(win&&win.loaded){var checkDom=function(){log4javascript.logLog.debug("checkDom");domChecked=true;var logContainer=win.logMainContainer;if(logContainer.hasChildNodes()){if(logContainer.innerHTML.indexOf("TEST MESSAGE")==-1){appender.close();t.fail("Log message not correctly logged (log container innerHTML: "+logContainer.innerHTML+")");}else{t.assert(appender.isVisible());appender.close();t.assert(!appender.isVisible());t.succeed();}}else{appender.close();t.fail("Console has no log messages");}} +window.setTimeout(checkDom,300);}else{appender.close();t.fail("Console mistakenly raised load event");}} +appender.addEventListener("load",onLoadHandler);t.logger.addAppender(appender);t.logger.debug("TEST MESSAGE");};s.test("InlineAppender test",function(t){var inlineAppender=new log4javascript.InlineAppender();inlineAppender.setInitiallyMinimized(false);inlineAppender.setNewestMessageAtTop(false);inlineAppender.setScrollToLatestMessage(true);inlineAppender.setWidth(600);inlineAppender.setHeight(200);testConsoleAppender(t,inlineAppender);});s.test("InPageAppender with separate console HTML file test",function(t){var inPageAppender=new log4javascript.InPageAppender();inPageAppender.setInitiallyMinimized(false);inPageAppender.setNewestMessageAtTop(false);inPageAppender.setScrollToLatestMessage(true);inPageAppender.setUseDocumentWrite(false);inPageAppender.setWidth(600);inPageAppender.setHeight(200);testConsoleAppender(t,inPageAppender);});s.test("PopUpAppender test",function(t){var popUpAppender=new log4javascript.PopUpAppender();popUpAppender.setFocusPopUp(true);popUpAppender.setUseOldPopUp(false);popUpAppender.setNewestMessageAtTop(false);popUpAppender.setScrollToLatestMessage(true);popUpAppender.setComplainAboutPopUpBlocking(false);popUpAppender.setWidth(600);popUpAppender.setHeight(200);testConsoleAppender(t,popUpAppender);});s.test("PopUpAppender with separate console HTML file test",function(t){var popUpAppender=new log4javascript.PopUpAppender();popUpAppender.setFocusPopUp(true);popUpAppender.setUseOldPopUp(false);popUpAppender.setNewestMessageAtTop(false);popUpAppender.setScrollToLatestMessage(true);popUpAppender.setComplainAboutPopUpBlocking(false);popUpAppender.setUseDocumentWrite(false);popUpAppender.setWidth(600);popUpAppender.setHeight(200);testConsoleAppender(t,popUpAppender);});}); diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js new file mode 100644 index 0000000..b9eb6b7 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js @@ -0,0 +1,16 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js new file mode 100644 index 0000000..b9eb6b7 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js @@ -0,0 +1,16 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js new file mode 100644 index 0000000..f5d1090 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js @@ -0,0 +1,28 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +function array_contains(arr,val){for(var i=0;i\s*<\/log4javascript:message>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});s.test("XmlLayout with exception test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^\s*<\/log4javascript:message>\s*\s*<\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});var setUpXmlLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.XmlLayout();} +s.test("XmlLayout seconds/milliseconds test 1",function(t){setUpXmlLayoutMillisecondsTest(t);var regex=new RegExp('^\\s*\\s*\\s*$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("XmlLayout seconds/milliseconds test 2",function(t){setUpXmlLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^\\s*\\s*\\s*$');t.assertRegexMatches(regex,formatted);});s.test("XmlLayout seconds/milliseconds test 3",function(t){setUpXmlLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^\\s*\\s*\\s*$');t.assertRegexMatches(regex,formatted);});s.test("escapeNewLines test",function(t){var escapeNewLines=log4javascript.evalInScope("escapeNewLines");var str="1\r2\n3\n4\r\n5\r6\r\n7";t.assertEquals(escapeNewLines(str),"1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");});s.test("JsonLayout format test",function(t){var layout=new log4javascript.JsonLayout();testLayoutWithVariables(layout,t);});s.test("JsonLayout test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/,t.appender.logMessages[0]);});s.test("JsonLayout JSON validity test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");eval("var o = "+t.appender.logMessages[0]);t.assertEquals(o.message,"TEST");});s.test("JsonLayout with number type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(15);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/,t.appender.logMessages[0]);});s.test("JsonLayout with object type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug({});t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with boolean type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(false);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/,t.appender.logMessages[0]);});s.test("JsonLayout with quote test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TE\"S\"T");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with exception test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/,t.appender.logMessages[0]);});var setUpJsonLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.JsonLayout();};s.test("JsonLayout seconds/milliseconds test 1",function(t){setUpJsonLayoutMillisecondsTest(t);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInMilliseconds+',"level":"DEBUG","url":".*","message":"TEST"}$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("JsonLayout seconds/milliseconds test 2",function(t){setUpJsonLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("JsonLayout seconds/milliseconds test 3",function(t){setUpJsonLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("HttpPostDataLayout format test",function(t){var layout=new log4javascript.HttpPostDataLayout();testLayoutWithVariables(layout,t);});s.test("HttpPostDataLayout test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST");t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout URL encoding test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST +\"1\"");t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout with exception test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/,t.appender.logMessages[0]);});(function(){var formatObjectExpansion=log4javascript.evalInScope("formatObjectExpansion");var newLine=log4javascript.evalInScope("newLine");var arr=[null,undefined,1.2,"A string",[1,"test"],{a:{b:1}}];s.test("Basic formatObjectExpansion array test (depth: 1)",function(t){t.assertEquals(formatObjectExpansion(arr,1),"["+newLine+" null,"+newLine+" undefined,"+newLine+" 1.2,"+newLine+" A string,"+newLine+" 1,test,"+newLine+" [object Object]"+newLine+"]");});s.test("Basic formatObjectExpansion array test (depth: 2)",function(t){t.assertEquals(formatObjectExpansion(arr,2),"["+newLine+" null,"+newLine+" undefined,"+newLine+" 1.2,"+newLine+" A string,"+newLine+" ["+newLine+" 1,"+newLine+" test"+newLine+" ],"+newLine+" {"+newLine+" a: [object Object]"+newLine+" }"+newLine+"]");});s.test("formatObjectExpansion simple object test",function(t){var obj={STRING:"A string"};t.assertEquals(formatObjectExpansion(obj,1),"{"+newLine+" STRING: A string"+newLine+"}");});s.test("formatObjectExpansion simple circular object test",function(t){var obj={};obj.a=obj;t.assertEquals(formatObjectExpansion(obj,2),"{"+newLine+" a: [object Object] [already expanded]"+newLine+"}");});})();var getSampleDate=function(){var date=new Date();date.setFullYear(2006);date.setMonth(7);date.setDate(30);date.setHours(15);date.setMinutes(38);date.setSeconds(45);return date;};s.test("String.replace test",function(t){t.assertEquals("Hello world".replace(/o/g,"Z"),"HellZ wZrld");});s.test("PatternLayout format test",function(t){var layout=new log4javascript.PatternLayout();testLayoutWithVariables(layout,t);});s.test("PatternLayout dates test",function(t){var layout=new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/,t.appender.logMessages[0]);});s.test("PatternLayout modifiers test",function(t){var layout=new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST|TEST|TEST| TEST|TEST |ST|ST| TEST|ST|TEST |");});s.test("PatternLayout conversion characters test",function(t){var layout=new log4javascript.PatternLayout("%c %n %p %r literal %%");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/,t.appender.logMessages[0]);});s.test("PatternLayout message test",function(t){var layout=new log4javascript.PatternLayout("%m{1} %m{2}");t.appender.setLayout(layout);var testObj={strikers:{quick:"Marlon"}};t.logger.debug(testObj);t.assertEquals("{\r\n strikers: [object Object]\r\n} {\r\n\ strikers: {\r\n quick: Marlon\r\n }\r\n}",t.appender.logMessages[0]);});}); diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js new file mode 100644 index 0000000..e64990f --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js @@ -0,0 +1,728 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function array_contains(arr, val) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] == val) { + return true; + } + } + return false; +} + +// Recursively checks that obj2's interface contains all of obj1's +// interface (functions and objects only) +function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) { + if (!namePrefix) { + namePrefix = ""; + } + var obj1PropertyNames = new Array(); + for (var i in obj1) { + if (i != "prototype" && i != "arguments") { + obj1PropertyNames.push(i); + } + } + if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) { + //obj1PropertyNames.push("prototype"); + } + for (var j = 0; j < obj1PropertyNames.length; j++) { + var propertyName = obj1PropertyNames[j]; + if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) { + var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName; + try { + if (typeof obj2[propertyName] == "undefined") { + throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name); + } else if (typeof obj2[propertyName] != typeof obj1[propertyName]){ + throw new Error(obj2_name + "'s " + propertyFullyQualifiedName + " is of the wrong type: " + typeof obj2[propertyName] + " when it is type " + typeof obj1[propertyName] + " in " + obj1_name); + } else if (obj1[propertyName] != Function.prototype.apply) { + if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) { + throw new Error("Interfaces don't match"); + } + } + } catch(ex) { + throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message); + } + } + } + return true; +}; + +// Simply tests a layout for exceptions when formatting +var testLayoutWithVariables = function(layout, t) { + var emptyObject = {}; + var emptyArray = []; + var emptyString = ""; + var localUndefined = emptyArray[0]; + var oneLevelObject = { + "name": "One-level object" + }; + var twoLevelObject = { + "name": "Two-level object", + "data": oneLevelObject + }; + var threeLevelObject = { + "name": "Three-level object", + "data": twoLevelObject + }; + var anArray = [ + 3, + "stuff", + true, + false, + 0, + null, + localUndefined, + 3.14, + function(p) { return "I'm a function"; }, + [1, "things"] + ]; + var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject, + twoLevelObject, threeLevelObject, anArray]; + + t.log("Testing layout " + layout) + for (var i = 0; i < arrayOfTestItems.length; i++) { + var ex = new Error("Test error"); + var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO, + [arrayOfTestItems[i]], null); + t.log("Formatting", arrayOfTestItems[i], result); + var result = layout.format(loggingEvent); + // Now try with an exception + loggingEvent.exception = ex; + t.log("Formatting with exception", arrayOfTestItems[i], result); + result = layout.format(loggingEvent); + } +}; + +xn.test.enableTestDebug = true; +xn.test.enable_log4javascript = false; + +xn.test.suite("log4javascript tests", function(s) { + log4javascript.logLog.setQuietMode(true); + var ArrayAppender = function(layout) { + if (layout) { + this.setLayout(layout); + } + this.logMessages = []; + }; + + ArrayAppender.prototype = new log4javascript.Appender(); + + ArrayAppender.prototype.layout = new log4javascript.NullLayout(); + + ArrayAppender.prototype.append = function(loggingEvent) { + var formattedMessage = this.getLayout().format(loggingEvent); + if (this.getLayout().ignoresThrowable()) { + formattedMessage += loggingEvent.getThrowableStrRep(); + } + this.logMessages.push(formattedMessage); + }; + + ArrayAppender.prototype.toString = function() { + return "[ArrayAppender]"; + }; + + s.setUp = function(t) { + t.logger = log4javascript.getLogger("test"); + t.logger.removeAllAppenders(); + t.appender = new ArrayAppender(); + t.logger.addAppender(t.appender); + }; + + s.tearDown = function(t) { + t.logger.removeAppender(t.appender); + log4javascript.resetConfiguration(); + }; + + s.test("Stub script interface test", function(t) { + try { + compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub"); + } catch (ex) { + t.fail(ex); + } + }); + + s.test("Disable log4javascript test", function(t) { + log4javascript.setEnabled(false); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages.length, 0); + log4javascript.setEnabled(true); + }); + + s.test("Array.splice test 1", function(t) { + var a = ["Marlon", "Ashley", "Darius", "Lloyd"]; + var deletedItems = a.splice(1, 2); + t.assertEquals(a.join(","), "Marlon,Lloyd"); + t.assertEquals(deletedItems.join(","), "Ashley,Darius"); + }); + + s.test("Array.splice test 2", function(t) { + var a = ["Marlon", "Ashley", "Darius", "Lloyd"]; + var deletedItems = a.splice(1, 1, "Malky", "Jay"); + t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd"); + t.assertEquals(deletedItems.join(","), "Ashley"); + }); + + s.test("array_remove test", function(t) { + var array_remove = log4javascript.evalInScope("array_remove"); + var a = ["Marlon", "Ashley", "Darius"]; + array_remove(a, "Darius"); + t.assertEquals(a.join(","), "Marlon,Ashley"); + }); + + s.test("array_remove with empty array test", function(t) { + var array_remove = log4javascript.evalInScope("array_remove"); + var a = []; + array_remove(a, "Darius"); + t.assertEquals(a.join(","), ""); + }); + + s.test("Logger logging test", function(t) { + // Should log since the default level for loggers is DEBUG and + // the default threshold for appenders is ALL + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages.length, 1); + }); + + s.test("Logger levels test", function(t) { + var originalLevel = t.logger.getEffectiveLevel(); + t.logger.setLevel(log4javascript.Level.INFO); + t.logger.debug("TEST"); + t.logger.setLevel(originalLevel); + t.assertEquals(t.appender.logMessages.length, 0); + }); + + s.test("Logger getEffectiveLevel inheritance test 1", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + parentLogger.setLevel(log4javascript.Level.ERROR); + t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR); + }); + + s.test("Logger getEffectiveLevel inheritance test 2", function(t) { + var grandParentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2.test3"); + grandParentLogger.setLevel(log4javascript.Level.ERROR); + t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR); + }); + + s.test("Logger getEffectiveLevel inheritance test 3", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + parentLogger.setLevel(log4javascript.Level.ERROR); + childLogger.setLevel(log4javascript.Level.INFO); + t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO); + }); + + s.test("Logger getEffectiveLevel root inheritance test", function(t) { + var rootLogger = log4javascript.getRootLogger(); + var childLogger = log4javascript.getLogger("test1.test2.test3"); + rootLogger.setLevel(log4javascript.Level.WARN); + t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN); + }); + + s.test("Logger null level test", function(t) { + t.logger.setLevel(null); + // Should default to root logger level, which is DEBUG + t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG); + }); + + s.test("Logger appender additivity test 1", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + var parentLoggerAppender = new ArrayAppender(); + var childLoggerAppender = new ArrayAppender(); + + parentLogger.addAppender(parentLoggerAppender); + childLogger.addAppender(childLoggerAppender); + + parentLogger.info("Parent logger test message"); + childLogger.info("Child logger test message"); + + t.assertEquals(parentLoggerAppender.logMessages.length, 2); + t.assertEquals(childLoggerAppender.logMessages.length, 1); + }); + + s.test("Logger appender additivity test 2", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + var parentLoggerAppender = new ArrayAppender(); + var childLoggerAppender = new ArrayAppender(); + + parentLogger.addAppender(parentLoggerAppender); + childLogger.addAppender(childLoggerAppender); + + childLogger.setAdditivity(false); + + parentLogger.info("Parent logger test message"); + childLogger.info("Child logger test message"); + + t.assertEquals(parentLoggerAppender.logMessages.length, 1); + t.assertEquals(childLoggerAppender.logMessages.length, 1); + }); + + s.test("Logger appender additivity test 3", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + var parentLoggerAppender = new ArrayAppender(); + var childLoggerAppender = new ArrayAppender(); + + parentLogger.addAppender(parentLoggerAppender); + childLogger.addAppender(childLoggerAppender); + + childLogger.setAdditivity(false); + + parentLogger.info("Parent logger test message"); + childLogger.info("Child logger test message"); + + childLogger.setAdditivity(true); + + childLogger.info("Child logger test message 2"); + + t.assertEquals(parentLoggerAppender.logMessages.length, 2); + t.assertEquals(childLoggerAppender.logMessages.length, 2); + }); + + s.test("Appender threshold test", function(t) { + t.appender.setThreshold(log4javascript.Level.INFO); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages.length, 0); + }); + + s.test("Basic appender / layout test", function(t) { + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages[0], "TEST"); + }); + + s.test("Appender uniqueness within logger test", function(t) { + // Add the same appender to the logger for a second time + t.logger.addAppender(t.appender); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages.length, 1); + }); + + s.test("Logger remove appender test", function(t) { + t.logger.debug("TEST"); + t.logger.removeAppender(t.appender); + t.logger.debug("TEST AGAIN"); + t.assertEquals(t.appender.logMessages.length, 1); + }); + + s.test("", function(t) { + t.logger.debug("TEST"); + t.logger.removeAppender(t.appender); + t.logger.debug("TEST AGAIN"); + t.assertEquals(t.appender.logMessages.length, 1); + }); + s.test("SimpleLayout format test", function(t) { + var layout = new log4javascript.SimpleLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("SimpleLayout test", function(t) { + t.appender.setLayout(new log4javascript.SimpleLayout()); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST"); + }); + s.test("NullLayout format test", function(t) { + var layout = new log4javascript.NullLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("NullLayout test", function(t) { + t.appender.setLayout(new log4javascript.NullLayout()); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages[0], "TEST"); + }); + s.test("XmlLayout format test", function(t) { + var layout = new log4javascript.XmlLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("XmlLayout test", function(t) { + t.appender.setLayout(new log4javascript.XmlLayout()); + t.logger.debug("TEST"); + t.assertRegexMatches(/^\s*<\/log4javascript:message>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]); + }); + + s.test("XmlLayout with exception test", function(t) { + t.appender.setLayout(new log4javascript.XmlLayout()); + t.logger.debug("TEST", new Error("Test error")); + t.assertRegexMatches(/^\s*<\/log4javascript:message>\s*\s*<\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]); + }); + + var setUpXmlLayoutMillisecondsTest = function(t) { + t.date = new Date(); + t.timeInMilliseconds = t.date.getTime(); + t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000); + t.milliseconds = t.date.getMilliseconds(); + + t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null); + t.layout = new log4javascript.XmlLayout(); + } + + s.test("XmlLayout seconds/milliseconds test 1", function(t) { + setUpXmlLayoutMillisecondsTest(t); + + // Test default (i.e. timestamps in milliseconds) first + var regex = new RegExp('^\\s*\\s*\\s*$'); + t.assertRegexMatches(regex, t.layout.format(t.loggingEvent)); + }); + + s.test("XmlLayout seconds/milliseconds test 2", function(t) { + setUpXmlLayoutMillisecondsTest(t); + + // Change the global setting + log4javascript.setTimeStampsInMilliseconds(false); + var formatted = t.layout.format(t.loggingEvent); + log4javascript.setTimeStampsInMilliseconds(true); + var regex = new RegExp('^\\s*\\s*\\s*$'); + t.assertRegexMatches(regex, formatted); + }); + + s.test("XmlLayout seconds/milliseconds test 3", function(t) { + setUpXmlLayoutMillisecondsTest(t); + + // Change the layout setting + t.layout.setTimeStampsInMilliseconds(false); + var formatted = t.layout.format(t.loggingEvent); + var regex = new RegExp('^\\s*\\s*\\s*$'); + t.assertRegexMatches(regex, formatted); + }); + s.test("escapeNewLines test", function(t) { + var escapeNewLines = log4javascript.evalInScope("escapeNewLines"); + var str = "1\r2\n3\n4\r\n5\r6\r\n7"; + t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7"); + }); + + s.test("JsonLayout format test", function(t) { + var layout = new log4javascript.JsonLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("JsonLayout test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug("TEST"); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout JSON validity test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug("TEST"); + eval("var o = " + t.appender.logMessages[0]); + t.assertEquals(o.message, "TEST"); + }); + + s.test("JsonLayout with number type message test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug(15); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout with object type message test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug({}); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout with boolean type message test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug(false); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout with quote test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug("TE\"S\"T"); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout with exception test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug("TEST", new Error("Test error")); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]); + }); + + var setUpJsonLayoutMillisecondsTest = function(t) { + t.date = new Date(); + t.timeInMilliseconds = t.date.getTime(); + t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000); + t.milliseconds = t.date.getMilliseconds(); + + t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null); + t.layout = new log4javascript.JsonLayout(); + }; + + s.test("JsonLayout seconds/milliseconds test 1", function(t) { + setUpJsonLayoutMillisecondsTest(t); + + // Test default (i.e. timestamps in milliseconds) first + var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$'); + t.assertRegexMatches(regex, t.layout.format(t.loggingEvent)); + }); + + s.test("JsonLayout seconds/milliseconds test 2", function(t) { + setUpJsonLayoutMillisecondsTest(t); + + // Change the global setting + log4javascript.setTimeStampsInMilliseconds(false); + var formatted = t.layout.format(t.loggingEvent); + log4javascript.setTimeStampsInMilliseconds(true); + var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$'); + t.assertRegexMatches(regex, formatted); + }); + + s.test("JsonLayout seconds/milliseconds test 3", function(t) { + setUpJsonLayoutMillisecondsTest(t); + + // Change the layout setting + t.layout.setTimeStampsInMilliseconds(false); + var formatted = t.layout.format(t.loggingEvent); + var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$'); + t.assertRegexMatches(regex, formatted); + }); + s.test("HttpPostDataLayout format test", function(t) { + var layout = new log4javascript.HttpPostDataLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("HttpPostDataLayout test", function(t) { + t.appender.setLayout(new log4javascript.HttpPostDataLayout()); + t.logger.debug("TEST"); + t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]); + }); + + s.test("HttpPostDataLayout URL encoding test", function(t) { + t.appender.setLayout(new log4javascript.HttpPostDataLayout()); + t.logger.debug("TEST +\"1\""); + t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]); + }); + + s.test("HttpPostDataLayout with exception test", function(t) { + t.appender.setLayout(new log4javascript.HttpPostDataLayout()); + t.logger.debug("TEST", new Error("Test error")); + t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]); + }); + + (function() { + var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion"); + var newLine = log4javascript.evalInScope("newLine"); + var arr = [ + null, + undefined, + 1.2, + "A string", + [1, "test"], + { + a: { + b: 1 + } + } + ]; + + s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) { + t.assertEquals(formatObjectExpansion(arr, 1), + "[" + newLine + + " null," + newLine + + " undefined," + newLine + + " 1.2," + newLine + + " A string," + newLine + + " 1,test," + newLine + + " [object Object]" + newLine + + "]" + ); + }); + + s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) { + t.assertEquals(formatObjectExpansion(arr, 2), + "[" + newLine + + " null," + newLine + + " undefined," + newLine + + " 1.2," + newLine + + " A string," + newLine + + " [" + newLine + + " 1," + newLine + + " test" + newLine + + " ]," + newLine + + " {" + newLine + + " a: [object Object]" + newLine + + " }" + newLine + + "]" + ); + }); + + s.test("formatObjectExpansion simple object test", function(t) { + var obj = { + STRING: "A string" + }; + t.assertEquals(formatObjectExpansion(obj, 1), + "{" + newLine + + " STRING: A string" + newLine + + "}" + ); + }); + + s.test("formatObjectExpansion simple circular object test", function(t) { + var obj = {}; + obj.a = obj; + + t.assertEquals(formatObjectExpansion(obj, 2), + "{" + newLine + + " a: [object Object] [already expanded]" + newLine + + "}" + ); + }); + })(); /* ---------------------------------------------------------- */ + + var getSampleDate = function() { + var date = new Date(); + date.setFullYear(2006); + date.setMonth(7); + date.setDate(30); + date.setHours(15); + date.setMinutes(38); + date.setSeconds(45); + return date; + }; + + /* ---------------------------------------------------------- */ + + s.test("String.replace test", function(t) { + t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld"); + }); + + s.test("PatternLayout format test", function(t) { + var layout = new log4javascript.PatternLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("PatternLayout dates test", function(t) { + var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}"); + t.appender.setLayout(layout); + t.logger.debug("TEST"); + t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/, t.appender.logMessages[0]); + }); + + s.test("PatternLayout modifiers test", function(t) { + var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|"); + t.appender.setLayout(layout); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST| TEST|TEST |ST|ST| TEST|ST|TEST |"); + }); + + s.test("PatternLayout conversion characters test", function(t) { + var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%"); + t.appender.setLayout(layout); + t.logger.debug("TEST"); + t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]); + }); + + s.test("PatternLayout message test", function(t) { + var layout = new log4javascript.PatternLayout("%m{1} %m{2}"); + t.appender.setLayout(layout); + var testObj = { + strikers: { + quick: "Marlon" + } + }; + t.logger.debug(testObj); + t.assertEquals("{\r\n strikers: [object Object]\r\n} {\r\n\ strikers: {\r\n quick: Marlon\r\n }\r\n}", t.appender.logMessages[0]); + }); +/* + s.test("AjaxAppender JsonLayout single message test", function(t) { + t.async(10000); + // Create and add an Ajax appender + var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do"); + ajaxAppender.setLayout(new log4javascript.JsonLayout()); + ajaxAppender.setRequestSuccessCallback( + function(xmlHttp) { + // Response comes back as JSON array of messages logged + var jsonResponse = xmlHttp.responseText; + var arr = eval(jsonResponse); + t.assertEquals(arr.length, 1); + t.assertEquals(arr[0], "TEST"); + t.succeed(); + } + ); + ajaxAppender.setFailCallback( + function(msg) { + t.fail(msg); + ajaxErrorMessage = msg; + } + ); + t.logger.addAppender(ajaxAppender); + t.logger.debug("TEST"); + }); + + s.test("AjaxAppender JsonLayout batched messages test", function(t) { + t.async(10000); + var message1 = "TEST 1"; + var message2 = "String with \"lots of 'quotes'\" + plusses in"; + var message3 = "A non-threatening string"; + // Create and add an Ajax appender + var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do"); + ajaxAppender.setLayout(new log4javascript.JsonLayout()); + ajaxAppender.setBatchSize(3); + ajaxAppender.setRequestSuccessCallback( + function(xmlHttp) { + // Response comes back as JSON array of messages logged + var jsonResponse = xmlHttp.responseText; + var arr = eval(jsonResponse); + t.assertEquals(arr.length, 3); + t.assertEquals(arr[0], message1); + t.assertEquals(arr[1], message2); + t.assertEquals(arr[2], message3); + t.succeed(); + } + ); + ajaxAppender.setFailCallback( + function(msg) { + t.fail(msg); + ajaxErrorMessage = msg; + } + ); + t.logger.addAppender(ajaxAppender); + t.logger.debug(message1); + t.logger.info(message2); + t.logger.warn(message3); + }); + + s.test("AjaxAppender HttpPostDataLayout single message test", function(t) { + t.async(10000); + // Create and add an Ajax appender + var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do"); + var testMessage = "TEST +\"1\""; + ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout()); + ajaxAppender.setRequestSuccessCallback( + function(xmlHttp) { + // Response comes back as JSON array of messages logged + var jsonResponse = xmlHttp.responseText; + var arr = eval(jsonResponse); + t.assertEquals(arr.length, 1); + t.assertEquals(arr[0], testMessage); + t.succeed(); + } + ); + ajaxAppender.setFailCallback( + function(msg) { + t.fail(msg); + ajaxErrorMessage = msg; + } + ); + t.logger.addAppender(ajaxAppender); + t.logger.debug(testMessage); + }); +*/ +}); \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js new file mode 100644 index 0000000..55bd2ca --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js @@ -0,0 +1,862 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function array_contains(arr, val) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] == val) { + return true; + } + } + return false; +} + +// Recursively checks that obj2's interface contains all of obj1's +// interface (functions and objects only) +function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) { + if (!namePrefix) { + namePrefix = ""; + } + var obj1PropertyNames = new Array(); + for (var i in obj1) { + if (i != "prototype" && i != "arguments") { + obj1PropertyNames.push(i); + } + } + if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) { + //obj1PropertyNames.push("prototype"); + } + for (var j = 0; j < obj1PropertyNames.length; j++) { + var propertyName = obj1PropertyNames[j]; + if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) { + var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName; + try { + if (typeof obj2[propertyName] == "undefined") { + throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name); + } else if (typeof obj2[propertyName] != typeof obj1[propertyName]){ + throw new Error(obj2_name + "'s " + propertyFullyQualifiedName + " is of the wrong type: " + typeof obj2[propertyName] + " when it is type " + typeof obj1[propertyName] + " in " + obj1_name); + } else if (obj1[propertyName] != Function.prototype.apply) { + if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) { + throw new Error("Interfaces don't match"); + } + } + } catch(ex) { + throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message); + } + } + } + return true; +}; + +// Simply tests a layout for exceptions when formatting +var testLayoutWithVariables = function(layout, t) { + var emptyObject = {}; + var emptyArray = []; + var emptyString = ""; + var localUndefined = emptyArray[0]; + var oneLevelObject = { + "name": "One-level object" + }; + var twoLevelObject = { + "name": "Two-level object", + "data": oneLevelObject + }; + var threeLevelObject = { + "name": "Three-level object", + "data": twoLevelObject + }; + var anArray = [ + 3, + "stuff", + true, + false, + 0, + null, + localUndefined, + 3.14, + function(p) { return "I'm a function"; }, + [1, "things"] + ]; + var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject, + twoLevelObject, threeLevelObject, anArray]; + + t.log("Testing layout " + layout) + for (var i = 0; i < arrayOfTestItems.length; i++) { + var ex = new Error("Test error"); + var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO, + [arrayOfTestItems[i]], null); + t.log("Formatting", arrayOfTestItems[i], result); + var result = layout.format(loggingEvent); + // Now try with an exception + loggingEvent.exception = ex; + t.log("Formatting with exception", arrayOfTestItems[i], result); + result = layout.format(loggingEvent); + } +}; + +xn.test.enableTestDebug = true; +xn.test.enable_log4javascript = false; + +xn.test.suite("log4javascript tests", function(s) { + log4javascript.logLog.setQuietMode(true); + var ArrayAppender = function(layout) { + if (layout) { + this.setLayout(layout); + } + this.logMessages = []; + }; + + ArrayAppender.prototype = new log4javascript.Appender(); + + ArrayAppender.prototype.layout = new log4javascript.NullLayout(); + + ArrayAppender.prototype.append = function(loggingEvent) { + var formattedMessage = this.getLayout().format(loggingEvent); + if (this.getLayout().ignoresThrowable()) { + formattedMessage += loggingEvent.getThrowableStrRep(); + } + this.logMessages.push(formattedMessage); + }; + + ArrayAppender.prototype.toString = function() { + return "[ArrayAppender]"; + }; + + s.setUp = function(t) { + t.logger = log4javascript.getLogger("test"); + t.logger.removeAllAppenders(); + t.appender = new ArrayAppender(); + t.logger.addAppender(t.appender); + }; + + s.tearDown = function(t) { + t.logger.removeAppender(t.appender); + log4javascript.resetConfiguration(); + }; + + s.test("Stub script interface test", function(t) { + try { + compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub"); + } catch (ex) { + t.fail(ex); + } + }); + + s.test("Disable log4javascript test", function(t) { + log4javascript.setEnabled(false); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages.length, 0); + log4javascript.setEnabled(true); + }); + + s.test("Array.splice test 1", function(t) { + var a = ["Marlon", "Ashley", "Darius", "Lloyd"]; + var deletedItems = a.splice(1, 2); + t.assertEquals(a.join(","), "Marlon,Lloyd"); + t.assertEquals(deletedItems.join(","), "Ashley,Darius"); + }); + + s.test("Array.splice test 2", function(t) { + var a = ["Marlon", "Ashley", "Darius", "Lloyd"]; + var deletedItems = a.splice(1, 1, "Malky", "Jay"); + t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd"); + t.assertEquals(deletedItems.join(","), "Ashley"); + }); + + s.test("array_remove test", function(t) { + var array_remove = log4javascript.evalInScope("array_remove"); + var a = ["Marlon", "Ashley", "Darius"]; + array_remove(a, "Darius"); + t.assertEquals(a.join(","), "Marlon,Ashley"); + }); + + s.test("array_remove with empty array test", function(t) { + var array_remove = log4javascript.evalInScope("array_remove"); + var a = []; + array_remove(a, "Darius"); + t.assertEquals(a.join(","), ""); + }); + + s.test("Logger logging test", function(t) { + // Should log since the default level for loggers is DEBUG and + // the default threshold for appenders is ALL + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages.length, 1); + }); + + s.test("Logger levels test", function(t) { + var originalLevel = t.logger.getEffectiveLevel(); + t.logger.setLevel(log4javascript.Level.INFO); + t.logger.debug("TEST"); + t.logger.setLevel(originalLevel); + t.assertEquals(t.appender.logMessages.length, 0); + }); + + s.test("Logger getEffectiveLevel inheritance test 1", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + parentLogger.setLevel(log4javascript.Level.ERROR); + t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR); + }); + + s.test("Logger getEffectiveLevel inheritance test 2", function(t) { + var grandParentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2.test3"); + grandParentLogger.setLevel(log4javascript.Level.ERROR); + t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR); + }); + + s.test("Logger getEffectiveLevel inheritance test 3", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + parentLogger.setLevel(log4javascript.Level.ERROR); + childLogger.setLevel(log4javascript.Level.INFO); + t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO); + }); + + s.test("Logger getEffectiveLevel root inheritance test", function(t) { + var rootLogger = log4javascript.getRootLogger(); + var childLogger = log4javascript.getLogger("test1.test2.test3"); + rootLogger.setLevel(log4javascript.Level.WARN); + t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN); + }); + + s.test("Logger null level test", function(t) { + t.logger.setLevel(null); + // Should default to root logger level, which is DEBUG + t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG); + }); + + s.test("Logger appender additivity test 1", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + var parentLoggerAppender = new ArrayAppender(); + var childLoggerAppender = new ArrayAppender(); + + parentLogger.addAppender(parentLoggerAppender); + childLogger.addAppender(childLoggerAppender); + + parentLogger.info("Parent logger test message"); + childLogger.info("Child logger test message"); + + t.assertEquals(parentLoggerAppender.logMessages.length, 2); + t.assertEquals(childLoggerAppender.logMessages.length, 1); + }); + + s.test("Logger appender additivity test 2", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + var parentLoggerAppender = new ArrayAppender(); + var childLoggerAppender = new ArrayAppender(); + + parentLogger.addAppender(parentLoggerAppender); + childLogger.addAppender(childLoggerAppender); + + childLogger.setAdditivity(false); + + parentLogger.info("Parent logger test message"); + childLogger.info("Child logger test message"); + + t.assertEquals(parentLoggerAppender.logMessages.length, 1); + t.assertEquals(childLoggerAppender.logMessages.length, 1); + }); + + s.test("Logger appender additivity test 3", function(t) { + var parentLogger = log4javascript.getLogger("test1"); + var childLogger = log4javascript.getLogger("test1.test2"); + var parentLoggerAppender = new ArrayAppender(); + var childLoggerAppender = new ArrayAppender(); + + parentLogger.addAppender(parentLoggerAppender); + childLogger.addAppender(childLoggerAppender); + + childLogger.setAdditivity(false); + + parentLogger.info("Parent logger test message"); + childLogger.info("Child logger test message"); + + childLogger.setAdditivity(true); + + childLogger.info("Child logger test message 2"); + + t.assertEquals(parentLoggerAppender.logMessages.length, 2); + t.assertEquals(childLoggerAppender.logMessages.length, 2); + }); + + s.test("Appender threshold test", function(t) { + t.appender.setThreshold(log4javascript.Level.INFO); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages.length, 0); + }); + + s.test("Basic appender / layout test", function(t) { + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages[0], "TEST"); + }); + + s.test("Appender uniqueness within logger test", function(t) { + // Add the same appender to the logger for a second time + t.logger.addAppender(t.appender); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages.length, 1); + }); + + s.test("Logger remove appender test", function(t) { + t.logger.debug("TEST"); + t.logger.removeAppender(t.appender); + t.logger.debug("TEST AGAIN"); + t.assertEquals(t.appender.logMessages.length, 1); + }); + + s.test("", function(t) { + t.logger.debug("TEST"); + t.logger.removeAppender(t.appender); + t.logger.debug("TEST AGAIN"); + t.assertEquals(t.appender.logMessages.length, 1); + }); + s.test("SimpleLayout format test", function(t) { + var layout = new log4javascript.SimpleLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("SimpleLayout test", function(t) { + t.appender.setLayout(new log4javascript.SimpleLayout()); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST"); + }); + s.test("NullLayout format test", function(t) { + var layout = new log4javascript.NullLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("NullLayout test", function(t) { + t.appender.setLayout(new log4javascript.NullLayout()); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages[0], "TEST"); + }); + s.test("XmlLayout format test", function(t) { + var layout = new log4javascript.XmlLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("XmlLayout test", function(t) { + t.appender.setLayout(new log4javascript.XmlLayout()); + t.logger.debug("TEST"); + t.assertRegexMatches(/^\s*<\/log4javascript:message>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]); + }); + + s.test("XmlLayout with exception test", function(t) { + t.appender.setLayout(new log4javascript.XmlLayout()); + t.logger.debug("TEST", new Error("Test error")); + t.assertRegexMatches(/^\s*<\/log4javascript:message>\s*\s*<\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]); + }); + + var setUpXmlLayoutMillisecondsTest = function(t) { + t.date = new Date(); + t.timeInMilliseconds = t.date.getTime(); + t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000); + t.milliseconds = t.date.getMilliseconds(); + + t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null); + t.layout = new log4javascript.XmlLayout(); + } + + s.test("XmlLayout seconds/milliseconds test 1", function(t) { + setUpXmlLayoutMillisecondsTest(t); + + // Test default (i.e. timestamps in milliseconds) first + var regex = new RegExp('^\\s*\\s*\\s*$'); + t.assertRegexMatches(regex, t.layout.format(t.loggingEvent)); + }); + + s.test("XmlLayout seconds/milliseconds test 2", function(t) { + setUpXmlLayoutMillisecondsTest(t); + + // Change the global setting + log4javascript.setTimeStampsInMilliseconds(false); + var formatted = t.layout.format(t.loggingEvent); + log4javascript.setTimeStampsInMilliseconds(true); + var regex = new RegExp('^\\s*\\s*\\s*$'); + t.assertRegexMatches(regex, formatted); + }); + + s.test("XmlLayout seconds/milliseconds test 3", function(t) { + setUpXmlLayoutMillisecondsTest(t); + + // Change the layout setting + t.layout.setTimeStampsInMilliseconds(false); + var formatted = t.layout.format(t.loggingEvent); + var regex = new RegExp('^\\s*\\s*\\s*$'); + t.assertRegexMatches(regex, formatted); + }); + s.test("escapeNewLines test", function(t) { + var escapeNewLines = log4javascript.evalInScope("escapeNewLines"); + var str = "1\r2\n3\n4\r\n5\r6\r\n7"; + t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7"); + }); + + s.test("JsonLayout format test", function(t) { + var layout = new log4javascript.JsonLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("JsonLayout test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug("TEST"); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout JSON validity test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug("TEST"); + eval("var o = " + t.appender.logMessages[0]); + t.assertEquals(o.message, "TEST"); + }); + + s.test("JsonLayout with number type message test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug(15); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout with object type message test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug({}); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout with boolean type message test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug(false); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout with quote test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug("TE\"S\"T"); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]); + }); + + s.test("JsonLayout with exception test", function(t) { + t.appender.setLayout(new log4javascript.JsonLayout()); + t.logger.debug("TEST", new Error("Test error")); + t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]); + }); + + var setUpJsonLayoutMillisecondsTest = function(t) { + t.date = new Date(); + t.timeInMilliseconds = t.date.getTime(); + t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000); + t.milliseconds = t.date.getMilliseconds(); + + t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null); + t.layout = new log4javascript.JsonLayout(); + }; + + s.test("JsonLayout seconds/milliseconds test 1", function(t) { + setUpJsonLayoutMillisecondsTest(t); + + // Test default (i.e. timestamps in milliseconds) first + var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$'); + t.assertRegexMatches(regex, t.layout.format(t.loggingEvent)); + }); + + s.test("JsonLayout seconds/milliseconds test 2", function(t) { + setUpJsonLayoutMillisecondsTest(t); + + // Change the global setting + log4javascript.setTimeStampsInMilliseconds(false); + var formatted = t.layout.format(t.loggingEvent); + log4javascript.setTimeStampsInMilliseconds(true); + var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$'); + t.assertRegexMatches(regex, formatted); + }); + + s.test("JsonLayout seconds/milliseconds test 3", function(t) { + setUpJsonLayoutMillisecondsTest(t); + + // Change the layout setting + t.layout.setTimeStampsInMilliseconds(false); + var formatted = t.layout.format(t.loggingEvent); + var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$'); + t.assertRegexMatches(regex, formatted); + }); + s.test("HttpPostDataLayout format test", function(t) { + var layout = new log4javascript.HttpPostDataLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("HttpPostDataLayout test", function(t) { + t.appender.setLayout(new log4javascript.HttpPostDataLayout()); + t.logger.debug("TEST"); + t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]); + }); + + s.test("HttpPostDataLayout URL encoding test", function(t) { + t.appender.setLayout(new log4javascript.HttpPostDataLayout()); + t.logger.debug("TEST +\"1\""); + t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]); + }); + + s.test("HttpPostDataLayout with exception test", function(t) { + t.appender.setLayout(new log4javascript.HttpPostDataLayout()); + t.logger.debug("TEST", new Error("Test error")); + t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]); + }); + + (function() { + var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion"); + var newLine = log4javascript.evalInScope("newLine"); + var arr = [ + null, + undefined, + 1.2, + "A string", + [1, "test"], + { + a: { + b: 1 + } + } + ]; + + s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) { + t.assertEquals(formatObjectExpansion(arr, 1), + "[" + newLine + + " null," + newLine + + " undefined," + newLine + + " 1.2," + newLine + + " A string," + newLine + + " 1,test," + newLine + + " [object Object]" + newLine + + "]" + ); + }); + + s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) { + t.assertEquals(formatObjectExpansion(arr, 2), + "[" + newLine + + " null," + newLine + + " undefined," + newLine + + " 1.2," + newLine + + " A string," + newLine + + " [" + newLine + + " 1," + newLine + + " test" + newLine + + " ]," + newLine + + " {" + newLine + + " a: [object Object]" + newLine + + " }" + newLine + + "]" + ); + }); + + s.test("formatObjectExpansion simple object test", function(t) { + var obj = { + STRING: "A string" + }; + t.assertEquals(formatObjectExpansion(obj, 1), + "{" + newLine + + " STRING: A string" + newLine + + "}" + ); + }); + + s.test("formatObjectExpansion simple circular object test", function(t) { + var obj = {}; + obj.a = obj; + + t.assertEquals(formatObjectExpansion(obj, 2), + "{" + newLine + + " a: [object Object] [already expanded]" + newLine + + "}" + ); + }); + })(); /* ---------------------------------------------------------- */ + + var getSampleDate = function() { + var date = new Date(); + date.setFullYear(2006); + date.setMonth(7); + date.setDate(30); + date.setHours(15); + date.setMinutes(38); + date.setSeconds(45); + return date; + }; + + /* ---------------------------------------------------------- */ + + s.test("String.replace test", function(t) { + t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld"); + }); + + s.test("PatternLayout format test", function(t) { + var layout = new log4javascript.PatternLayout(); + testLayoutWithVariables(layout, t); + }); + + s.test("PatternLayout dates test", function(t) { + var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}"); + t.appender.setLayout(layout); + t.logger.debug("TEST"); + t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/, t.appender.logMessages[0]); + }); + + s.test("PatternLayout modifiers test", function(t) { + var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|"); + t.appender.setLayout(layout); + t.logger.debug("TEST"); + t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST| TEST|TEST |ST|ST| TEST|ST|TEST |"); + }); + + s.test("PatternLayout conversion characters test", function(t) { + var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%"); + t.appender.setLayout(layout); + t.logger.debug("TEST"); + t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]); + }); + + s.test("PatternLayout message test", function(t) { + var layout = new log4javascript.PatternLayout("%m{1} %m{2}"); + t.appender.setLayout(layout); + var testObj = { + strikers: { + quick: "Marlon" + } + }; + t.logger.debug(testObj); + t.assertEquals("{\r\n strikers: [object Object]\r\n} {\r\n\ strikers: {\r\n quick: Marlon\r\n }\r\n}", t.appender.logMessages[0]); + }); + // Tests for exceptions when logging + s.test("Logging/grouping test", function(t) { + var browserConsoleAppender = new log4javascript.BrowserConsoleAppender(); + t.logger.addAppender(browserConsoleAppender); + + // Test each level + t.logger.trace("TEST TRACE"); + t.logger.debug("TEST DEBUG"); + t.logger.info("TEST INFO"); + t.logger.warn("TEST WARN"); + t.logger.error("TEST ERROR"); + t.logger.fatal("TEST FATAL"); + + // Test with exception + t.logger.fatal("TEST FATAL", new Error("Fake error")); + + // Test multiple messages + t.logger.info("TEST INFO", "Second message", ["a", "b", "c"]); + + // Test groups + t.logger.group("TEST GROUP"); + t.logger.info("TEST INFO"); + t.logger.groupEnd("TEST GROUP"); + t.logger.info("TEST INFO"); + + t.logger.removeAppender(browserConsoleAppender); + }); + +/* + s.test("AjaxAppender JsonLayout single message test", function(t) { + t.async(10000); + // Create and add an Ajax appender + var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do"); + ajaxAppender.setLayout(new log4javascript.JsonLayout()); + ajaxAppender.setRequestSuccessCallback( + function(xmlHttp) { + // Response comes back as JSON array of messages logged + var jsonResponse = xmlHttp.responseText; + var arr = eval(jsonResponse); + t.assertEquals(arr.length, 1); + t.assertEquals(arr[0], "TEST"); + t.succeed(); + } + ); + ajaxAppender.setFailCallback( + function(msg) { + t.fail(msg); + ajaxErrorMessage = msg; + } + ); + t.logger.addAppender(ajaxAppender); + t.logger.debug("TEST"); + }); + + s.test("AjaxAppender JsonLayout batched messages test", function(t) { + t.async(10000); + var message1 = "TEST 1"; + var message2 = "String with \"lots of 'quotes'\" + plusses in"; + var message3 = "A non-threatening string"; + // Create and add an Ajax appender + var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do"); + ajaxAppender.setLayout(new log4javascript.JsonLayout()); + ajaxAppender.setBatchSize(3); + ajaxAppender.setRequestSuccessCallback( + function(xmlHttp) { + // Response comes back as JSON array of messages logged + var jsonResponse = xmlHttp.responseText; + var arr = eval(jsonResponse); + t.assertEquals(arr.length, 3); + t.assertEquals(arr[0], message1); + t.assertEquals(arr[1], message2); + t.assertEquals(arr[2], message3); + t.succeed(); + } + ); + ajaxAppender.setFailCallback( + function(msg) { + t.fail(msg); + ajaxErrorMessage = msg; + } + ); + t.logger.addAppender(ajaxAppender); + t.logger.debug(message1); + t.logger.info(message2); + t.logger.warn(message3); + }); + + s.test("AjaxAppender HttpPostDataLayout single message test", function(t) { + t.async(10000); + // Create and add an Ajax appender + var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do"); + var testMessage = "TEST +\"1\""; + ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout()); + ajaxAppender.setRequestSuccessCallback( + function(xmlHttp) { + // Response comes back as JSON array of messages logged + var jsonResponse = xmlHttp.responseText; + var arr = eval(jsonResponse); + t.assertEquals(arr.length, 1); + t.assertEquals(arr[0], testMessage); + t.succeed(); + } + ); + ajaxAppender.setFailCallback( + function(msg) { + t.fail(msg); + ajaxErrorMessage = msg; + } + ); + t.logger.addAppender(ajaxAppender); + t.logger.debug(testMessage); + }); +*/ + var testConsoleAppender = function(t, appender) { + var timeoutCallback = function() { + //alert("Failed. Debug messages follow."); + //log4javascript.logLog.displayDebug(); + return (windowLoaded ? "Timed out while waiting for messages to appear" : + "Timed out while waiting for window to load") + ". Debug messages: " + + log4javascript.logLog.debugMessages.join("\r\n"); + } + + t.async(60000, timeoutCallback); + + var windowLoaded = false; + var domChecked = false; + + // Set a timeout to allow the pop-up to appear + var onLoadHandler = function() { + log4javascript.logLog.debug("onLoadHandler"); + windowLoaded = true; + var win = appender.getConsoleWindow(); + + if (win && win.loaded) { + // Check that the log container element contains the log message. Since + // the console window waits 100 milliseconds before actually rendering the + // message as a DOM element, we need to use a timer + var checkDom = function() { + log4javascript.logLog.debug("checkDom"); + domChecked = true; + var logContainer = win.logMainContainer; + if (logContainer.hasChildNodes()) { + if (logContainer.innerHTML.indexOf("TEST MESSAGE") == -1) { + appender.close(); + t.fail("Log message not correctly logged (log container innerHTML: " + logContainer.innerHTML + ")"); + } else { + t.assert(appender.isVisible()); + appender.close(); + t.assert(!appender.isVisible()); + t.succeed(); + } + } else { + appender.close(); + t.fail("Console has no log messages"); + } + } + window.setTimeout(checkDom, 300); + } else { + appender.close(); + t.fail("Console mistakenly raised load event"); + } + } + + appender.addEventListener("load", onLoadHandler); + t.logger.addAppender(appender); + t.logger.debug("TEST MESSAGE"); + }; + + s.test("InlineAppender test", function(t) { + var inlineAppender = new log4javascript.InlineAppender(); + inlineAppender.setInitiallyMinimized(false); + inlineAppender.setNewestMessageAtTop(false); + inlineAppender.setScrollToLatestMessage(true); + inlineAppender.setWidth(600); + inlineAppender.setHeight(200); + + testConsoleAppender(t, inlineAppender); + }); + + s.test("InPageAppender with separate console HTML file test", function(t) { + var inPageAppender = new log4javascript.InPageAppender(); + inPageAppender.setInitiallyMinimized(false); + inPageAppender.setNewestMessageAtTop(false); + inPageAppender.setScrollToLatestMessage(true); + inPageAppender.setUseDocumentWrite(false); + inPageAppender.setWidth(600); + inPageAppender.setHeight(200); + + testConsoleAppender(t, inPageAppender); + }); + + s.test("PopUpAppender test", function(t) { + var popUpAppender = new log4javascript.PopUpAppender(); + popUpAppender.setFocusPopUp(true); + popUpAppender.setUseOldPopUp(false); + popUpAppender.setNewestMessageAtTop(false); + popUpAppender.setScrollToLatestMessage(true); + popUpAppender.setComplainAboutPopUpBlocking(false); + popUpAppender.setWidth(600); + popUpAppender.setHeight(200); + + testConsoleAppender(t, popUpAppender); + + + }); + + s.test("PopUpAppender with separate console HTML file test", function(t) { + var popUpAppender = new log4javascript.PopUpAppender(); + popUpAppender.setFocusPopUp(true); + popUpAppender.setUseOldPopUp(false); + popUpAppender.setNewestMessageAtTop(false); + popUpAppender.setScrollToLatestMessage(true); + popUpAppender.setComplainAboutPopUpBlocking(false); + popUpAppender.setUseDocumentWrite(false); + popUpAppender.setWidth(600); + popUpAppender.setHeight(200); + + testConsoleAppender(t, popUpAppender); + }); +}); \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/license.txt b/planetstack/core/static/log4javascript-1.4.6/license.txt new file mode 100644 index 0000000..29f81d8 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/license.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/planetstack/core/static/log4javascript-1.4.6/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/log4javascript.js new file mode 100644 index 0000000..042daa9 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/log4javascript.js @@ -0,0 +1,274 @@ +/** + * Copyright 2013 Tim Down. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i0){var firstItem=this[0];for(var i=0,len=this.length-1;i2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();} +Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+ +toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i1&&isError(lastParam)){exception=lastParam;finalParamIndex--;} +var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];} +var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};} +Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+ +toStr(loggerName)+" supplied, returning anonymous logger");} +if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");} +if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;} +parentLogger.addChild(logger);} +return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);} +return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);} +return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);} +if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);} +if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+ +this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+ +this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];} +SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];} +NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];} +XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]>";} +var str=""+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+=""+newLine;for(i=0,len=loggingEvent.messages.length;i"+newLine;}} +if(loggingEvent.exception){str+=""+newLine;} +str+=""+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");} +function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];} +JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+" ";childLines=[];for(i=0,len=obj.length;i0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+" ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+ +getExceptionStringRep(ex));}} +expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}} +return doFormat(obj,depth,indentation);} +var SimpleDateFormat;(function(){var 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']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()=minimalDaysInFirstWeek){weekInMonth++;} +return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;} +switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);} +break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);} +break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}} +searchString=searchString.substr(result.index+result[0].length);} +return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;} +this.customFields=[];} +PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}} +var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";} +if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}} +break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;} +break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}} +replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+ +specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}} +var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);} +replacement=val;} +break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;} +var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l=200&&xmlHttp.status<300)||xmlHttp.status==1223;} +function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;} +var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+ +configOptionName+"' may not be set after the appender has been initialized");return false;} +return true;} +this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));} +sending=false;if(timed){scheduleSending();}}}} +this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}} +if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);} +sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();} +return sendingAnything;} +this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();} +formattedMessages.push(currentFormattedMessage);} +if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+ +formattedMessages.join(appender.getLayout().batchSeparator)+ +appender.getLayout().batchFooter;} +if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";} +postData+="layout="+urlEncode(appender.getLayout().toString());} +return postData;} +function scheduleSending(){window.setTimeout(sendAll,timerInterval);} +function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}} +function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());} +xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);} +if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+ +url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}} +xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);} +xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);} +return;} +xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}} +this.append=function(loggingEvent){if(isSupported){if(!initialized){init();} +queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);} +queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();} +if(sendAllRemaining()){return"Sending log messages";}};} +if(timed){scheduleSending();}}} +AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;function setCookie(name,value,days,path){var expires;path=path?"; path="+path:"";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString();}else{expires="";} +document.cookie=escape(name)+"="+escape(value)+expires+path;} +function getCookie(name){var nameEquals=escape(name)+"=";var ca=document.cookie.split(";");for(var i=0,len=ca.length;i','','','log4javascript','','','','','','','','','','','
','
','
','Filters:','','','','','','','','
','','
','Options:','','','','','','','','
','
','
','
','
','
','','','
','
','','',''];};var defaultCommandLineFunctions=[];ConsoleAppender=function(){};var consoleAppenderIdCounter=1;ConsoleAppender.prototype=new Appender();ConsoleAppender.prototype.create=function(inPage,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,focusConsoleWindow){var appender=this;var initialized=false;var consoleWindowCreated=false;var consoleWindowLoaded=false;var consoleClosed=false;var queuedLoggingEvents=[];var isSupported=true;var consoleAppenderId=consoleAppenderIdCounter++;initiallyMinimized=extractBooleanFromParam(initiallyMinimized,this.defaults.initiallyMinimized);lazyInit=extractBooleanFromParam(lazyInit,this.defaults.lazyInit);useDocumentWrite=extractBooleanFromParam(useDocumentWrite,this.defaults.useDocumentWrite);var newestMessageAtTop=this.defaults.newestMessageAtTop;var scrollToLatestMessage=this.defaults.scrollToLatestMessage;width=width?width:this.defaults.width;height=height?height:this.defaults.height;var maxMessages=this.defaults.maxMessages;var showCommandLine=this.defaults.showCommandLine;var commandLineObjectExpansionDepth=this.defaults.commandLineObjectExpansionDepth;var showHideButton=this.defaults.showHideButton;var showCloseButton=this.defaults.showCloseButton;var showLogEntryDeleteButtons=this.defaults.showLogEntryDeleteButtons;this.setLayout(this.defaults.layout);var init,createWindow,safeToAppend,getConsoleWindow,open;var appenderName=inPage?"InPageAppender":"PopUpAppender";var checkCanConfigure=function(configOptionName){if(consoleWindowCreated){handleError(appenderName+": configuration option '"+configOptionName+"' may not be set after the appender has been initialized");return false;} +return true;};var consoleWindowExists=function(){return(consoleWindowLoaded&&isSupported&&!consoleClosed);};this.isNewestMessageAtTop=function(){return newestMessageAtTop;};this.setNewestMessageAtTop=function(newestMessageAtTopParam){newestMessageAtTop=bool(newestMessageAtTopParam);if(consoleWindowExists()){getConsoleWindow().setNewestAtTop(newestMessageAtTop);}};this.isScrollToLatestMessage=function(){return scrollToLatestMessage;};this.setScrollToLatestMessage=function(scrollToLatestMessageParam){scrollToLatestMessage=bool(scrollToLatestMessageParam);if(consoleWindowExists()){getConsoleWindow().setScrollToLatest(scrollToLatestMessage);}};this.getWidth=function(){return width;};this.setWidth=function(widthParam){if(checkCanConfigure("width")){width=extractStringFromParam(widthParam,width);}};this.getHeight=function(){return height;};this.setHeight=function(heightParam){if(checkCanConfigure("height")){height=extractStringFromParam(heightParam,height);}};this.getMaxMessages=function(){return maxMessages;};this.setMaxMessages=function(maxMessagesParam){maxMessages=extractIntFromParam(maxMessagesParam,maxMessages);if(consoleWindowExists()){getConsoleWindow().setMaxMessages(maxMessages);}};this.isShowCommandLine=function(){return showCommandLine;};this.setShowCommandLine=function(showCommandLineParam){showCommandLine=bool(showCommandLineParam);if(consoleWindowExists()){getConsoleWindow().setShowCommandLine(showCommandLine);}};this.isShowHideButton=function(){return showHideButton;};this.setShowHideButton=function(showHideButtonParam){showHideButton=bool(showHideButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowHideButton(showHideButton);}};this.isShowCloseButton=function(){return showCloseButton;};this.setShowCloseButton=function(showCloseButtonParam){showCloseButton=bool(showCloseButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowCloseButton(showCloseButton);}};this.getCommandLineObjectExpansionDepth=function(){return commandLineObjectExpansionDepth;};this.setCommandLineObjectExpansionDepth=function(commandLineObjectExpansionDepthParam){commandLineObjectExpansionDepth=extractIntFromParam(commandLineObjectExpansionDepthParam,commandLineObjectExpansionDepth);};var minimized=initiallyMinimized;this.isInitiallyMinimized=function(){return initiallyMinimized;};this.setInitiallyMinimized=function(initiallyMinimizedParam){if(checkCanConfigure("initiallyMinimized")){initiallyMinimized=bool(initiallyMinimizedParam);minimized=initiallyMinimized;}};this.isUseDocumentWrite=function(){return useDocumentWrite;};this.setUseDocumentWrite=function(useDocumentWriteParam){if(checkCanConfigure("useDocumentWrite")){useDocumentWrite=bool(useDocumentWriteParam);}};function QueuedLoggingEvent(loggingEvent,formattedMessage){this.loggingEvent=loggingEvent;this.levelName=loggingEvent.level.name;this.formattedMessage=formattedMessage;} +QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;} +QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){} +QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();} +if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();} +queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent,formattedMessage));checkAndAppend();}};this.group=function(name,initiallyExpanded){if(isSupported){queuedLoggingEvents.push(new QueuedGroup(name,initiallyExpanded));checkAndAppend();}};this.groupEnd=function(){if(isSupported){queuedLoggingEvents.push(new QueuedGroupEnd());checkAndAppend();}};var appendQueuedLoggingEvents=function(){var currentLoggingEvent;while(queuedLoggingEvents.length>0){queuedLoggingEvents.shift().append();} +if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();} +queuedLoggingEvents.length=0;};this.focus=function(){if(consoleWindowExists()){getConsoleWindow().focus();}};this.focusCommandLine=function(){if(consoleWindowExists()){getConsoleWindow().focusCommandLine();}};this.focusSearch=function(){if(consoleWindowExists()){getConsoleWindow().focusSearch();}};var commandWindow=window;this.getCommandWindow=function(){return commandWindow;};this.setCommandWindow=function(commandWindowParam){commandWindow=commandWindowParam;};this.executeLastCommand=function(){if(consoleWindowExists()){getConsoleWindow().evalLastCommand();}};var commandLayout=new PatternLayout("%m");this.getCommandLayout=function(){return commandLayout;};this.setCommandLayout=function(commandLayoutParam){commandLayout=commandLayoutParam;};this.evalCommandAndAppend=function(expr){var commandReturnValue={appendResult:true,isError:false};var commandOutput="";try{var result,i;if(!commandWindow.eval&&commandWindow.execScript){commandWindow.execScript("null");} +var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i";consoleClosed=false;var iframeDocumentExistsTest=function(win){try{return bool(win)&&bool(win.document);}catch(ex){return false;}};if(iframeDocumentExistsTest(getConsoleWindow())){writeToDocument();}else{pollConsoleWindow(iframeDocumentExistsTest,100,writeToDocument,initErrorMessage);} +consoleWindowCreated=true;};createWindow=function(show){if(show||!initiallyMinimized){var pageLoadHandler=function(){if(!container){containerElement=document.createElement("div");containerElement.style.position="fixed";containerElement.style.left="0";containerElement.style.right="0";containerElement.style.bottom="0";document.body.appendChild(containerElement);appender.addCssProperty("borderWidth","1px 0 0 0");appender.addCssProperty("zIndex",1000000);open();}else{try{var el=document.getElementById(container);if(el.nodeType==1){containerElement=el;} +open();}catch(ex){handleError("InPageAppender.init: invalid container element '"+container+"' supplied",ex);}}};if(pageLoaded&&container&&container.appendChild){containerElement=container;open();}else if(pageLoaded){pageLoadHandler();}else{log4javascript.addEventListener("load",pageLoadHandler);} +windowCreationStarted=true;}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){var iframe=window.frames[iframeId];if(iframe){return iframe;}};safeToAppend=function(){if(isSupported&&!consoleClosed){if(consoleWindowCreated&&!consoleWindowLoaded&&getConsoleWindow()&&isLoaded(getConsoleWindow())){consoleWindowLoaded=true;} +return consoleWindowLoaded;} +return false;};}else{var useOldPopUp=appender.defaults.useOldPopUp;var complainAboutPopUpBlocking=appender.defaults.complainAboutPopUpBlocking;var reopenWhenClosed=this.defaults.reopenWhenClosed;this.isUseOldPopUp=function(){return useOldPopUp;};this.setUseOldPopUp=function(useOldPopUpParam){if(checkCanConfigure("useOldPopUp")){useOldPopUp=bool(useOldPopUpParam);}};this.isComplainAboutPopUpBlocking=function(){return complainAboutPopUpBlocking;};this.setComplainAboutPopUpBlocking=function(complainAboutPopUpBlockingParam){if(checkCanConfigure("complainAboutPopUpBlocking")){complainAboutPopUpBlocking=bool(complainAboutPopUpBlockingParam);}};this.isFocusPopUp=function(){return focusConsoleWindow;};this.setFocusPopUp=function(focusPopUpParam){focusConsoleWindow=bool(focusPopUpParam);};this.isReopenWhenClosed=function(){return reopenWhenClosed;};this.setReopenWhenClosed=function(reopenWhenClosedParam){reopenWhenClosed=bool(reopenWhenClosedParam);};this.close=function(){logLog.debug("close "+this);try{popUp.close();this.unload();}catch(ex){}};this.hide=function(){logLog.debug("hide "+this);if(consoleWindowExists()){this.close();}};this.show=function(){logLog.debug("show "+this);if(!consoleWindowCreated){open();}};this.isVisible=function(){return safeToAppend();};var popUp;open=function(){var windowProperties="width="+width+",height="+height+",status,resizable";var frameInfo="";try{var frameEl=window.frameElement;if(frameEl){frameInfo="_"+frameEl.tagName+"_"+(frameEl.name||frameEl.id||"");}}catch(e){frameInfo="_inaccessibleParentFrame";} +var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;} +var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}} +return false;};var popUpClosedCallback=function(){if(!consoleClosed){appender.unload();}};function finalInit(){getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp||!useDocumentWrite);consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();pollConsoleWindow(checkPopUpClosed,500,popUpClosedCallback,"PopUpAppender.checkPopUpClosed: error checking pop-up window");} +try{popUp=window.open(getConsoleUrl(),windowName,windowProperties);consoleClosed=false;consoleWindowCreated=true;if(popUp&&popUp.document){if(useDocumentWrite&&useOldPopUp&&isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{if(useDocumentWrite){writeHtml(popUp.document);} +var popUpLoadedTest=function(win){return bool(win)&&isLoaded(win);};if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow(popUpLoadedTest,100,finalInit,"PopUpAppender.init: unable to create console window");}}}else{isSupported=false;logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");if(complainAboutPopUpBlocking){handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}}catch(ex){handleError("PopUpAppender.init: error creating pop-up",ex);}};createWindow=function(){if(!initiallyMinimized){open();}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){return popUp;};safeToAppend=function(){if(isSupported&&!isUndefined(popUp)&&!consoleClosed){if(popUp.closed||(consoleWindowLoaded&&isUndefined(popUp.closed))){appender.unload();logLog.debug("PopUpAppender: pop-up closed");return false;} +if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}} +return isSupported&&consoleWindowLoaded&&!consoleClosed;};} +this.getConsoleWindow=getConsoleWindow;};ConsoleAppender.addGlobalCommandLineFunction=function(functionName,commandLineFunction){defaultCommandLineFunctions.push([functionName,commandLineFunction]);};function PopUpAppender(lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(false,null,lazyInit,initiallyMinimized,useDocumentWrite,width,height,this.defaults.focusPopUp);} +PopUpAppender.prototype=new ConsoleAppender();PopUpAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,focusPopUp:false,lazyInit:true,useOldPopUp:true,complainAboutPopUpBlocking:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"600",height:"400",reopenWhenClosed:false,maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:true,showLogEntryDeleteButtons:true,useDocumentWrite:true};PopUpAppender.prototype.toString=function(){return"PopUpAppender";};log4javascript.PopUpAppender=PopUpAppender;function InPageAppender(container,lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(true,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,false);} +InPageAppender.prototype=new ConsoleAppender();InPageAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,lazyInit:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"100%",height:"220px",maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:false,showLogEntryDeleteButtons:true,useDocumentWrite:true};InPageAppender.prototype.toString=function(){return"InPageAppender";};log4javascript.InPageAppender=InPageAppender;log4javascript.InlineAppender=InPageAppender;})();function padWithSpaces(str,len){if(str.length]*>","i");if(regex.test(el.outerHTML)){return RegExp.$1.toLowerCase();}} +return"";} +var lt="<";var gt=">";if(includeRootNode&&rootNode.nodeType!=nodeTypes.DOCUMENT_FRAGMENT_NODE){switch(rootNode.nodeType){case nodeTypes.ELEMENT_NODE:var tagName=rootNode.tagName.toLowerCase();xhtml=startNewLine?newLine+indentation:"";xhtml+=lt;var prefix=getNamespace(rootNode);var hasPrefix=!!prefix;if(hasPrefix){xhtml+=prefix+":";} +xhtml+=tagName;for(i=0,len=rootNode.attributes.length;i"+newLine;case nodeTypes.DOCUMENT_NODE:xhtml="";for(var i=0,len=rootNode.childNodes.length;i + * Version: 1.4.6 + * Edition: log4javascript + * Build date: 19 March 2013 + * Website: http://log4javascript.org + */ + +/* -------------------------------------------------------------------------- */ +// Array-related stuff + +// Next three methods are solely for IE5, which is missing them +if (!Array.prototype.push) { + Array.prototype.push = function() { + for (var i = 0, len = arguments.length; i < len; i++){ + this[this.length] = arguments[i]; + } + return this.length; + }; +} + +if (!Array.prototype.shift) { + Array.prototype.shift = function() { + if (this.length > 0) { + var firstItem = this[0]; + for (var i = 0, len = this.length - 1; i < len; i++) { + this[i] = this[i + 1]; + } + this.length = this.length - 1; + return firstItem; + } + }; +} + +if (!Array.prototype.splice) { + Array.prototype.splice = function(startIndex, deleteCount) { + var itemsAfterDeleted = this.slice(startIndex + deleteCount); + var itemsDeleted = this.slice(startIndex, startIndex + deleteCount); + this.length = startIndex; + // Copy the arguments into a proper Array object + var argumentsArray = []; + for (var i = 0, len = arguments.length; i < len; i++) { + argumentsArray[i] = arguments[i]; + } + var itemsToAppend = (argumentsArray.length > 2) ? + itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted; + for (i = 0, len = itemsToAppend.length; i < len; i++) { + this.push(itemsToAppend[i]); + } + return itemsDeleted; + }; +} + +/* -------------------------------------------------------------------------- */ + +var log4javascript = (function() { + + function isUndefined(obj) { + return typeof obj == "undefined"; + } + + /* ---------------------------------------------------------------------- */ + // Custom event support + + function EventSupport() {} + + EventSupport.prototype = { + eventTypes: [], + eventListeners: {}, + setEventTypes: function(eventTypesParam) { + if (eventTypesParam instanceof Array) { + this.eventTypes = eventTypesParam; + this.eventListeners = {}; + for (var i = 0, len = this.eventTypes.length; i < len; i++) { + this.eventListeners[this.eventTypes[i]] = []; + } + } else { + handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array"); + } + }, + + addEventListener: function(eventType, listener) { + if (typeof listener == "function") { + if (!array_contains(this.eventTypes, eventType)) { + handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'"); + } + this.eventListeners[eventType].push(listener); + } else { + handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function"); + } + }, + + removeEventListener: function(eventType, listener) { + if (typeof listener == "function") { + if (!array_contains(this.eventTypes, eventType)) { + handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'"); + } + array_remove(this.eventListeners[eventType], listener); + } else { + handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function"); + } + }, + + dispatchEvent: function(eventType, eventArgs) { + if (array_contains(this.eventTypes, eventType)) { + var listeners = this.eventListeners[eventType]; + for (var i = 0, len = listeners.length; i < len; i++) { + listeners[i](this, eventType, eventArgs); + } + } else { + handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'"); + } + } + }; + + /* -------------------------------------------------------------------------- */ + + var applicationStartDate = new Date(); + var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" + + Math.floor(Math.random() * 100000000); + var emptyFunction = function() {}; + var newLine = "\r\n"; + var pageLoaded = false; + + // Create main log4javascript object; this will be assigned public properties + function Log4JavaScript() {} + Log4JavaScript.prototype = new EventSupport(); + + log4javascript = new Log4JavaScript(); + log4javascript.version = "1.4.6"; + log4javascript.edition = "log4javascript"; + + /* -------------------------------------------------------------------------- */ + // Utility functions + + function toStr(obj) { + if (obj && obj.toString) { + return obj.toString(); + } else { + return String(obj); + } + } + + function getExceptionMessage(ex) { + if (ex.message) { + return ex.message; + } else if (ex.description) { + return ex.description; + } else { + return toStr(ex); + } + } + + // Gets the portion of the URL after the last slash + function getUrlFileName(url) { + var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\")); + return url.substr(lastSlashIndex + 1); + } + + // Returns a nicely formatted representation of an error + function getExceptionStringRep(ex) { + if (ex) { + var exStr = "Exception: " + getExceptionMessage(ex); + try { + if (ex.lineNumber) { + exStr += " on line number " + ex.lineNumber; + } + if (ex.fileName) { + exStr += " in file " + getUrlFileName(ex.fileName); + } + } catch (localEx) { + logLog.warn("Unable to obtain file and line information for error"); + } + if (showStackTraces && ex.stack) { + exStr += newLine + "Stack trace:" + newLine + ex.stack; + } + return exStr; + } + return null; + } + + function bool(obj) { + return Boolean(obj); + } + + function trim(str) { + return str.replace(/^\s+/, "").replace(/\s+$/, ""); + } + + function splitIntoLines(text) { + // Ensure all line breaks are \n only + var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); + return text2.split("\n"); + } + + var urlEncode = (typeof window.encodeURIComponent != "undefined") ? + function(str) { + return encodeURIComponent(str); + }: + function(str) { + return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D"); + }; + + var urlDecode = (typeof window.decodeURIComponent != "undefined") ? + function(str) { + return decodeURIComponent(str); + }: + function(str) { + return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "="); + }; + + function array_remove(arr, val) { + var index = -1; + for (var i = 0, len = arr.length; i < len; i++) { + if (arr[i] === val) { + index = i; + break; + } + } + if (index >= 0) { + arr.splice(index, 1); + return true; + } else { + return false; + } + } + + function array_contains(arr, val) { + for(var i = 0, len = arr.length; i < len; i++) { + if (arr[i] == val) { + return true; + } + } + return false; + } + + function extractBooleanFromParam(param, defaultValue) { + if (isUndefined(param)) { + return defaultValue; + } else { + return bool(param); + } + } + + function extractStringFromParam(param, defaultValue) { + if (isUndefined(param)) { + return defaultValue; + } else { + return String(param); + } + } + + function extractIntFromParam(param, defaultValue) { + if (isUndefined(param)) { + return defaultValue; + } else { + try { + var value = parseInt(param, 10); + return isNaN(value) ? defaultValue : value; + } catch (ex) { + logLog.warn("Invalid int param " + param, ex); + return defaultValue; + } + } + } + + function extractFunctionFromParam(param, defaultValue) { + if (typeof param == "function") { + return param; + } else { + return defaultValue; + } + } + + function isError(err) { + return (err instanceof Error); + } + + if (!Function.prototype.apply){ + Function.prototype.apply = function(obj, args) { + var methodName = "__apply__"; + if (typeof obj[methodName] != "undefined") { + methodName += String(Math.random()).substr(2); + } + obj[methodName] = this; + + var argsStrings = []; + for (var i = 0, len = args.length; i < len; i++) { + argsStrings[i] = "args[" + i + "]"; + } + var script = "obj." + methodName + "(" + argsStrings.join(",") + ")"; + var returnValue = eval(script); + delete obj[methodName]; + return returnValue; + }; + } + + if (!Function.prototype.call){ + Function.prototype.call = function(obj) { + var args = []; + for (var i = 1, len = arguments.length; i < len; i++) { + args[i - 1] = arguments[i]; + } + return this.apply(obj, args); + }; + } + + function getListenersPropertyName(eventName) { + return "__log4javascript_listeners__" + eventName; + } + + function addEvent(node, eventName, listener, useCapture, win) { + win = win ? win : window; + if (node.addEventListener) { + node.addEventListener(eventName, listener, useCapture); + } else if (node.attachEvent) { + node.attachEvent("on" + eventName, listener); + } else { + var propertyName = getListenersPropertyName(eventName); + if (!node[propertyName]) { + node[propertyName] = []; + // Set event handler + node["on" + eventName] = function(evt) { + evt = getEvent(evt, win); + var listenersPropertyName = getListenersPropertyName(eventName); + + // Clone the array of listeners to leave the original untouched + var listeners = this[listenersPropertyName].concat([]); + var currentListener; + + // Call each listener in turn + while ((currentListener = listeners.shift())) { + currentListener.call(this, evt); + } + }; + } + node[propertyName].push(listener); + } + } + + function removeEvent(node, eventName, listener, useCapture) { + if (node.removeEventListener) { + node.removeEventListener(eventName, listener, useCapture); + } else if (node.detachEvent) { + node.detachEvent("on" + eventName, listener); + } else { + var propertyName = getListenersPropertyName(eventName); + if (node[propertyName]) { + array_remove(node[propertyName], listener); + } + } + } + + function getEvent(evt, win) { + win = win ? win : window; + return evt ? evt : win.event; + } + + function stopEventPropagation(evt) { + if (evt.stopPropagation) { + evt.stopPropagation(); + } else if (typeof evt.cancelBubble != "undefined") { + evt.cancelBubble = true; + } + evt.returnValue = false; + } + + /* ---------------------------------------------------------------------- */ + // Simple logging for log4javascript itself + + var logLog = { + quietMode: false, + + debugMessages: [], + + setQuietMode: function(quietMode) { + this.quietMode = bool(quietMode); + }, + + numberOfErrors: 0, + + alertAllErrors: false, + + setAlertAllErrors: function(alertAllErrors) { + this.alertAllErrors = alertAllErrors; + }, + + debug: function(message) { + this.debugMessages.push(message); + }, + + displayDebug: function() { + alert(this.debugMessages.join(newLine)); + }, + + warn: function(message, exception) { + }, + + error: function(message, exception) { + if (++this.numberOfErrors == 1 || this.alertAllErrors) { + if (!this.quietMode) { + var alertMessage = "log4javascript error: " + message; + if (exception) { + alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception); + } + alert(alertMessage); + } + } + } + }; + log4javascript.logLog = logLog; + + log4javascript.setEventTypes(["load", "error"]); + + function handleError(message, exception) { + logLog.error(message, exception); + log4javascript.dispatchEvent("error", { "message": message, "exception": exception }); + } + + log4javascript.handleError = handleError; + + /* ---------------------------------------------------------------------- */ + + var enabled = !((typeof log4javascript_disabled != "undefined") && + log4javascript_disabled); + + log4javascript.setEnabled = function(enable) { + enabled = bool(enable); + }; + + log4javascript.isEnabled = function() { + return enabled; + }; + + var useTimeStampsInMilliseconds = true; + + log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) { + useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds); + }; + + log4javascript.isTimeStampsInMilliseconds = function() { + return useTimeStampsInMilliseconds; + }; + + + // This evaluates the given expression in the current scope, thus allowing + // scripts to access private variables. Particularly useful for testing + log4javascript.evalInScope = function(expr) { + return eval(expr); + }; + + var showStackTraces = false; + + log4javascript.setShowStackTraces = function(show) { + showStackTraces = bool(show); + }; + + /* ---------------------------------------------------------------------- */ + // Levels + + var Level = function(level, name) { + this.level = level; + this.name = name; + }; + + Level.prototype = { + toString: function() { + return this.name; + }, + equals: function(level) { + return this.level == level.level; + }, + isGreaterOrEqual: function(level) { + return this.level >= level.level; + } + }; + + Level.ALL = new Level(Number.MIN_VALUE, "ALL"); + Level.TRACE = new Level(10000, "TRACE"); + Level.DEBUG = new Level(20000, "DEBUG"); + Level.INFO = new Level(30000, "INFO"); + Level.WARN = new Level(40000, "WARN"); + Level.ERROR = new Level(50000, "ERROR"); + Level.FATAL = new Level(60000, "FATAL"); + Level.OFF = new Level(Number.MAX_VALUE, "OFF"); + + log4javascript.Level = Level; + + /* ---------------------------------------------------------------------- */ + // Timers + + function Timer(name, level) { + this.name = name; + this.level = isUndefined(level) ? Level.INFO : level; + this.start = new Date(); + } + + Timer.prototype.getElapsedTime = function() { + return new Date().getTime() - this.start.getTime(); + }; + + /* ---------------------------------------------------------------------- */ + // Loggers + + var anonymousLoggerName = "[anonymous]"; + var defaultLoggerName = "[default]"; + var nullLoggerName = "[null]"; + var rootLoggerName = "root"; + + function Logger(name) { + this.name = name; + this.parent = null; + this.children = []; + + var appenders = []; + var loggerLevel = null; + var isRoot = (this.name === rootLoggerName); + var isNull = (this.name === nullLoggerName); + + var appenderCache = null; + var appenderCacheInvalidated = false; + + this.addChild = function(childLogger) { + this.children.push(childLogger); + childLogger.parent = this; + childLogger.invalidateAppenderCache(); + }; + + // Additivity + var additive = true; + this.getAdditivity = function() { + return additive; + }; + + this.setAdditivity = function(additivity) { + var valueChanged = (additive != additivity); + additive = additivity; + if (valueChanged) { + this.invalidateAppenderCache(); + } + }; + + // Create methods that use the appenders variable in this scope + this.addAppender = function(appender) { + if (isNull) { + handleError("Logger.addAppender: you may not add an appender to the null logger"); + } else { + if (appender instanceof log4javascript.Appender) { + if (!array_contains(appenders, appender)) { + appenders.push(appender); + appender.setAddedToLogger(this); + this.invalidateAppenderCache(); + } + } else { + handleError("Logger.addAppender: appender supplied ('" + + toStr(appender) + "') is not a subclass of Appender"); + } + } + }; + + this.removeAppender = function(appender) { + array_remove(appenders, appender); + appender.setRemovedFromLogger(this); + this.invalidateAppenderCache(); + }; + + this.removeAllAppenders = function() { + var appenderCount = appenders.length; + if (appenderCount > 0) { + for (var i = 0; i < appenderCount; i++) { + appenders[i].setRemovedFromLogger(this); + } + appenders.length = 0; + this.invalidateAppenderCache(); + } + }; + + this.getEffectiveAppenders = function() { + if (appenderCache === null || appenderCacheInvalidated) { + // Build appender cache + var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ? + [] : this.parent.getEffectiveAppenders(); + appenderCache = parentEffectiveAppenders.concat(appenders); + appenderCacheInvalidated = false; + } + return appenderCache; + }; + + this.invalidateAppenderCache = function() { + appenderCacheInvalidated = true; + for (var i = 0, len = this.children.length; i < len; i++) { + this.children[i].invalidateAppenderCache(); + } + }; + + this.log = function(level, params) { + if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) { + // Check whether last param is an exception + var exception; + var finalParamIndex = params.length - 1; + var lastParam = params[finalParamIndex]; + if (params.length > 1 && isError(lastParam)) { + exception = lastParam; + finalParamIndex--; + } + + // Construct genuine array for the params + var messages = []; + for (var i = 0; i <= finalParamIndex; i++) { + messages[i] = params[i]; + } + + var loggingEvent = new LoggingEvent( + this, new Date(), level, messages, exception); + + this.callAppenders(loggingEvent); + } + }; + + this.callAppenders = function(loggingEvent) { + var effectiveAppenders = this.getEffectiveAppenders(); + for (var i = 0, len = effectiveAppenders.length; i < len; i++) { + effectiveAppenders[i].doAppend(loggingEvent); + } + }; + + this.setLevel = function(level) { + // Having a level of null on the root logger would be very bad. + if (isRoot && level === null) { + handleError("Logger.setLevel: you cannot set the level of the root logger to null"); + } else if (level instanceof Level) { + loggerLevel = level; + } else { + handleError("Logger.setLevel: level supplied to logger " + + this.name + " is not an instance of log4javascript.Level"); + } + }; + + this.getLevel = function() { + return loggerLevel; + }; + + this.getEffectiveLevel = function() { + for (var logger = this; logger !== null; logger = logger.parent) { + var level = logger.getLevel(); + if (level !== null) { + return level; + } + } + }; + + this.group = function(name, initiallyExpanded) { + if (enabled) { + var effectiveAppenders = this.getEffectiveAppenders(); + for (var i = 0, len = effectiveAppenders.length; i < len; i++) { + effectiveAppenders[i].group(name, initiallyExpanded); + } + } + }; + + this.groupEnd = function() { + if (enabled) { + var effectiveAppenders = this.getEffectiveAppenders(); + for (var i = 0, len = effectiveAppenders.length; i < len; i++) { + effectiveAppenders[i].groupEnd(); + } + } + }; + + var timers = {}; + + this.time = function(name, level) { + if (enabled) { + if (isUndefined(name)) { + handleError("Logger.time: a name for the timer must be supplied"); + } else if (level && !(level instanceof Level)) { + handleError("Logger.time: level supplied to timer " + + name + " is not an instance of log4javascript.Level"); + } else { + timers[name] = new Timer(name, level); + } + } + }; + + this.timeEnd = function(name) { + if (enabled) { + if (isUndefined(name)) { + handleError("Logger.timeEnd: a name for the timer must be supplied"); + } else if (timers[name]) { + var timer = timers[name]; + var milliseconds = timer.getElapsedTime(); + this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]); + delete timers[name]; + } else { + logLog.warn("Logger.timeEnd: no timer found with name " + name); + } + } + }; + + this.assert = function(expr) { + if (enabled && !expr) { + var args = []; + for (var i = 1, len = arguments.length; i < len; i++) { + args.push(arguments[i]); + } + args = (args.length > 0) ? args : ["Assertion Failure"]; + args.push(newLine); + args.push(expr); + this.log(Level.ERROR, args); + } + }; + + this.toString = function() { + return "Logger[" + this.name + "]"; + }; + } + + Logger.prototype = { + trace: function() { + this.log(Level.TRACE, arguments); + }, + + debug: function() { + this.log(Level.DEBUG, arguments); + }, + + info: function() { + this.log(Level.INFO, arguments); + }, + + warn: function() { + this.log(Level.WARN, arguments); + }, + + error: function() { + this.log(Level.ERROR, arguments); + }, + + fatal: function() { + this.log(Level.FATAL, arguments); + }, + + isEnabledFor: function(level) { + return level.isGreaterOrEqual(this.getEffectiveLevel()); + }, + + isTraceEnabled: function() { + return this.isEnabledFor(Level.TRACE); + }, + + isDebugEnabled: function() { + return this.isEnabledFor(Level.DEBUG); + }, + + isInfoEnabled: function() { + return this.isEnabledFor(Level.INFO); + }, + + isWarnEnabled: function() { + return this.isEnabledFor(Level.WARN); + }, + + isErrorEnabled: function() { + return this.isEnabledFor(Level.ERROR); + }, + + isFatalEnabled: function() { + return this.isEnabledFor(Level.FATAL); + } + }; + + Logger.prototype.trace.isEntryPoint = true; + Logger.prototype.debug.isEntryPoint = true; + Logger.prototype.info.isEntryPoint = true; + Logger.prototype.warn.isEntryPoint = true; + Logger.prototype.error.isEntryPoint = true; + Logger.prototype.fatal.isEntryPoint = true; + + /* ---------------------------------------------------------------------- */ + // Logger access methods + + // Hashtable of loggers keyed by logger name + var loggers = {}; + var loggerNames = []; + + var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG; + var rootLogger = new Logger(rootLoggerName); + rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL); + + log4javascript.getRootLogger = function() { + return rootLogger; + }; + + log4javascript.getLogger = function(loggerName) { + // Use default logger if loggerName is not specified or invalid + if (!(typeof loggerName == "string")) { + loggerName = anonymousLoggerName; + logLog.warn("log4javascript.getLogger: non-string logger name " + + toStr(loggerName) + " supplied, returning anonymous logger"); + } + + // Do not allow retrieval of the root logger by name + if (loggerName == rootLoggerName) { + handleError("log4javascript.getLogger: root logger may not be obtained by name"); + } + + // Create the logger for this name if it doesn't already exist + if (!loggers[loggerName]) { + var logger = new Logger(loggerName); + loggers[loggerName] = logger; + loggerNames.push(loggerName); + + // Set up parent logger, if it doesn't exist + var lastDotIndex = loggerName.lastIndexOf("."); + var parentLogger; + if (lastDotIndex > -1) { + var parentLoggerName = loggerName.substring(0, lastDotIndex); + parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc. + } else { + parentLogger = rootLogger; + } + parentLogger.addChild(logger); + } + return loggers[loggerName]; + }; + + var defaultLogger = null; + log4javascript.getDefaultLogger = function() { + if (!defaultLogger) { + defaultLogger = log4javascript.getLogger(defaultLoggerName); + var a = new log4javascript.PopUpAppender(); + defaultLogger.addAppender(a); + } + return defaultLogger; + }; + + var nullLogger = null; + log4javascript.getNullLogger = function() { + if (!nullLogger) { + nullLogger = new Logger(nullLoggerName); + nullLogger.setLevel(Level.OFF); + } + return nullLogger; + }; + + // Destroys all loggers + log4javascript.resetConfiguration = function() { + rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL); + loggers = {}; + }; + + /* ---------------------------------------------------------------------- */ + // Logging events + + var LoggingEvent = function(logger, timeStamp, level, messages, + exception) { + this.logger = logger; + this.timeStamp = timeStamp; + this.timeStampInMilliseconds = timeStamp.getTime(); + this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000); + this.milliseconds = this.timeStamp.getMilliseconds(); + this.level = level; + this.messages = messages; + this.exception = exception; + }; + + LoggingEvent.prototype = { + getThrowableStrRep: function() { + return this.exception ? + getExceptionStringRep(this.exception) : ""; + }, + getCombinedMessages: function() { + return (this.messages.length == 1) ? this.messages[0] : + this.messages.join(newLine); + }, + toString: function() { + return "LoggingEvent[" + this.level + "]"; + } + }; + + log4javascript.LoggingEvent = LoggingEvent; + + /* ---------------------------------------------------------------------- */ + // Layout prototype + + var Layout = function() { + }; + + Layout.prototype = { + defaults: { + loggerKey: "logger", + timeStampKey: "timestamp", + millisecondsKey: "milliseconds", + levelKey: "level", + messageKey: "message", + exceptionKey: "exception", + urlKey: "url" + }, + loggerKey: "logger", + timeStampKey: "timestamp", + millisecondsKey: "milliseconds", + levelKey: "level", + messageKey: "message", + exceptionKey: "exception", + urlKey: "url", + batchHeader: "", + batchFooter: "", + batchSeparator: "", + returnsPostData: false, + overrideTimeStampsSetting: false, + useTimeStampsInMilliseconds: null, + + format: function() { + handleError("Layout.format: layout supplied has no format() method"); + }, + + ignoresThrowable: function() { + handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method"); + }, + + getContentType: function() { + return "text/plain"; + }, + + allowBatching: function() { + return true; + }, + + setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) { + this.overrideTimeStampsSetting = true; + this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds); + }, + + isTimeStampsInMilliseconds: function() { + return this.overrideTimeStampsSetting ? + this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds; + }, + + getTimeStampValue: function(loggingEvent) { + return this.isTimeStampsInMilliseconds() ? + loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds; + }, + + getDataValues: function(loggingEvent, combineMessages) { + var dataValues = [ + [this.loggerKey, loggingEvent.logger.name], + [this.timeStampKey, this.getTimeStampValue(loggingEvent)], + [this.levelKey, loggingEvent.level.name], + [this.urlKey, window.location.href], + [this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages] + ]; + if (!this.isTimeStampsInMilliseconds()) { + dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]); + } + if (loggingEvent.exception) { + dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]); + } + if (this.hasCustomFields()) { + for (var i = 0, len = this.customFields.length; i < len; i++) { + var val = this.customFields[i].value; + + // Check if the value is a function. If so, execute it, passing it the + // current layout and the logging event + if (typeof val === "function") { + val = val(this, loggingEvent); + } + dataValues.push([this.customFields[i].name, val]); + } + } + return dataValues; + }, + + setKeys: function(loggerKey, timeStampKey, levelKey, messageKey, + exceptionKey, urlKey, millisecondsKey) { + this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey); + this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey); + this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey); + this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey); + this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey); + this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey); + this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey); + }, + + setCustomField: function(name, value) { + var fieldUpdated = false; + for (var i = 0, len = this.customFields.length; i < len; i++) { + if (this.customFields[i].name === name) { + this.customFields[i].value = value; + fieldUpdated = true; + } + } + if (!fieldUpdated) { + this.customFields.push({"name": name, "value": value}); + } + }, + + hasCustomFields: function() { + return (this.customFields.length > 0); + }, + + toString: function() { + handleError("Layout.toString: all layouts must override this method"); + } + }; + + log4javascript.Layout = Layout; + + /* ---------------------------------------------------------------------- */ + // Appender prototype + + var Appender = function() {}; + + Appender.prototype = new EventSupport(); + + Appender.prototype.layout = new PatternLayout(); + Appender.prototype.threshold = Level.ALL; + Appender.prototype.loggers = []; + + // Performs threshold checks before delegating actual logging to the + // subclass's specific append method. + Appender.prototype.doAppend = function(loggingEvent) { + if (enabled && loggingEvent.level.level >= this.threshold.level) { + this.append(loggingEvent); + } + }; + + Appender.prototype.append = function(loggingEvent) {}; + + Appender.prototype.setLayout = function(layout) { + if (layout instanceof Layout) { + this.layout = layout; + } else { + handleError("Appender.setLayout: layout supplied to " + + this.toString() + " is not a subclass of Layout"); + } + }; + + Appender.prototype.getLayout = function() { + return this.layout; + }; + + Appender.prototype.setThreshold = function(threshold) { + if (threshold instanceof Level) { + this.threshold = threshold; + } else { + handleError("Appender.setThreshold: threshold supplied to " + + this.toString() + " is not a subclass of Level"); + } + }; + + Appender.prototype.getThreshold = function() { + return this.threshold; + }; + + Appender.prototype.setAddedToLogger = function(logger) { + this.loggers.push(logger); + }; + + Appender.prototype.setRemovedFromLogger = function(logger) { + array_remove(this.loggers, logger); + }; + + Appender.prototype.group = emptyFunction; + Appender.prototype.groupEnd = emptyFunction; + + Appender.prototype.toString = function() { + handleError("Appender.toString: all appenders must override this method"); + }; + + log4javascript.Appender = Appender; + + /* ---------------------------------------------------------------------- */ + // SimpleLayout + + function SimpleLayout() { + this.customFields = []; + } + + SimpleLayout.prototype = new Layout(); + + SimpleLayout.prototype.format = function(loggingEvent) { + return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages(); + }; + + SimpleLayout.prototype.ignoresThrowable = function() { + return true; + }; + + SimpleLayout.prototype.toString = function() { + return "SimpleLayout"; + }; + + log4javascript.SimpleLayout = SimpleLayout; + /* ----------------------------------------------------------------------- */ + // NullLayout + + function NullLayout() { + this.customFields = []; + } + + NullLayout.prototype = new Layout(); + + NullLayout.prototype.format = function(loggingEvent) { + return loggingEvent.messages; + }; + + NullLayout.prototype.ignoresThrowable = function() { + return true; + }; + + NullLayout.prototype.toString = function() { + return "NullLayout"; + }; + + log4javascript.NullLayout = NullLayout; +/* ---------------------------------------------------------------------- */ + // XmlLayout + + function XmlLayout(combineMessages) { + this.combineMessages = extractBooleanFromParam(combineMessages, true); + this.customFields = []; + } + + XmlLayout.prototype = new Layout(); + + XmlLayout.prototype.isCombinedMessages = function() { + return this.combineMessages; + }; + + XmlLayout.prototype.getContentType = function() { + return "text/xml"; + }; + + XmlLayout.prototype.escapeCdata = function(str) { + return str.replace(/\]\]>/, "]]>]]>
"; + } + + var str = "" + newLine; + if (this.combineMessages) { + str += formatMessage(loggingEvent.getCombinedMessages()); + } else { + str += "" + newLine; + for (i = 0, len = loggingEvent.messages.length; i < len; i++) { + str += formatMessage(loggingEvent.messages[i]) + newLine; + } + str += "" + newLine; + } + if (this.hasCustomFields()) { + for (i = 0, len = this.customFields.length; i < len; i++) { + str += "" + newLine; + } + } + if (loggingEvent.exception) { + str += "" + newLine; + } + str += "" + newLine + newLine; + return str; + }; + + XmlLayout.prototype.ignoresThrowable = function() { + return false; + }; + + XmlLayout.prototype.toString = function() { + return "XmlLayout"; + }; + + log4javascript.XmlLayout = XmlLayout; + /* ---------------------------------------------------------------------- */ + // JsonLayout related + + function escapeNewLines(str) { + return str.replace(/\r\n|\r|\n/g, "\\r\\n"); + } + + function JsonLayout(readable, combineMessages) { + this.readable = extractBooleanFromParam(readable, false); + this.combineMessages = extractBooleanFromParam(combineMessages, true); + this.batchHeader = this.readable ? "[" + newLine : "["; + this.batchFooter = this.readable ? "]" + newLine : "]"; + this.batchSeparator = this.readable ? "," + newLine : ","; + this.setKeys(); + this.colon = this.readable ? ": " : ":"; + this.tab = this.readable ? "\t" : ""; + this.lineBreak = this.readable ? newLine : ""; + this.customFields = []; + } + + /* ---------------------------------------------------------------------- */ + // JsonLayout + + JsonLayout.prototype = new Layout(); + + JsonLayout.prototype.isReadable = function() { + return this.readable; + }; + + JsonLayout.prototype.isCombinedMessages = function() { + return this.combineMessages; + }; + + JsonLayout.prototype.format = function(loggingEvent) { + var layout = this; + var dataValues = this.getDataValues(loggingEvent, this.combineMessages); + var str = "{" + this.lineBreak; + var i, len; + + function formatValue(val, prefix, expand) { + // Check the type of the data value to decide whether quotation marks + // or expansion are required + var formattedValue; + var valType = typeof val; + if (val instanceof Date) { + formattedValue = String(val.getTime()); + } else if (expand && (val instanceof Array)) { + formattedValue = "[" + layout.lineBreak; + for (var i = 0, len = val.length; i < len; i++) { + var childPrefix = prefix + layout.tab; + formattedValue += childPrefix + formatValue(val[i], childPrefix, false); + if (i < val.length - 1) { + formattedValue += ","; + } + formattedValue += layout.lineBreak; + } + formattedValue += prefix + "]"; + } else if (valType !== "number" && valType !== "boolean") { + formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\""; + } else { + formattedValue = val; + } + return formattedValue; + } + + for (i = 0, len = dataValues.length - 1; i <= len; i++) { + str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true); + if (i < len) { + str += ","; + } + str += this.lineBreak; + } + + str += "}" + this.lineBreak; + return str; + }; + + JsonLayout.prototype.ignoresThrowable = function() { + return false; + }; + + JsonLayout.prototype.toString = function() { + return "JsonLayout"; + }; + + JsonLayout.prototype.getContentType = function() { + return "application/json"; + }; + + log4javascript.JsonLayout = JsonLayout; + /* ---------------------------------------------------------------------- */ + // HttpPostDataLayout + + function HttpPostDataLayout() { + this.setKeys(); + this.customFields = []; + this.returnsPostData = true; + } + + HttpPostDataLayout.prototype = new Layout(); + + // Disable batching + HttpPostDataLayout.prototype.allowBatching = function() { + return false; + }; + + HttpPostDataLayout.prototype.format = function(loggingEvent) { + var dataValues = this.getDataValues(loggingEvent); + var queryBits = []; + for (var i = 0, len = dataValues.length; i < len; i++) { + var val = (dataValues[i][1] instanceof Date) ? + String(dataValues[i][1].getTime()) : dataValues[i][1]; + queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val)); + } + return queryBits.join("&"); + }; + + HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) { + return false; + }; + + HttpPostDataLayout.prototype.toString = function() { + return "HttpPostDataLayout"; + }; + + log4javascript.HttpPostDataLayout = HttpPostDataLayout; + /* ---------------------------------------------------------------------- */ + // formatObjectExpansion + + function formatObjectExpansion(obj, depth, indentation) { + var objectsExpanded = []; + + function doFormat(obj, depth, indentation) { + var i, j, len, childDepth, childIndentation, childLines, expansion, + childExpansion; + + if (!indentation) { + indentation = ""; + } + + function formatString(text) { + var lines = splitIntoLines(text); + for (var j = 1, jLen = lines.length; j < jLen; j++) { + lines[j] = indentation + lines[j]; + } + return lines.join(newLine); + } + + if (obj === null) { + return "null"; + } else if (typeof obj == "undefined") { + return "undefined"; + } else if (typeof obj == "string") { + return formatString(obj); + } else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) { + try { + expansion = toStr(obj); + } catch (ex) { + expansion = "Error formatting property. Details: " + getExceptionStringRep(ex); + } + return expansion + " [already expanded]"; + } else if ((obj instanceof Array) && depth > 0) { + objectsExpanded.push(obj); + expansion = "[" + newLine; + childDepth = depth - 1; + childIndentation = indentation + " "; + childLines = []; + for (i = 0, len = obj.length; i < len; i++) { + try { + childExpansion = doFormat(obj[i], childDepth, childIndentation); + childLines.push(childIndentation + childExpansion); + } catch (ex) { + childLines.push(childIndentation + "Error formatting array member. Details: " + + getExceptionStringRep(ex) + ""); + } + } + expansion += childLines.join("," + newLine) + newLine + indentation + "]"; + return expansion; + } else if (Object.prototype.toString.call(obj) == "[object Date]") { + return obj.toString(); + } else if (typeof obj == "object" && depth > 0) { + objectsExpanded.push(obj); + expansion = "{" + newLine; + childDepth = depth - 1; + childIndentation = indentation + " "; + childLines = []; + for (i in obj) { + try { + childExpansion = doFormat(obj[i], childDepth, childIndentation); + childLines.push(childIndentation + i + ": " + childExpansion); + } catch (ex) { + childLines.push(childIndentation + i + ": Error formatting property. Details: " + + getExceptionStringRep(ex)); + } + } + expansion += childLines.join("," + newLine) + newLine + indentation + "}"; + return expansion; + } else { + return formatString(toStr(obj)); + } + } + return doFormat(obj, depth, indentation); + } + /* ---------------------------------------------------------------------- */ + // Date-related stuff + + var SimpleDateFormat; + + (function() { + var 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']+)/; + var monthNames = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"]; + var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5; + var types = { + G : TEXT2, + y : YEAR, + M : MONTH, + w : NUMBER, + W : NUMBER, + D : NUMBER, + d : NUMBER, + F : NUMBER, + E : TEXT3, + a : TEXT2, + H : NUMBER, + k : NUMBER, + K : NUMBER, + h : NUMBER, + m : NUMBER, + s : NUMBER, + S : NUMBER, + Z : TIMEZONE + }; + var ONE_DAY = 24 * 60 * 60 * 1000; + var ONE_WEEK = 7 * ONE_DAY; + var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1; + + var newDateAtMidnight = function(year, month, day) { + var d = new Date(year, month, day, 0, 0, 0); + d.setMilliseconds(0); + return d; + }; + + Date.prototype.getDifference = function(date) { + return this.getTime() - date.getTime(); + }; + + Date.prototype.isBefore = function(d) { + return this.getTime() < d.getTime(); + }; + + Date.prototype.getUTCTime = function() { + return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(), + this.getSeconds(), this.getMilliseconds()); + }; + + Date.prototype.getTimeSince = function(d) { + return this.getUTCTime() - d.getUTCTime(); + }; + + Date.prototype.getPreviousSunday = function() { + // Using midday avoids any possibility of DST messing things up + var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0); + var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY); + return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(), + previousSunday.getDate()); + }; + + Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) { + if (isUndefined(this.minimalDaysInFirstWeek)) { + minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK; + } + var previousSunday = this.getPreviousSunday(); + var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1); + var numberOfSundays = previousSunday.isBefore(startOfYear) ? + 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK); + var numberOfDaysInFirstWeek = 7 - startOfYear.getDay(); + var weekInYear = numberOfSundays; + if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) { + weekInYear--; + } + return weekInYear; + }; + + Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) { + if (isUndefined(this.minimalDaysInFirstWeek)) { + minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK; + } + var previousSunday = this.getPreviousSunday(); + var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1); + var numberOfSundays = previousSunday.isBefore(startOfMonth) ? + 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK); + var numberOfDaysInFirstWeek = 7 - startOfMonth.getDay(); + var weekInMonth = numberOfSundays; + if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) { + weekInMonth++; + } + return weekInMonth; + }; + + Date.prototype.getDayInYear = function() { + var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1); + return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY); + }; + + /* ------------------------------------------------------------------ */ + + SimpleDateFormat = function(formatString) { + this.formatString = formatString; + }; + + /** + * Sets the minimum number of days in a week in order for that week to + * be considered as belonging to a particular month or year + */ + SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) { + this.minimalDaysInFirstWeek = days; + }; + + SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() { + return isUndefined(this.minimalDaysInFirstWeek) ? + DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek; + }; + + var padWithZeroes = function(str, len) { + while (str.length < len) { + str = "0" + str; + } + return str; + }; + + var formatText = function(data, numberOfLetters, minLength) { + return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters)); + }; + + var formatNumber = function(data, numberOfLetters) { + var dataString = "" + data; + // Pad with 0s as necessary + return padWithZeroes(dataString, numberOfLetters); + }; + + SimpleDateFormat.prototype.format = function(date) { + var formattedString = ""; + var result; + var searchString = this.formatString; + while ((result = regex.exec(searchString))) { + var quotedString = result[1]; + var patternLetters = result[2]; + var otherLetters = result[3]; + var otherCharacters = result[4]; + + // If the pattern matched is quoted string, output the text between the quotes + if (quotedString) { + if (quotedString == "''") { + formattedString += "'"; + } else { + formattedString += quotedString.substring(1, quotedString.length - 1); + } + } else if (otherLetters) { + // Swallow non-pattern letters by doing nothing here + } else if (otherCharacters) { + // Simply output other characters + formattedString += otherCharacters; + } else if (patternLetters) { + // Replace pattern letters + var patternLetter = patternLetters.charAt(0); + var numberOfLetters = patternLetters.length; + var rawData = ""; + switch(patternLetter) { + case "G": + rawData = "AD"; + break; + case "y": + rawData = date.getFullYear(); + break; + case "M": + rawData = date.getMonth(); + break; + case "w": + rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek()); + break; + case "W": + rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek()); + break; + case "D": + rawData = date.getDayInYear(); + break; + case "d": + rawData = date.getDate(); + break; + case "F": + rawData = 1 + Math.floor((date.getDate() - 1) / 7); + break; + case "E": + rawData = dayNames[date.getDay()]; + break; + case "a": + rawData = (date.getHours() >= 12) ? "PM" : "AM"; + break; + case "H": + rawData = date.getHours(); + break; + case "k": + rawData = date.getHours() || 24; + break; + case "K": + rawData = date.getHours() % 12; + break; + case "h": + rawData = (date.getHours() % 12) || 12; + break; + case "m": + rawData = date.getMinutes(); + break; + case "s": + rawData = date.getSeconds(); + break; + case "S": + rawData = date.getMilliseconds(); + break; + case "Z": + rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time. + break; + } + // Format the raw data depending on the type + switch(types[patternLetter]) { + case TEXT2: + formattedString += formatText(rawData, numberOfLetters, 2); + break; + case TEXT3: + formattedString += formatText(rawData, numberOfLetters, 3); + break; + case NUMBER: + formattedString += formatNumber(rawData, numberOfLetters); + break; + case YEAR: + if (numberOfLetters <= 3) { + // Output a 2-digit year + var dataString = "" + rawData; + formattedString += dataString.substr(2, 2); + } else { + formattedString += formatNumber(rawData, numberOfLetters); + } + break; + case MONTH: + if (numberOfLetters >= 3) { + formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters); + } else { + // NB. Months returned by getMonth are zero-based + formattedString += formatNumber(rawData + 1, numberOfLetters); + } + break; + case TIMEZONE: + var isPositive = (rawData > 0); + // The following line looks like a mistake but isn't + // because of the way getTimezoneOffset measures. + var prefix = isPositive ? "-" : "+"; + var absData = Math.abs(rawData); + + // Hours + var hours = "" + Math.floor(absData / 60); + hours = padWithZeroes(hours, 2); + // Minutes + var minutes = "" + (absData % 60); + minutes = padWithZeroes(minutes, 2); + + formattedString += prefix + hours + minutes; + break; + } + } + searchString = searchString.substr(result.index + result[0].length); + } + return formattedString; + }; + })(); + + log4javascript.SimpleDateFormat = SimpleDateFormat; + + /* ---------------------------------------------------------------------- */ + // PatternLayout + + function PatternLayout(pattern) { + if (pattern) { + this.pattern = pattern; + } else { + this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN; + } + this.customFields = []; + } + + PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n"; + PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n"; + PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS"; + PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS"; + PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS"; + + PatternLayout.prototype = new Layout(); + + PatternLayout.prototype.format = function(loggingEvent) { + var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/; + var formattedString = ""; + var result; + var searchString = this.pattern; + + // Cannot use regex global flag since it doesn't work with exec in IE5 + while ((result = regex.exec(searchString))) { + var matchedString = result[0]; + var padding = result[1]; + var truncation = result[2]; + var conversionCharacter = result[3]; + var specifier = result[5]; + var text = result[6]; + + // Check if the pattern matched was just normal text + if (text) { + formattedString += "" + text; + } else { + // Create a raw replacement string based on the conversion + // character and specifier + var replacement = ""; + switch(conversionCharacter) { + case "a": // Array of messages + case "m": // Message + var depth = 0; + if (specifier) { + depth = parseInt(specifier, 10); + if (isNaN(depth)) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character '" + conversionCharacter + + "' - should be a number"); + depth = 0; + } + } + var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages; + for (var i = 0, len = messages.length; i < len; i++) { + if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) { + replacement += " "; + } + if (depth === 0) { + replacement += messages[i]; + } else { + replacement += formatObjectExpansion(messages[i], depth); + } + } + break; + case "c": // Logger name + var loggerName = loggingEvent.logger.name; + if (specifier) { + var precision = parseInt(specifier, 10); + var loggerNameBits = loggingEvent.logger.name.split("."); + if (precision >= loggerNameBits.length) { + replacement = loggerName; + } else { + replacement = loggerNameBits.slice(loggerNameBits.length - precision).join("."); + } + } else { + replacement = loggerName; + } + break; + case "d": // Date + var dateFormat = PatternLayout.ISO8601_DATEFORMAT; + if (specifier) { + dateFormat = specifier; + // Pick up special cases + if (dateFormat == "ISO8601") { + dateFormat = PatternLayout.ISO8601_DATEFORMAT; + } else if (dateFormat == "ABSOLUTE") { + dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT; + } else if (dateFormat == "DATE") { + dateFormat = PatternLayout.DATETIME_DATEFORMAT; + } + } + // Format the date + replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp); + break; + case "f": // Custom field + if (this.hasCustomFields()) { + var fieldIndex = 0; + if (specifier) { + fieldIndex = parseInt(specifier, 10); + if (isNaN(fieldIndex)) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character 'f' - should be a number"); + } else if (fieldIndex === 0) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character 'f' - must be greater than zero"); + } else if (fieldIndex > this.customFields.length) { + handleError("PatternLayout.format: invalid specifier '" + + specifier + "' for conversion character 'f' - there aren't that many custom fields"); + } else { + fieldIndex = fieldIndex - 1; + } + } + var val = this.customFields[fieldIndex].value; + if (typeof val == "function") { + val = val(this, loggingEvent); + } + replacement = val; + } + break; + case "n": // New line + replacement = newLine; + break; + case "p": // Level + replacement = loggingEvent.level.name; + break; + case "r": // Milliseconds since log4javascript startup + replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate); + break; + case "%": // Literal % sign + replacement = "%"; + break; + default: + replacement = matchedString; + break; + } + // Format the replacement according to any padding or + // truncation specified + var l; + + // First, truncation + if (truncation) { + l = parseInt(truncation.substr(1), 10); + var strLen = replacement.length; + if (l < strLen) { + replacement = replacement.substring(strLen - l, strLen); + } + } + // Next, padding + if (padding) { + if (padding.charAt(0) == "-") { + l = parseInt(padding.substr(1), 10); + // Right pad with spaces + while (replacement.length < l) { + replacement += " "; + } + } else { + l = parseInt(padding, 10); + // Left pad with spaces + while (replacement.length < l) { + replacement = " " + replacement; + } + } + } + formattedString += replacement; + } + searchString = searchString.substr(result.index + result[0].length); + } + return formattedString; + }; + + PatternLayout.prototype.ignoresThrowable = function() { + return true; + }; + + PatternLayout.prototype.toString = function() { + return "PatternLayout"; + }; + + log4javascript.PatternLayout = PatternLayout; + /* ---------------------------------------------------------------------- */ + // AlertAppender + + function AlertAppender() {} + + AlertAppender.prototype = new Appender(); + + AlertAppender.prototype.layout = new SimpleLayout(); + + AlertAppender.prototype.append = function(loggingEvent) { + var formattedMessage = this.getLayout().format(loggingEvent); + if (this.getLayout().ignoresThrowable()) { + formattedMessage += loggingEvent.getThrowableStrRep(); + } + alert(formattedMessage); + }; + + AlertAppender.prototype.toString = function() { + return "AlertAppender"; + }; + + log4javascript.AlertAppender = AlertAppender; + /* ---------------------------------------------------------------------- */ + // BrowserConsoleAppender (only works in Opera and Safari and Firefox with + // Firebug extension) + + function BrowserConsoleAppender() {} + + BrowserConsoleAppender.prototype = new log4javascript.Appender(); + BrowserConsoleAppender.prototype.layout = new NullLayout(); + BrowserConsoleAppender.prototype.threshold = Level.DEBUG; + + BrowserConsoleAppender.prototype.append = function(loggingEvent) { + var appender = this; + + var getFormattedMessage = function() { + var layout = appender.getLayout(); + var formattedMessage = layout.format(loggingEvent); + if (layout.ignoresThrowable() && loggingEvent.exception) { + formattedMessage += loggingEvent.getThrowableStrRep(); + } + return formattedMessage; + }; + + if ((typeof opera != "undefined") && opera.postError) { // Opera + opera.postError(getFormattedMessage()); + } else if (window.console && window.console.log) { // Safari and Firebug + var formattedMesage = getFormattedMessage(); + // Log to Firebug using its logging methods or revert to the console.log + // method in Safari + if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) { + window.console.debug(formattedMesage); + } else if (window.console.info && Level.INFO.equals(loggingEvent.level)) { + window.console.info(formattedMesage); + } else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) { + window.console.warn(formattedMesage); + } else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) { + window.console.error(formattedMesage); + } else { + window.console.log(formattedMesage); + } + } + }; + + BrowserConsoleAppender.prototype.group = function(name) { + if (window.console && window.console.group) { + window.console.group(name); + } + }; + + BrowserConsoleAppender.prototype.groupEnd = function() { + if (window.console && window.console.groupEnd) { + window.console.groupEnd(); + } + }; + + BrowserConsoleAppender.prototype.toString = function() { + return "BrowserConsoleAppender"; + }; + + log4javascript.BrowserConsoleAppender = BrowserConsoleAppender; + /* ---------------------------------------------------------------------- */ + // AjaxAppender related + + var xmlHttpFactories = [ + function() { return new XMLHttpRequest(); }, + function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, + function() { return new ActiveXObject("Microsoft.XMLHTTP"); } + ]; + + var getXmlHttp = function(errorHandler) { + // This is only run the first time; the value of getXmlHttp gets + // replaced with the factory that succeeds on the first run + var xmlHttp = null, factory; + for (var i = 0, len = xmlHttpFactories.length; i < len; i++) { + factory = xmlHttpFactories[i]; + try { + xmlHttp = factory(); + getXmlHttp = factory; + return xmlHttp; + } catch (e) { + } + } + // If we're here, all factories have failed, so throw an error + if (errorHandler) { + errorHandler(); + } else { + handleError("getXmlHttp: unable to obtain XMLHttpRequest object"); + } + }; + + function isHttpRequestSuccessful(xmlHttp) { + return isUndefined(xmlHttp.status) || xmlHttp.status === 0 || + (xmlHttp.status >= 200 && xmlHttp.status < 300) || + xmlHttp.status == 1223 /* Fix for IE */; + } + + /* ---------------------------------------------------------------------- */ + // AjaxAppender + + function AjaxAppender(url) { + var appender = this; + var isSupported = true; + if (!url) { + handleError("AjaxAppender: URL must be specified in constructor"); + isSupported = false; + } + + var timed = this.defaults.timed; + var waitForResponse = this.defaults.waitForResponse; + var batchSize = this.defaults.batchSize; + var timerInterval = this.defaults.timerInterval; + var requestSuccessCallback = this.defaults.requestSuccessCallback; + var failCallback = this.defaults.failCallback; + var postVarName = this.defaults.postVarName; + var sendAllOnUnload = this.defaults.sendAllOnUnload; + var contentType = this.defaults.contentType; + var sessionId = null; + + var queuedLoggingEvents = []; + var queuedRequests = []; + var headers = []; + var sending = false; + var initialized = false; + + // Configuration methods. The function scope is used to prevent + // direct alteration to the appender configuration properties. + function checkCanConfigure(configOptionName) { + if (initialized) { + handleError("AjaxAppender: configuration option '" + + configOptionName + + "' may not be set after the appender has been initialized"); + return false; + } + return true; + } + + this.getSessionId = function() { return sessionId; }; + this.setSessionId = function(sessionIdParam) { + sessionId = extractStringFromParam(sessionIdParam, null); + this.layout.setCustomField("sessionid", sessionId); + }; + + this.setLayout = function(layoutParam) { + if (checkCanConfigure("layout")) { + this.layout = layoutParam; + // Set the session id as a custom field on the layout, if not already present + if (sessionId !== null) { + this.setSessionId(sessionId); + } + } + }; + + this.isTimed = function() { return timed; }; + this.setTimed = function(timedParam) { + if (checkCanConfigure("timed")) { + timed = bool(timedParam); + } + }; + + this.getTimerInterval = function() { return timerInterval; }; + this.setTimerInterval = function(timerIntervalParam) { + if (checkCanConfigure("timerInterval")) { + timerInterval = extractIntFromParam(timerIntervalParam, timerInterval); + } + }; + + this.isWaitForResponse = function() { return waitForResponse; }; + this.setWaitForResponse = function(waitForResponseParam) { + if (checkCanConfigure("waitForResponse")) { + waitForResponse = bool(waitForResponseParam); + } + }; + + this.getBatchSize = function() { return batchSize; }; + this.setBatchSize = function(batchSizeParam) { + if (checkCanConfigure("batchSize")) { + batchSize = extractIntFromParam(batchSizeParam, batchSize); + } + }; + + this.isSendAllOnUnload = function() { return sendAllOnUnload; }; + this.setSendAllOnUnload = function(sendAllOnUnloadParam) { + if (checkCanConfigure("sendAllOnUnload")) { + sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload); + } + }; + + this.setRequestSuccessCallback = function(requestSuccessCallbackParam) { + requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback); + }; + + this.setFailCallback = function(failCallbackParam) { + failCallback = extractFunctionFromParam(failCallbackParam, failCallback); + }; + + this.getPostVarName = function() { return postVarName; }; + this.setPostVarName = function(postVarNameParam) { + if (checkCanConfigure("postVarName")) { + postVarName = extractStringFromParam(postVarNameParam, postVarName); + } + }; + + this.getHeaders = function() { return headers; }; + this.addHeader = function(name, value) { + if (name.toLowerCase() == "content-type") { + contentType = value; + } else { + headers.push( { name: name, value: value } ); + } + }; + + // Internal functions + function sendAll() { + if (isSupported && enabled) { + sending = true; + var currentRequestBatch; + if (waitForResponse) { + // Send the first request then use this function as the callback once + // the response comes back + if (queuedRequests.length > 0) { + currentRequestBatch = queuedRequests.shift(); + sendRequest(preparePostData(currentRequestBatch), sendAll); + } else { + sending = false; + if (timed) { + scheduleSending(); + } + } + } else { + // Rattle off all the requests without waiting to see the response + while ((currentRequestBatch = queuedRequests.shift())) { + sendRequest(preparePostData(currentRequestBatch)); + } + sending = false; + if (timed) { + scheduleSending(); + } + } + } + } + + this.sendAll = sendAll; + + // Called when the window unloads. At this point we're past caring about + // waiting for responses or timers or incomplete batches - everything + // must go, now + function sendAllRemaining() { + var sendingAnything = false; + if (isSupported && enabled) { + // Create requests for everything left over, batched as normal + var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1; + var currentLoggingEvent; + var batchedLoggingEvents = []; + while ((currentLoggingEvent = queuedLoggingEvents.shift())) { + batchedLoggingEvents.push(currentLoggingEvent); + if (queuedLoggingEvents.length >= actualBatchSize) { + // Queue this batch of log entries + queuedRequests.push(batchedLoggingEvents); + batchedLoggingEvents = []; + } + } + // If there's a partially completed batch, add it + if (batchedLoggingEvents.length > 0) { + queuedRequests.push(batchedLoggingEvents); + } + sendingAnything = (queuedRequests.length > 0); + waitForResponse = false; + timed = false; + sendAll(); + } + return sendingAnything; + } + + this.sendAllRemaining = sendAllRemaining; + + function preparePostData(batchedLoggingEvents) { + // Format the logging events + var formattedMessages = []; + var currentLoggingEvent; + var postData = ""; + while ((currentLoggingEvent = batchedLoggingEvents.shift())) { + var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent); + if (appender.getLayout().ignoresThrowable()) { + currentFormattedMessage += currentLoggingEvent.getThrowableStrRep(); + } + formattedMessages.push(currentFormattedMessage); + } + // Create the post data string + if (batchedLoggingEvents.length == 1) { + postData = formattedMessages.join(""); + } else { + postData = appender.getLayout().batchHeader + + formattedMessages.join(appender.getLayout().batchSeparator) + + appender.getLayout().batchFooter; + } + if (contentType == appender.defaults.contentType) { + postData = appender.getLayout().returnsPostData ? postData : + urlEncode(postVarName) + "=" + urlEncode(postData); + // Add the layout name to the post data + if (postData.length > 0) { + postData += "&"; + } + postData += "layout=" + urlEncode(appender.getLayout().toString()); + } + return postData; + } + + function scheduleSending() { + window.setTimeout(sendAll, timerInterval); + } + + function xmlHttpErrorHandler() { + var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled"; + handleError(msg); + isSupported = false; + if (failCallback) { + failCallback(msg); + } + } + + function sendRequest(postData, successCallback) { + try { + var xmlHttp = getXmlHttp(xmlHttpErrorHandler); + if (isSupported) { + if (xmlHttp.overrideMimeType) { + xmlHttp.overrideMimeType(appender.getLayout().getContentType()); + } + xmlHttp.onreadystatechange = function() { + if (xmlHttp.readyState == 4) { + if (isHttpRequestSuccessful(xmlHttp)) { + if (requestSuccessCallback) { + requestSuccessCallback(xmlHttp); + } + if (successCallback) { + successCallback(xmlHttp); + } + } else { + var msg = "AjaxAppender.append: XMLHttpRequest request to URL " + + url + " returned status code " + xmlHttp.status; + handleError(msg); + if (failCallback) { + failCallback(msg); + } + } + xmlHttp.onreadystatechange = emptyFunction; + xmlHttp = null; + } + }; + xmlHttp.open("POST", url, true); + try { + for (var i = 0, header; header = headers[i++]; ) { + xmlHttp.setRequestHeader(header.name, header.value); + } + xmlHttp.setRequestHeader("Content-Type", contentType); + } catch (headerEx) { + var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" + + " does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled"; + handleError(msg); + isSupported = false; + if (failCallback) { + failCallback(msg); + } + return; + } + xmlHttp.send(postData); + } + } catch (ex) { + var errMsg = "AjaxAppender.append: error sending log message to " + url; + handleError(errMsg, ex); + isSupported = false; + if (failCallback) { + failCallback(errMsg + ". Details: " + getExceptionStringRep(ex)); + } + } + } + + this.append = function(loggingEvent) { + if (isSupported) { + if (!initialized) { + init(); + } + queuedLoggingEvents.push(loggingEvent); + var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1; + + if (queuedLoggingEvents.length >= actualBatchSize) { + var currentLoggingEvent; + var batchedLoggingEvents = []; + while ((currentLoggingEvent = queuedLoggingEvents.shift())) { + batchedLoggingEvents.push(currentLoggingEvent); + } + // Queue this batch of log entries + queuedRequests.push(batchedLoggingEvents); + + // If using a timer, the queue of requests will be processed by the + // timer function, so nothing needs to be done here. + if (!timed && (!waitForResponse || (waitForResponse && !sending))) { + sendAll(); + } + } + } + }; + + function init() { + initialized = true; + // Add unload event to send outstanding messages + if (sendAllOnUnload) { + var oldBeforeUnload = window.onbeforeunload; + window.onbeforeunload = function() { + if (oldBeforeUnload) { + oldBeforeUnload(); + } + if (sendAllRemaining()) { + return "Sending log messages"; + } + }; + } + // Start timer + if (timed) { + scheduleSending(); + } + } + } + + AjaxAppender.prototype = new Appender(); + + AjaxAppender.prototype.defaults = { + waitForResponse: false, + timed: false, + timerInterval: 1000, + batchSize: 1, + sendAllOnUnload: false, + requestSuccessCallback: null, + failCallback: null, + postVarName: "data", + contentType: "application/x-www-form-urlencoded" + }; + + AjaxAppender.prototype.layout = new HttpPostDataLayout(); + + AjaxAppender.prototype.toString = function() { + return "AjaxAppender"; + }; + + log4javascript.AjaxAppender = AjaxAppender; + /* ---------------------------------------------------------------------- */ + // PopUpAppender and InPageAppender related + + function setCookie(name, value, days, path) { + var expires; + path = path ? "; path=" + path : ""; + if (days) { + var date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + expires = "; expires=" + date.toGMTString(); + } else { + expires = ""; + } + document.cookie = escape(name) + "=" + escape(value) + expires + path; + } + + function getCookie(name) { + var nameEquals = escape(name) + "="; + var ca = document.cookie.split(";"); + for (var i = 0, len = ca.length; i < len; i++) { + var c = ca[i]; + while (c.charAt(0) === " ") { + c = c.substring(1, c.length); + } + if (c.indexOf(nameEquals) === 0) { + return unescape(c.substring(nameEquals.length, c.length)); + } + } + return null; + } + + // Gets the base URL of the location of the log4javascript script. + // This is far from infallible. + function getBaseUrl() { + var scripts = document.getElementsByTagName("script"); + for (var i = 0, len = scripts.length; i < len; ++i) { + if (scripts[i].src.indexOf("log4javascript") != -1) { + var lastSlash = scripts[i].src.lastIndexOf("/"); + return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1); + } + } + return null; + } + + function isLoaded(win) { + try { + return bool(win.loaded); + } catch (ex) { + return false; + } + } + + /* ---------------------------------------------------------------------- */ + // ConsoleAppender (prototype for PopUpAppender and InPageAppender) + + var ConsoleAppender; + + // Create an anonymous function to protect base console methods + (function() { + var getConsoleHtmlLines = function() { + return [ +'', +'', +' ', +' log4javascript', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +'', +' ', +'
', +'
', +'
', +' Filters:', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +'
', +' ', +'
', +' Options:', +' ', +' ', +' ', +' ', +' ', +' ', +' ', +'
', +'
', +'
', +'
', +'
', +'
', +' ', +' ', +'
', +'
', +' ', +'', +'' +]; + }; + + var defaultCommandLineFunctions = []; + + ConsoleAppender = function() {}; + + var consoleAppenderIdCounter = 1; + ConsoleAppender.prototype = new Appender(); + + ConsoleAppender.prototype.create = function(inPage, container, + lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) { + var appender = this; + + // Common properties + var initialized = false; + var consoleWindowCreated = false; + var consoleWindowLoaded = false; + var consoleClosed = false; + + var queuedLoggingEvents = []; + var isSupported = true; + var consoleAppenderId = consoleAppenderIdCounter++; + + // Local variables + initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized); + lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit); + useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite); + var newestMessageAtTop = this.defaults.newestMessageAtTop; + var scrollToLatestMessage = this.defaults.scrollToLatestMessage; + width = width ? width : this.defaults.width; + height = height ? height : this.defaults.height; + var maxMessages = this.defaults.maxMessages; + var showCommandLine = this.defaults.showCommandLine; + var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth; + var showHideButton = this.defaults.showHideButton; + var showCloseButton = this.defaults.showCloseButton; + var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons; + + this.setLayout(this.defaults.layout); + + // Functions whose implementations vary between subclasses + var init, createWindow, safeToAppend, getConsoleWindow, open; + + // Configuration methods. The function scope is used to prevent + // direct alteration to the appender configuration properties. + var appenderName = inPage ? "InPageAppender" : "PopUpAppender"; + var checkCanConfigure = function(configOptionName) { + if (consoleWindowCreated) { + handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized"); + return false; + } + return true; + }; + + var consoleWindowExists = function() { + return (consoleWindowLoaded && isSupported && !consoleClosed); + }; + + this.isNewestMessageAtTop = function() { return newestMessageAtTop; }; + this.setNewestMessageAtTop = function(newestMessageAtTopParam) { + newestMessageAtTop = bool(newestMessageAtTopParam); + if (consoleWindowExists()) { + getConsoleWindow().setNewestAtTop(newestMessageAtTop); + } + }; + + this.isScrollToLatestMessage = function() { return scrollToLatestMessage; }; + this.setScrollToLatestMessage = function(scrollToLatestMessageParam) { + scrollToLatestMessage = bool(scrollToLatestMessageParam); + if (consoleWindowExists()) { + getConsoleWindow().setScrollToLatest(scrollToLatestMessage); + } + }; + + this.getWidth = function() { return width; }; + this.setWidth = function(widthParam) { + if (checkCanConfigure("width")) { + width = extractStringFromParam(widthParam, width); + } + }; + + this.getHeight = function() { return height; }; + this.setHeight = function(heightParam) { + if (checkCanConfigure("height")) { + height = extractStringFromParam(heightParam, height); + } + }; + + this.getMaxMessages = function() { return maxMessages; }; + this.setMaxMessages = function(maxMessagesParam) { + maxMessages = extractIntFromParam(maxMessagesParam, maxMessages); + if (consoleWindowExists()) { + getConsoleWindow().setMaxMessages(maxMessages); + } + }; + + this.isShowCommandLine = function() { return showCommandLine; }; + this.setShowCommandLine = function(showCommandLineParam) { + showCommandLine = bool(showCommandLineParam); + if (consoleWindowExists()) { + getConsoleWindow().setShowCommandLine(showCommandLine); + } + }; + + this.isShowHideButton = function() { return showHideButton; }; + this.setShowHideButton = function(showHideButtonParam) { + showHideButton = bool(showHideButtonParam); + if (consoleWindowExists()) { + getConsoleWindow().setShowHideButton(showHideButton); + } + }; + + this.isShowCloseButton = function() { return showCloseButton; }; + this.setShowCloseButton = function(showCloseButtonParam) { + showCloseButton = bool(showCloseButtonParam); + if (consoleWindowExists()) { + getConsoleWindow().setShowCloseButton(showCloseButton); + } + }; + + this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; }; + this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) { + commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth); + }; + + var minimized = initiallyMinimized; + this.isInitiallyMinimized = function() { return initiallyMinimized; }; + this.setInitiallyMinimized = function(initiallyMinimizedParam) { + if (checkCanConfigure("initiallyMinimized")) { + initiallyMinimized = bool(initiallyMinimizedParam); + minimized = initiallyMinimized; + } + }; + + this.isUseDocumentWrite = function() { return useDocumentWrite; }; + this.setUseDocumentWrite = function(useDocumentWriteParam) { + if (checkCanConfigure("useDocumentWrite")) { + useDocumentWrite = bool(useDocumentWriteParam); + } + }; + + // Common methods + function QueuedLoggingEvent(loggingEvent, formattedMessage) { + this.loggingEvent = loggingEvent; + this.levelName = loggingEvent.level.name; + this.formattedMessage = formattedMessage; + } + + QueuedLoggingEvent.prototype.append = function() { + getConsoleWindow().log(this.levelName, this.formattedMessage); + }; + + function QueuedGroup(name, initiallyExpanded) { + this.name = name; + this.initiallyExpanded = initiallyExpanded; + } + + QueuedGroup.prototype.append = function() { + getConsoleWindow().group(this.name, this.initiallyExpanded); + }; + + function QueuedGroupEnd() {} + + QueuedGroupEnd.prototype.append = function() { + getConsoleWindow().groupEnd(); + }; + + var checkAndAppend = function() { + // Next line forces a check of whether the window has been closed + safeToAppend(); + if (!initialized) { + init(); + } else if (consoleClosed && reopenWhenClosed) { + createWindow(); + } + if (safeToAppend()) { + appendQueuedLoggingEvents(); + } + }; + + this.append = function(loggingEvent) { + if (isSupported) { + // Format the message + var formattedMessage = appender.getLayout().format(loggingEvent); + if (this.getLayout().ignoresThrowable()) { + formattedMessage += loggingEvent.getThrowableStrRep(); + } + queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage)); + checkAndAppend(); + } + }; + + this.group = function(name, initiallyExpanded) { + if (isSupported) { + queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded)); + checkAndAppend(); + } + }; + + this.groupEnd = function() { + if (isSupported) { + queuedLoggingEvents.push(new QueuedGroupEnd()); + checkAndAppend(); + } + }; + + var appendQueuedLoggingEvents = function() { + var currentLoggingEvent; + while (queuedLoggingEvents.length > 0) { + queuedLoggingEvents.shift().append(); + } + if (focusConsoleWindow) { + getConsoleWindow().focus(); + } + }; + + this.setAddedToLogger = function(logger) { + this.loggers.push(logger); + if (enabled && !lazyInit) { + init(); + } + }; + + this.clear = function() { + if (consoleWindowExists()) { + getConsoleWindow().clearLog(); + } + queuedLoggingEvents.length = 0; + }; + + this.focus = function() { + if (consoleWindowExists()) { + getConsoleWindow().focus(); + } + }; + + this.focusCommandLine = function() { + if (consoleWindowExists()) { + getConsoleWindow().focusCommandLine(); + } + }; + + this.focusSearch = function() { + if (consoleWindowExists()) { + getConsoleWindow().focusSearch(); + } + }; + + var commandWindow = window; + + this.getCommandWindow = function() { return commandWindow; }; + this.setCommandWindow = function(commandWindowParam) { + commandWindow = commandWindowParam; + }; + + this.executeLastCommand = function() { + if (consoleWindowExists()) { + getConsoleWindow().evalLastCommand(); + } + }; + + var commandLayout = new PatternLayout("%m"); + this.getCommandLayout = function() { return commandLayout; }; + this.setCommandLayout = function(commandLayoutParam) { + commandLayout = commandLayoutParam; + }; + + this.evalCommandAndAppend = function(expr) { + var commandReturnValue = { appendResult: true, isError: false }; + var commandOutput = ""; + // Evaluate the command + try { + var result, i; + // The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no + // eval method on the window object initially, but once execScript has been called on + // it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25 + if (!commandWindow.eval && commandWindow.execScript) { + commandWindow.execScript("null"); + } + + var commandLineFunctionsHash = {}; + for (i = 0, len = commandLineFunctions.length; i < len; i++) { + commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1]; + } + + // Keep an array of variables that are being changed in the command window so that they + // can be restored to their original values afterwards + var objectsToRestore = []; + var addObjectToRestore = function(name) { + objectsToRestore.push([name, commandWindow[name]]); + }; + + addObjectToRestore("appender"); + commandWindow.appender = appender; + + addObjectToRestore("commandReturnValue"); + commandWindow.commandReturnValue = commandReturnValue; + + addObjectToRestore("commandLineFunctionsHash"); + commandWindow.commandLineFunctionsHash = commandLineFunctionsHash; + + var addFunctionToWindow = function(name) { + addObjectToRestore(name); + commandWindow[name] = function() { + return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue); + }; + }; + + for (i = 0, len = commandLineFunctions.length; i < len; i++) { + addFunctionToWindow(commandLineFunctions[i][0]); + } + + // Another bizarre workaround to get IE to eval in the global scope + if (commandWindow === window && commandWindow.execScript) { + addObjectToRestore("evalExpr"); + addObjectToRestore("result"); + window.evalExpr = expr; + commandWindow.execScript("window.result=eval(window.evalExpr);"); + result = window.result; + } else { + result = commandWindow.eval(expr); + } + commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth); + + // Restore variables in the command window to their original state + for (i = 0, len = objectsToRestore.length; i < len; i++) { + commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1]; + } + } catch (ex) { + commandOutput = "Error evaluating command: " + getExceptionStringRep(ex); + commandReturnValue.isError = true; + } + // Append command output + if (commandReturnValue.appendResult) { + var message = ">>> " + expr; + if (!isUndefined(commandOutput)) { + message += newLine + commandOutput; + } + var level = commandReturnValue.isError ? Level.ERROR : Level.INFO; + var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null); + var mainLayout = this.getLayout(); + this.setLayout(commandLayout); + this.append(loggingEvent); + this.setLayout(mainLayout); + } + }; + + var commandLineFunctions = defaultCommandLineFunctions.concat([]); + + this.addCommandLineFunction = function(functionName, commandLineFunction) { + commandLineFunctions.push([functionName, commandLineFunction]); + }; + + var commandHistoryCookieName = "log4javascriptCommandHistory"; + this.storeCommandHistory = function(commandHistory) { + setCookie(commandHistoryCookieName, commandHistory.join(",")); + }; + + var writeHtml = function(doc) { + var lines = getConsoleHtmlLines(); + doc.open(); + for (var i = 0, len = lines.length; i < len; i++) { + doc.writeln(lines[i]); + } + doc.close(); + }; + + // Set up event listeners + this.setEventTypes(["load", "unload"]); + + var consoleWindowLoadHandler = function() { + var win = getConsoleWindow(); + win.setAppender(appender); + win.setNewestAtTop(newestMessageAtTop); + win.setScrollToLatest(scrollToLatestMessage); + win.setMaxMessages(maxMessages); + win.setShowCommandLine(showCommandLine); + win.setShowHideButton(showHideButton); + win.setShowCloseButton(showCloseButton); + win.setMainWindow(window); + + // Restore command history stored in cookie + var storedValue = getCookie(commandHistoryCookieName); + if (storedValue) { + win.commandHistory = storedValue.split(","); + win.currentCommandIndex = win.commandHistory.length; + } + + appender.dispatchEvent("load", { "win" : win }); + }; + + this.unload = function() { + logLog.debug("unload " + this + ", caller: " + this.unload.caller); + if (!consoleClosed) { + logLog.debug("really doing unload " + this); + consoleClosed = true; + consoleWindowLoaded = false; + consoleWindowCreated = false; + appender.dispatchEvent("unload", {}); + } + }; + + var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) { + function doPoll() { + try { + // Test if the console has been closed while polling + if (consoleClosed) { + clearInterval(poll); + } + if (windowTest(getConsoleWindow())) { + clearInterval(poll); + successCallback(); + } + } catch (ex) { + clearInterval(poll); + isSupported = false; + handleError(errorMessage, ex); + } + } + + // Poll the pop-up since the onload event is not reliable + var poll = setInterval(doPoll, interval); + }; + + var getConsoleUrl = function() { + var documentDomainSet = (document.domain != location.hostname); + return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" + + (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : ""); + }; + + // Define methods and properties that vary between subclasses + if (inPage) { + // InPageAppender + + var containerElement = null; + + // Configuration methods. The function scope is used to prevent + // direct alteration to the appender configuration properties. + var cssProperties = []; + this.addCssProperty = function(name, value) { + if (checkCanConfigure("cssProperties")) { + cssProperties.push([name, value]); + } + }; + + // Define useful variables + var windowCreationStarted = false; + var iframeContainerDiv; + var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId; + + this.hide = function() { + if (initialized && consoleWindowCreated) { + if (consoleWindowExists()) { + getConsoleWindow().$("command").blur(); + } + iframeContainerDiv.style.display = "none"; + minimized = true; + } + }; + + this.show = function() { + if (initialized) { + if (consoleWindowCreated) { + iframeContainerDiv.style.display = "block"; + this.setShowCommandLine(showCommandLine); // Force IE to update + minimized = false; + } else if (!windowCreationStarted) { + createWindow(true); + } + } + }; + + this.isVisible = function() { + return !minimized && !consoleClosed; + }; + + this.close = function(fromButton) { + if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) { + iframeContainerDiv.parentNode.removeChild(iframeContainerDiv); + this.unload(); + } + }; + + // Create open, init, getConsoleWindow and safeToAppend functions + open = function() { + var initErrorMessage = "InPageAppender.open: unable to create console iframe"; + + function finalInit() { + try { + if (!initiallyMinimized) { + appender.show(); + } + consoleWindowLoadHandler(); + consoleWindowLoaded = true; + appendQueuedLoggingEvents(); + } catch (ex) { + isSupported = false; + handleError(initErrorMessage, ex); + } + } + + function writeToDocument() { + try { + var windowTest = function(win) { return isLoaded(win); }; + if (useDocumentWrite) { + writeHtml(getConsoleWindow().document); + } + if (windowTest(getConsoleWindow())) { + finalInit(); + } else { + pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage); + } + } catch (ex) { + isSupported = false; + handleError(initErrorMessage, ex); + } + } + + minimized = false; + iframeContainerDiv = containerElement.appendChild(document.createElement("div")); + + iframeContainerDiv.style.width = width; + iframeContainerDiv.style.height = height; + iframeContainerDiv.style.border = "solid gray 1px"; + + for (var i = 0, len = cssProperties.length; i < len; i++) { + iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1]; + } + + var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'"; + + // Adding an iframe using the DOM would be preferable, but it doesn't work + // in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror + // it creates the iframe fine but I haven't been able to find a way to obtain + // the iframe's window object + iframeContainerDiv.innerHTML = ""; + consoleClosed = false; + + // Write the console HTML to the iframe + var iframeDocumentExistsTest = function(win) { + try { + return bool(win) && bool(win.document); + } catch (ex) { + return false; + } + }; + if (iframeDocumentExistsTest(getConsoleWindow())) { + writeToDocument(); + } else { + pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage); + } + consoleWindowCreated = true; + }; + + createWindow = function(show) { + if (show || !initiallyMinimized) { + var pageLoadHandler = function() { + if (!container) { + // Set up default container element + containerElement = document.createElement("div"); + containerElement.style.position = "fixed"; + containerElement.style.left = "0"; + containerElement.style.right = "0"; + containerElement.style.bottom = "0"; + document.body.appendChild(containerElement); + appender.addCssProperty("borderWidth", "1px 0 0 0"); + appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be + open(); + } else { + try { + var el = document.getElementById(container); + if (el.nodeType == 1) { + containerElement = el; + } + open(); + } catch (ex) { + handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex); + } + } + }; + + // Test the type of the container supplied. First, check if it's an element + if (pageLoaded && container && container.appendChild) { + containerElement = container; + open(); + } else if (pageLoaded) { + pageLoadHandler(); + } else { + log4javascript.addEventListener("load", pageLoadHandler); + } + windowCreationStarted = true; + } + }; + + init = function() { + createWindow(); + initialized = true; + }; + + getConsoleWindow = function() { + var iframe = window.frames[iframeId]; + if (iframe) { + return iframe; + } + }; + + safeToAppend = function() { + if (isSupported && !consoleClosed) { + if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) { + consoleWindowLoaded = true; + } + return consoleWindowLoaded; + } + return false; + }; + } else { + // PopUpAppender + + // Extract params + var useOldPopUp = appender.defaults.useOldPopUp; + var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking; + var reopenWhenClosed = this.defaults.reopenWhenClosed; + + // Configuration methods. The function scope is used to prevent + // direct alteration to the appender configuration properties. + this.isUseOldPopUp = function() { return useOldPopUp; }; + this.setUseOldPopUp = function(useOldPopUpParam) { + if (checkCanConfigure("useOldPopUp")) { + useOldPopUp = bool(useOldPopUpParam); + } + }; + + this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; }; + this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) { + if (checkCanConfigure("complainAboutPopUpBlocking")) { + complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam); + } + }; + + this.isFocusPopUp = function() { return focusConsoleWindow; }; + this.setFocusPopUp = function(focusPopUpParam) { + // This property can be safely altered after logging has started + focusConsoleWindow = bool(focusPopUpParam); + }; + + this.isReopenWhenClosed = function() { return reopenWhenClosed; }; + this.setReopenWhenClosed = function(reopenWhenClosedParam) { + // This property can be safely altered after logging has started + reopenWhenClosed = bool(reopenWhenClosedParam); + }; + + this.close = function() { + logLog.debug("close " + this); + try { + popUp.close(); + this.unload(); + } catch (ex) { + // Do nothing + } + }; + + this.hide = function() { + logLog.debug("hide " + this); + if (consoleWindowExists()) { + this.close(); + } + }; + + this.show = function() { + logLog.debug("show " + this); + if (!consoleWindowCreated) { + open(); + } + }; + + this.isVisible = function() { + return safeToAppend(); + }; + + // Define useful variables + var popUp; + + // Create open, init, getConsoleWindow and safeToAppend functions + open = function() { + var windowProperties = "width=" + width + ",height=" + height + ",status,resizable"; + var frameInfo = ""; + try { + var frameEl = window.frameElement; + if (frameEl) { + frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || ""); + } + } catch (e) { + frameInfo = "_inaccessibleParentFrame"; + } + var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo; + if (!useOldPopUp || !useDocumentWrite) { + // Ensure a previous window isn't used by using a unique name + windowName = windowName + "_" + uniqueId; + } + + var checkPopUpClosed = function(win) { + if (consoleClosed) { + return true; + } else { + try { + return bool(win) && win.closed; + } catch(ex) {} + } + return false; + }; + + var popUpClosedCallback = function() { + if (!consoleClosed) { + appender.unload(); + } + }; + + function finalInit() { + getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite); + consoleWindowLoadHandler(); + consoleWindowLoaded = true; + appendQueuedLoggingEvents(); + pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback, + "PopUpAppender.checkPopUpClosed: error checking pop-up window"); + } + + try { + popUp = window.open(getConsoleUrl(), windowName, windowProperties); + consoleClosed = false; + consoleWindowCreated = true; + if (popUp && popUp.document) { + if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) { + popUp.mainPageReloaded(); + finalInit(); + } else { + if (useDocumentWrite) { + writeHtml(popUp.document); + } + // Check if the pop-up window object is available + var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); }; + if (isLoaded(popUp)) { + finalInit(); + } else { + pollConsoleWindow(popUpLoadedTest, 100, finalInit, + "PopUpAppender.init: unable to create console window"); + } + } + } else { + isSupported = false; + logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender"); + if (complainAboutPopUpBlocking) { + handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging."); + } + } + } catch (ex) { + handleError("PopUpAppender.init: error creating pop-up", ex); + } + }; + + createWindow = function() { + if (!initiallyMinimized) { + open(); + } + }; + + init = function() { + createWindow(); + initialized = true; + }; + + getConsoleWindow = function() { + return popUp; + }; + + safeToAppend = function() { + if (isSupported && !isUndefined(popUp) && !consoleClosed) { + if (popUp.closed || + (consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera + appender.unload(); + logLog.debug("PopUpAppender: pop-up closed"); + return false; + } + if (!consoleWindowLoaded && isLoaded(popUp)) { + consoleWindowLoaded = true; + } + } + return isSupported && consoleWindowLoaded && !consoleClosed; + }; + } + + // Expose getConsoleWindow so that automated tests can check the DOM + this.getConsoleWindow = getConsoleWindow; + }; + + ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) { + defaultCommandLineFunctions.push([functionName, commandLineFunction]); + }; + + /* ------------------------------------------------------------------ */ + + function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite, + width, height) { + this.create(false, null, lazyInit, initiallyMinimized, + useDocumentWrite, width, height, this.defaults.focusPopUp); + } + + PopUpAppender.prototype = new ConsoleAppender(); + + PopUpAppender.prototype.defaults = { + layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"), + initiallyMinimized: false, + focusPopUp: false, + lazyInit: true, + useOldPopUp: true, + complainAboutPopUpBlocking: true, + newestMessageAtTop: false, + scrollToLatestMessage: true, + width: "600", + height: "400", + reopenWhenClosed: false, + maxMessages: null, + showCommandLine: true, + commandLineObjectExpansionDepth: 1, + showHideButton: false, + showCloseButton: true, + showLogEntryDeleteButtons: true, + useDocumentWrite: true + }; + + PopUpAppender.prototype.toString = function() { + return "PopUpAppender"; + }; + + log4javascript.PopUpAppender = PopUpAppender; + + /* ------------------------------------------------------------------ */ + + function InPageAppender(container, lazyInit, initiallyMinimized, + useDocumentWrite, width, height) { + this.create(true, container, lazyInit, initiallyMinimized, + useDocumentWrite, width, height, false); + } + + InPageAppender.prototype = new ConsoleAppender(); + + InPageAppender.prototype.defaults = { + layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"), + initiallyMinimized: false, + lazyInit: true, + newestMessageAtTop: false, + scrollToLatestMessage: true, + width: "100%", + height: "220px", + maxMessages: null, + showCommandLine: true, + commandLineObjectExpansionDepth: 1, + showHideButton: false, + showCloseButton: false, + showLogEntryDeleteButtons: true, + useDocumentWrite: true + }; + + InPageAppender.prototype.toString = function() { + return "InPageAppender"; + }; + + log4javascript.InPageAppender = InPageAppender; + + // Next line for backwards compatibility + log4javascript.InlineAppender = InPageAppender; + })(); + /* ---------------------------------------------------------------------- */ + // Console extension functions + + function padWithSpaces(str, len) { + if (str.length < len) { + var spaces = []; + var numberOfSpaces = Math.max(0, len - str.length); + for (var i = 0; i < numberOfSpaces; i++) { + spaces[i] = " "; + } + str += spaces.join(""); + } + return str; + } + + (function() { + function dir(obj) { + var maxLen = 0; + // Obtain the length of the longest property name + for (var p in obj) { + maxLen = Math.max(toStr(p).length, maxLen); + } + // Create the nicely formatted property list + var propList = []; + for (p in obj) { + var propNameStr = " " + padWithSpaces(toStr(p), maxLen + 2); + var propVal; + try { + propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6)); + } catch (ex) { + propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]"; + } + propList.push(propNameStr + propVal); + } + return propList.join(newLine); + } + + var nodeTypes = { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }; + + var preFormattedElements = ["script", "pre"]; + + // This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD + var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"]; + var indentationUnit = " "; + + // Create and return an XHTML string from the node specified + function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) { + includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode; + if (typeof indentation != "string") { + indentation = ""; + } + startNewLine = !!startNewLine; + preformatted = !!preformatted; + var xhtml; + + function isWhitespace(node) { + return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue)); + } + + function fixAttributeValue(attrValue) { + return attrValue.toString().replace(/&/g, "&").replace(/]*>", "i"); + if (regex.test(el.outerHTML)) { + return RegExp.$1.toLowerCase(); + } + } + return ""; + } + + var lt = "<"; + var gt = ">"; + + if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) { + switch (rootNode.nodeType) { + case nodeTypes.ELEMENT_NODE: + var tagName = rootNode.tagName.toLowerCase(); + xhtml = startNewLine ? newLine + indentation : ""; + xhtml += lt; + // Allow for namespaces, where present + var prefix = getNamespace(rootNode); + var hasPrefix = !!prefix; + if (hasPrefix) { + xhtml += prefix + ":"; + } + xhtml += tagName; + for (i = 0, len = rootNode.attributes.length; i < len; i++) { + var currentAttr = rootNode.attributes[i]; + // Check the attribute is valid. + if (! currentAttr.specified || + currentAttr.nodeValue === null || + currentAttr.nodeName.toLowerCase() === "style" || + typeof currentAttr.nodeValue !== "string" || + currentAttr.nodeName.indexOf("_moz") === 0) { + continue; + } + xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\""; + xhtml += fixAttributeValue(currentAttr.nodeValue); + xhtml += "\""; + } + // Style needs to be done separately as it is not reported as an + // attribute in IE + if (rootNode.style.cssText) { + var styleValue = getStyleAttributeValue(rootNode); + if (styleValue !== "") { + xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\""; + } + } + if (array_contains(emptyElements, tagName) || + (hasPrefix && !rootNode.hasChildNodes())) { + xhtml += "/" + gt; + } else { + xhtml += gt; + // Add output for childNodes collection (which doesn't include attribute nodes) + var childStartNewLine = !(rootNode.childNodes.length === 1 && + rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE); + var childPreformatted = array_contains(preFormattedElements, tagName); + for (var i = 0, len = rootNode.childNodes.length; i < len; i++) { + xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit, + childStartNewLine, childPreformatted); + } + // Add the end tag + var endTag = lt + "/" + tagName + gt; + xhtml += childStartNewLine ? newLine + indentation + endTag : endTag; + } + return xhtml; + case nodeTypes.TEXT_NODE: + if (isWhitespace(rootNode)) { + xhtml = ""; + } else { + if (preformatted) { + xhtml = rootNode.nodeValue; + } else { + // Trim whitespace from each line of the text node + var lines = splitIntoLines(trim(rootNode.nodeValue)); + var trimmedLines = []; + for (var i = 0, len = lines.length; i < len; i++) { + trimmedLines[i] = trim(lines[i]); + } + xhtml = trimmedLines.join(newLine + indentation); + } + if (startNewLine) { + xhtml = newLine + indentation + xhtml; + } + } + return xhtml; + case nodeTypes.CDATA_SECTION_NODE: + return "" + newLine; + case nodeTypes.DOCUMENT_NODE: + xhtml = ""; + // Add output for childNodes collection (which doesn't include attribute nodes) + for (var i = 0, len = rootNode.childNodes.length; i < len; i++) { + xhtml += getXhtml(rootNode.childNodes[i], true, indentation); + } + return xhtml; + default: + return ""; + } + } else { + xhtml = ""; + // Add output for childNodes collection (which doesn't include attribute nodes) + for (var i = 0, len = rootNode.childNodes.length; i < len; i++) { + xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit); + } + return xhtml; + } + } + + function createCommandLineFunctions() { + ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) { + return document.getElementById(args[0]); + }); + + ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) { + var lines = []; + for (var i = 0, len = args.length; i < len; i++) { + lines[i] = dir(args[i]); + } + return lines.join(newLine + newLine); + }); + + ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) { + var lines = []; + for (var i = 0, len = args.length; i < len; i++) { + var win = appender.getCommandWindow(); + lines[i] = getXhtml(args[i]); + } + return lines.join(newLine + newLine); + }); + + ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) { + var win, message; + if (args.length === 0 || args[0] === "") { + win = window; + message = "Command line set to run in main window"; + } else { + if (args[0].window == args[0]) { + win = args[0]; + message = "Command line set to run in frame '" + args[0].name + "'"; + } else { + win = window.frames[args[0]]; + if (win) { + message = "Command line set to run in frame '" + args[0] + "'"; + } else { + returnValue.isError = true; + message = "Frame '" + args[0] + "' does not exist"; + win = appender.getCommandWindow(); + } + } + } + appender.setCommandWindow(win); + return message; + }); + + ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) { + returnValue.appendResult = false; + appender.clear(); + }); + + ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) { + var keys = []; + for (var k in args[0]) { + keys.push(k); + } + return keys; + }); + + ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) { + var values = []; + for (var k in args[0]) { + try { + values.push(args[0][k]); + } catch (ex) { + logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex)); + } + } + return values; + }); + + ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) { + var expansionDepth = parseInt(args[0], 10); + if (isNaN(expansionDepth) || expansionDepth < 0) { + returnValue.isError = true; + return "" + args[0] + " is not a valid expansion depth"; + } else { + appender.setCommandLineObjectExpansionDepth(expansionDepth); + return "Object expansion depth set to " + expansionDepth; + } + }); + } + + function init() { + // Add command line functions + createCommandLineFunctions(); + } + + /* ------------------------------------------------------------------ */ + + init(); + })(); + + /* ---------------------------------------------------------------------- */ + // Main load + + log4javascript.setDocumentReady = function() { + pageLoaded = true; + log4javascript.dispatchEvent("load", {}); + }; + + if (window.addEventListener) { + window.addEventListener("load", log4javascript.setDocumentReady, false); + } else if (window.attachEvent) { + window.attachEvent("onload", log4javascript.setDocumentReady); + } else { + var oldOnload = window.onload; + if (typeof window.onload != "function") { + window.onload = log4javascript.setDocumentReady; + } else { + window.onload = function(evt) { + if (oldOnload) { + oldOnload(evt); + } + log4javascript.setDocumentReady(); + }; + } + } + + // Ensure that the log4javascript object is available in the window. This + // is necessary for log4javascript to be available in IE if loaded using + // Dojo's module system + window.log4javascript = log4javascript; + + return log4javascript; +})(); \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/main.css b/planetstack/core/static/log4javascript-1.4.6/main.css new file mode 100644 index 0000000..5ac3df3 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/main.css @@ -0,0 +1,300 @@ +body { + font-family: Verdana, Arial, Helvetica, Sans-serif; + font-size: 75%; + color: black; + background-color: #eeeeee; + text-align: center; + padding: 0px; + margin: 0px; +} + +div#container { + width: 770px; + text-align: left; + line-height: 150%; + border-width: 0px 1px 1px 1px; + border-color: #cccccc; + border-style: solid; + background-color: white; + color: black; + padding: 10px; + margin: 0px auto 10px auto; +} + +div#header { + margin: 0px; +} + +div#header h1 { + font-family: Courier New, Courier, Monospace, Serif; + padding: 8px 0 15px 0; + margin: 0px; + font-size: 200%; + font-weight: bold; + text-align: right; +} + +div#header h1 a { + color: black; +} + +div#nav { + font-size: 91.66%; + font-weight: bold; + padding-top: 5px; + padding-bottom: 5px; + border-bottom: solid #cccccc 1px; + text-align: right; + background-color: #f0f0fa; +} + +div#container.nonav div#content { + float: none; + width: auto; +} + +*.externallinkinfo { + float: right; + font-style: italic; +} + +div#content h1 { + padding: 10px 3px 5px 3px; + margin: 5px 0px; + font-size: 175%; + font-weight: normal; +} + +div#content h2 { + background-color: darkgreen; + color: white; + padding: 0px 3px; + font-size: 116.66%; + font-weight: bold; +} + +div#content h2 a { + color: white; +} + +div#content h3 { + padding: 0px 3px; + font-size: 116.66%; + font-weight: bold; + border-style: solid; + border-color: #003399; + border-width: 1px 0px; +} + +div#content h4 { + padding: 0px 3px; + font-size: 100%; + font-weight: bold; + border-top: solid #eeeeee 1px; +} + +div#content h5 { + padding: 0px; + margin: 3px 0px; +} + +div#footer { + margin-top: 20px; + padding: 2px; + border-top: solid #cccccc 1px; + font-size: 91.66%; +} + +a { + color: #003399; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a.bold { + font-weight: bold; +} + +a.underlined { + text-decoration: underline; +} + +a img { + border-width: 0px; +} + +br.clear { + clear: both; +} + +table { + font-size: 100%; +} + +/* Code */ +pre, code { + font-family: Courier New, Courier; + font-size: 108.33%; +} + +pre.code, pre.console { + border: solid 1px #cccccc; + padding: 3px; +} + +pre.code { + background-color: #eeeeee; +} + +*.trace { + color: #666666; +} + +*.debug { + color: green; +} + +*.info { + color: #000099; +} + +*.warn { + color: #999900; +} + +*.error { + color: red; +} + +*.fatal { + color: #660066; +} + + +div.example, div.panel { + border: solid 1px #cccccc; + background-color: #f5f5f5; + padding: 3px; + margin-bottom: 10px; +} + +div.panel h2 { + margin: 5px 0px; +} + +div.padded { + padding: 10px; +} + +div.hidden { + display: none; +} + +div.active { + background-color: #fcfffc; + border-color: green; +} + +label.rightofinput, input.rightoflabel { + margin-right: 20px; +} + +/* 'Back to top' link */ +p.linktotop { + text-align: right; +} + +ul.propertieslist li.method, ul.propertieslist li.property { + margin: 0; + padding: 0px 0px 15px 0px; +} + +ul.propertieslist li *.name { + font-size: 116.66%; + font-weight: bold; +} + +ul.propertieslist li.method div.methodsignature { + margin: 10px 0px; + font-size: 116.66%; + background-color: #eeeeee; +} + +ul.propertieslist li.method *.paramsheading { + font-weight: bold; +} + +ul.propertieslist li.method *.params { + padding-top: 5px; + padding-bottom: 5px; +} + +ul.propertieslist li.method *.params li.param { + padding-bottom: 10px; +} + +ul.propertieslist li.method *.params li.param *.paramname { + font-style: italic; +} + +div.serverlog { + height: 200px; + /*border: solid 1px #cccccc;*/ +} + +div#inPageConsole { + margin-top: 10px; +} + +div.iframecontainer { + background-color: white; + border: solid #cccccc 1px; + width: 100%; +} + +div.veryprominent { + background-color: darkgreen; + color: white; + font-weight: bold; + padding: 10px; + font-size: 133.33%; + margin-bottom: 10px; +} + +div.veryprominent a { + color: white; +} + +*.largetext { + font-size: 116.66%; +} + +div#leftcolumn { + float: left; + width: 160px; +} + +div#rightcolumn { + float: right; + width: 580px; +} + +td.fullsupport { + background-color: lightgreen; +} + +td.partialsupport { + background-color: gold; +} + +td.nosupport { + background-color: lightcoral; +} + +p.editions { + text-align: right; + font-style: italic; +} \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/test/index.html b/planetstack/core/static/log4javascript-1.4.6/test/index.html new file mode 100644 index 0000000..e01f13c --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/index.html @@ -0,0 +1,15 @@ + + + + + log4javascript - Tests + + + + + diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript.html new file mode 100644 index 0000000..8e426b9 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript - Tests + + + + + + + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite.html new file mode 100644 index 0000000..508dc83 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_lite - Tests + + + + + + + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html new file mode 100644 index 0000000..968019c --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_lite_uncompressed - Tests + + + + + + + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production.html new file mode 100644 index 0000000..e5308b1 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_production - Tests + + + + + + + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html new file mode 100644 index 0000000..21f84d7 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_production_uncompressed - Tests + + + + + + + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html new file mode 100644 index 0000000..3db9241 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_uncompressed - Tests + + + + + + + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/test/main.html b/planetstack/core/static/log4javascript-1.4.6/test/main.html new file mode 100644 index 0000000..176098f --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/main.html @@ -0,0 +1,16 @@ + + + + + log4javascript - %%build:edition%% - Tests + + + + + + + +
+
+ + diff --git a/planetstack/core/static/log4javascript-1.4.6/test/tests.css b/planetstack/core/static/log4javascript-1.4.6/test/tests.css new file mode 100644 index 0000000..9cddef8 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/tests.css @@ -0,0 +1,88 @@ +body { + font-family: verdana, arial, helvetica, sans-serif; + font-size: 81.25%; +} + +h2 { + font-size: 100%; + padding: 0; + margin: 0.1em 0 0.1em 0; +} + +div.xn_test_suite_container { + border: solid #cccccc 1px; + padding: 2px 5px; + margin: 2px 0px; +} + +div.xn_test_progressbar_container { + border: solid black 1px; +} + +div.xn_test_progressbar_container *.success { + background-color: #00ff00; +} + +div.xn_test_progressbar_container *.failure { + background-color: red; +} + +div.xn_test_overallprogressbar_container { + position: relative; +} + +div.xn_test_overallprogressbar_container h1 { + margin: 0; + padding: 2px; + font-size: 125%; + font-weight: bold; + white-space: nowrap; +} + +dl *.success { + color: green; +} + +dl *.failure { + color: red; +} + +span.xn_test_expander { + padding: 0; + border: solid black 1px; + cursor: pointer; + cursor: hand; + line-height: 100%; + font-weight: bold; + margin-right: 1em; + font-size: 11px; +} + +dl.xn_test_expanded { + display: block; +} + +dl.xn_test_collapsed { + display: none; +} + +div.xn_test_suite_success { + border: solid 2px limegreen; +} + +div.xn_test_suite_failure { + border: solid 2px red; +} + +pre.xn_test_log_report { + background-color: #f5f5f5; + padding: 3px; + border: solid gray 1px; + font-size: 11px; + font-family: Courier New, Courier, monospace; +} + +code.xn_test_stacktrace { + color: red; + overflow: +} \ No newline at end of file diff --git a/planetstack/core/static/log4javascript-1.4.6/test/xntest.js b/planetstack/core/static/log4javascript-1.4.6/test/xntest.js new file mode 100644 index 0000000..1b8f475 --- /dev/null +++ b/planetstack/core/static/log4javascript-1.4.6/test/xntest.js @@ -0,0 +1,739 @@ +// Next three methods are primarily for IE5, which is missing them +if (!Array.prototype.push) { + Array.prototype.push = function() { + for (var i = 0; i < arguments.length; i++){ + this[this.length] = arguments[i]; + } + return this.length; + }; +} + +if (!Array.prototype.shift) { + Array.prototype.shift = function() { + if (this.length > 0) { + var firstItem = this[0]; + for (var i = 0; i < this.length - 1; i++) { + this[i] = this[i + 1]; + } + this.length = this.length - 1; + return firstItem; + } + }; +} + +if (!Function.prototype.apply) { + Function.prototype.apply = function(obj, args) { + var methodName = "__apply__"; + if (typeof obj[methodName] != "undefined") { + methodName += (String(Math.random())).substr(2); + } + obj[methodName] = this; + + var argsStrings = new Array(args.length); + for (var i = 0; i < args.length; i++) { + argsStrings[i] = "args[" + i + "]"; + } + var script = "obj." + methodName + "(" + argsStrings.join(",") + ")"; + var returnValue = eval(script); + delete obj[methodName]; + return returnValue; + }; +} + +/* -------------------------------------------------------------------------- */ + +var xn = new Object(); + +(function() { + // Utility functions + + // Event listeners + var getListenersPropertyName = function(eventName) { + return "__listeners__" + eventName; + }; + + var addEventListener = function(node, eventName, listener, useCapture) { + useCapture = Boolean(useCapture); + if (node.addEventListener) { + node.addEventListener(eventName, listener, useCapture); + } else if (node.attachEvent) { + node.attachEvent("on" + eventName, listener); + } else { + var propertyName = getListenersPropertyName(eventName); + if (!node[propertyName]) { + node[propertyName] = new Array(); + + // Set event handler + node["on" + eventName] = function(evt) { + evt = module.getEvent(evt); + var listenersPropertyName = getListenersPropertyName(eventName); + + // Clone the array of listeners to leave the original untouched + var listeners = cloneArray(this[listenersPropertyName]); + var currentListener; + + // Call each listener in turn + while (currentListener = listeners.shift()) { + currentListener.call(this, evt); + } + }; + } + node[propertyName].push(listener); + } + }; + + // Clones an array + var cloneArray = function(arr) { + var clonedArray = []; + for (var i = 0; i < arr.length; i++) { + clonedArray[i] = arr[i]; + } + return clonedArray; + } + + var isFunction = function(f) { + if (!f){ return false; } + return (f instanceof Function || typeof f == "function"); + }; + + // CSS Utilities + + function array_contains(arr, val) { + for (var i = 0, len = arr.length; i < len; i++) { + if (arr[i] === val) { + return true; + } + } + return false; + } + + function addClass(el, cssClass) { + if (!hasClass(el, cssClass)) { + if (el.className) { + el.className += " " + cssClass; + } else { + el.className = cssClass; + } + } + } + + function hasClass(el, cssClass) { + if (el.className) { + var classNames = el.className.split(" "); + return array_contains(classNames, cssClass); + } + return false; + } + + function removeClass(el, cssClass) { + if (hasClass(el, cssClass)) { + // Rebuild the className property + var existingClasses = el.className.split(" "); + var newClasses = []; + for (var i = 0; i < existingClasses.length; i++) { + if (existingClasses[i] != cssClass) { + newClasses[newClasses.length] = existingClasses[i]; + } + } + el.className = newClasses.join(" "); + } + } + + function replaceClass(el, newCssClass, oldCssClass) { + removeClass(el, oldCssClass); + addClass(el, newCssClass); + } + + function getExceptionStringRep(ex) { + if (ex) { + var exStr = "Exception: "; + if (ex.message) { + exStr += ex.message; + } else if (ex.description) { + exStr += ex.description; + } + if (ex.lineNumber) { + exStr += " on line number " + ex.lineNumber; + } + if (ex.fileName) { + exStr += " in file " + ex.fileName; + } + return exStr; + } + return null; + } + + + /* ---------------------------------------------------------------------- */ + + /* Configure the test logger try to use FireBug */ + var log, error; + if (window["console"] && typeof console.log == "function") { + log = function() { + if (xn.test.enableTestDebug) { + console.log.apply(console, arguments); + } + }; + error = function() { + if (xn.test.enableTestDebug) { + console.error.apply(console, arguments); + } + }; + } else { + log = function() {}; + } + + /* Set up something to report to */ + + var initialized = false; + var container; + var progressBarContainer, progressBar, overallSummaryText; + var currentTest = null; + var suites = []; + var totalTestCount = 0; + var currentTestIndex = 0; + var testFailed = false; + var testsPassedCount = 0; + var startTime; + + var log4javascriptEnabled = false; + + var nextSuiteIndex = 0; + + function runNextSuite() { + if (nextSuiteIndex < suites.length) { + suites[nextSuiteIndex++].run(); + } + } + + var init = function() { + if (initialized) { return true; } + + container = document.createElement("div"); + + // Create the overall progress bar + progressBarContainer = container.appendChild(document.createElement("div")); + progressBarContainer.className = "xn_test_progressbar_container xn_test_overallprogressbar_container"; + progressBar = progressBarContainer.appendChild(document.createElement("div")); + progressBar.className = "success"; + + document.body.appendChild(container); + + var h1 = progressBar.appendChild(document.createElement("h1")); + overallSummaryText = h1.appendChild(document.createTextNode("")); + + initialized = true; + + // Set up logging + log4javascriptEnabled = !!log4javascript && xn.test.enable_log4javascript; + + function TestLogAppender() {} + + if (log4javascriptEnabled) { + TestLogAppender.prototype = new log4javascript.Appender(); + TestLogAppender.prototype.layout = new log4javascript.PatternLayout("%d{HH:mm:ss,SSS} %-5p %m"); + TestLogAppender.prototype.append = function(loggingEvent) { + var formattedMessage = this.getLayout().format(loggingEvent); + if (this.getLayout().ignoresThrowable()) { + formattedMessage += loggingEvent.getThrowableStrRep(); + } + currentTest.addLogMessage(formattedMessage); + }; + + var appender = new TestLogAppender(); + appender.setThreshold(log4javascript.Level.ALL); + log4javascript.getRootLogger().addAppender(appender); + log4javascript.getRootLogger().setLevel(log4javascript.Level.ALL); + } + + startTime = new Date(); + + // First, build each suite + for (var i = 0; i < suites.length; i++) { + suites[i].build(); + totalTestCount += suites[i].tests.length; + } + + // Now run each suite + runNextSuite(); + }; + + function updateProgressBar() { + progressBar.style.width = "" + parseInt(100 * (currentTestIndex) / totalTestCount) + "%"; + var s = (totalTestCount === 1) ? "" : "s"; + var timeTaken = new Date().getTime() - startTime.getTime(); + overallSummaryText.nodeValue = "" + testsPassedCount + " of " + totalTestCount + " test" + s + " passed in " + timeTaken + "ms"; + } + + addEventListener(window, "load", init); + + /* ---------------------------------------------------------------------- */ + + /* Test Suite */ + var Suite = function(name, callback, hideSuccessful) { + this.name = name; + this.callback = callback; + this.hideSuccessful = hideSuccessful; + this.tests = []; + this.log = log; + this.error = error; + this.expanded = true; + suites.push(this); + } + + Suite.prototype.test = function(name, callback, setUp, tearDown) { + this.log("adding a test named " + name) + var t = new Test(name, callback, this, setUp, tearDown); + this.tests.push(t); + }; + + Suite.prototype.build = function() { + // Build the elements used by the suite + var suite = this; + this.testFailed = false; + this.container = document.createElement("div"); + this.container.className = "xn_test_suite_container"; + + var heading = document.createElement("h2"); + this.expander = document.createElement("span"); + this.expander.className = "xn_test_expander"; + this.expander.onclick = function() { + if (suite.expanded) { + suite.collapse(); + } else { + suite.expand(); + } + }; + heading.appendChild(this.expander); + + this.headingTextNode = document.createTextNode(this.name); + heading.appendChild(this.headingTextNode); + this.container.appendChild(heading); + + this.reportContainer = document.createElement("dl"); + this.container.appendChild(this.reportContainer); + + this.progressBarContainer = document.createElement("div"); + this.progressBarContainer.className = "xn_test_progressbar_container"; + this.progressBar = document.createElement("div"); + this.progressBar.className = "success"; + this.progressBar.innerHTML = " "; + this.progressBarContainer.appendChild(this.progressBar); + this.reportContainer.appendChild(this.progressBarContainer); + + this.expand(); + + container.appendChild(this.container); + + // invoke callback to build the tests + this.callback.apply(this, [this]); + }; + + Suite.prototype.run = function() { + this.log("running suite '%s'", this.name) + this.startTime = new Date(); + + // now run the first test + this._currentIndex = 0; + this.runNextTest(); + }; + + Suite.prototype.updateProgressBar = function() { + // Update progress bar + this.progressBar.style.width = "" + parseInt(100 * (this._currentIndex) / this.tests.length) + "%"; + //log(this._currentIndex + ", " + this.tests.length + ", " + progressBar.style.width + ", " + progressBar.className); + }; + + Suite.prototype.expand = function() { + this.expander.innerHTML = "-"; + replaceClass(this.reportContainer, "xn_test_expanded", "xn_test_collapsed"); + this.expanded = true; + }; + + Suite.prototype.collapse = function() { + this.expander.innerHTML = "+"; + replaceClass(this.reportContainer, "xn_test_collapsed", "xn_test_expanded"); + this.expanded = false; + }; + + Suite.prototype.finish = function(timeTaken) { + var newClass = this.testFailed ? "xn_test_suite_failure" : "xn_test_suite_success"; + var oldClass = this.testFailed ? "xn_test_suite_success" : "xn_test_suite_failure"; + replaceClass(this.container, newClass, oldClass); + + this.headingTextNode.nodeValue += " (" + timeTaken + "ms)"; + + if (this.hideSuccessful && !this.testFailed) { + this.collapse(); + } + runNextSuite(); + }; + + /** + * Works recursively with external state (the next index) + * so that we can handle async tests differently + */ + Suite.prototype.runNextTest = function() { + if (this._currentIndex == this.tests.length) { + // finished! + var timeTaken = new Date().getTime() - this.startTime.getTime(); + + this.finish(timeTaken); + return; + } + + var suite = this; + var t = this.tests[this._currentIndex++]; + currentTestIndex++; + + if (isFunction(suite.setUp)) { + suite.setUp.apply(suite, [t]); + } + if (isFunction(t.setUp)) { + t.setUp.apply(t, [t]); + } + + t._run(); + + function afterTest() { + if (isFunction(suite.tearDown)) { + suite.tearDown.apply(suite, [t]); + } + if (isFunction(t.tearDown)) { + t.tearDown.apply(t, [t]); + } + suite.log("finished test [%s]", t.name); + updateProgressBar(); + suite.updateProgressBar(); + suite.runNextTest(); + } + + if (t.isAsync) { + t.whenFinished = afterTest; + } else { + setTimeout(afterTest, 1); + } + }; + + Suite.prototype.reportSuccess = function() { + }; + + /* ---------------------------------------------------------------------- */ + /** + * Create a new test + */ + var Test = function(name, callback, suite, setUp, tearDown) { + this.name = name; + this.callback = callback; + this.suite = suite; + this.setUp = setUp; + this.tearDown = tearDown; + this.log = log; + this.error = error; + this.assertCount = 0; + this.logMessages = []; + this.logExpanded = false; + }; + + /** + * Default success reporter, please override + */ + Test.prototype.reportSuccess = function(name, timeTaken) { + /* default success reporting handler */ + this.reportHeading = document.createElement("dt"); + var text = this.name + " passed in " + timeTaken + "ms"; + + this.reportHeading.appendChild(document.createTextNode(text)); + + this.reportHeading.className = "success"; + var dd = document.createElement("dd"); + dd.className = "success"; + + this.suite.reportContainer.appendChild(this.reportHeading); + this.suite.reportContainer.appendChild(dd); + this.createLogReport(); + }; + + /** + * Cause the test to immediately fail + */ + Test.prototype.reportFailure = function(name, msg, ex) { + this.suite.testFailed = true; + this.suite.progressBar.className = "failure"; + progressBar.className = "failure"; + this.reportHeading = document.createElement("dt"); + this.reportHeading.className = "failure"; + var text = document.createTextNode(this.name); + this.reportHeading.appendChild(text); + + var dd = document.createElement("dd"); + dd.appendChild(document.createTextNode(msg)); + dd.className = "failure"; + + this.suite.reportContainer.appendChild(this.reportHeading); + this.suite.reportContainer.appendChild(dd); + if (ex && ex.stack) { + var stackTraceContainer = this.suite.reportContainer.appendChild(document.createElement("code")); + stackTraceContainer.className = "xn_test_stacktrace"; + stackTraceContainer.innerHTML = ex.stack.replace(/\r/g, "\n").replace(/\n{1,2}/g, "
"); + } + this.createLogReport(); + }; + + Test.prototype.createLogReport = function() { + if (this.logMessages.length > 0) { + this.reportHeading.appendChild(document.createTextNode(" (")); + var logToggler = this.reportHeading.appendChild(document.createElement("a")); + logToggler.href = "#"; + logToggler.innerHTML = "show log"; + var test = this; + + logToggler.onclick = function() { + if (test.logExpanded) { + test.hideLogReport(); + this.innerHTML = "show log"; + test.logExpanded = false; + } else { + test.showLogReport(); + this.innerHTML = "hide log"; + test.logExpanded = true; + } + return false; + }; + + this.reportHeading.appendChild(document.createTextNode(")")); + + // Create log report + this.logReport = this.suite.reportContainer.appendChild(document.createElement("pre")); + this.logReport.style.display = "none"; + this.logReport.className = "xn_test_log_report"; + var logMessageDiv; + for (var i = 0, len = this.logMessages.length; i < len; i++) { + logMessageDiv = this.logReport.appendChild(document.createElement("div")); + logMessageDiv.appendChild(document.createTextNode(this.logMessages[i])); + } + } + }; + + Test.prototype.showLogReport = function() { + this.logReport.style.display = "inline-block"; + }; + + Test.prototype.hideLogReport = function() { + this.logReport.style.display = "none"; + }; + + Test.prototype.async = function(timeout, callback) { + timeout = timeout || 250; + var self = this; + var timedOutFunc = function() { + if (!self.completed) { + var message = (typeof callback === "undefined") ? + "Asynchronous test timed out" : callback(self); + self.fail(message); + } + } + var timer = setTimeout(function () { timedOutFunc.apply(self, []); }, timeout) + this.isAsync = true; + }; + + /** + * Run the test + */ + Test.prototype._run = function() { + this.log("starting test [%s]", this.name); + this.startTime = new Date(); + currentTest = this; + try { + this.callback(this); + if (!this.completed && !this.isAsync) { + this.succeed(); + } + } catch (e) { + this.log("test [%s] threw exception [%s]", this.name, e); + var s = (this.assertCount === 1) ? "" : "s"; + this.fail("Exception thrown after " + this.assertCount + " successful assertion" + s + ": " + getExceptionStringRep(e), e); + } + }; + + /** + * Cause the test to immediately succeed + */ + Test.prototype.succeed = function() { + if (this.completed) { return false; } + // this.log("test [%s] succeeded", this.name); + this.completed = true; + var timeTaken = new Date().getTime() - this.startTime.getTime(); + testsPassedCount++; + this.reportSuccess(this.name, timeTaken); + if (this.whenFinished) { + this.whenFinished(); + } + }; + + Test.prototype.fail = function(msg, ex) { + if (typeof msg != "string") { + msg = getExceptionStringRep(msg); + } + if (this.completed) { return false; } + this.completed = true; + // this.log("test [%s] failed", this.name); + this.reportFailure(this.name, msg, ex); + if (this.whenFinished) { + this.whenFinished(); + } + }; + + Test.prototype.addLogMessage = function(logMessage) { + this.logMessages.push(logMessage); + }; + + /* assertions */ + var displayStringForValue = function(obj) { + if (obj === null) { + return "null"; + } else if (typeof obj === "undefined") { + return "undefined"; + } + return obj.toString(); + }; + + var assert = function(args, expectedArgsCount, testFunction, defaultComment) { + this.assertCount++; + var comment = defaultComment; + var i; + var success; + var values = []; + if (args.length == expectedArgsCount) { + for (i = 0; i < args.length; i++) { + values[i] = args[i]; + } + } else if (args.length == expectedArgsCount + 1) { + comment = args[0]; + for (i = 1; i < args.length; i++) { + values[i - 1] = args[i]; + } + } else { + throw new Error("Invalid number of arguments passed to assert function"); + } + success = testFunction(values); + if (!success) { + var regex = /\{([0-9]+)\}/; + while (regex.test(comment)) { + comment = comment.replace(regex, displayStringForValue(values[parseInt(RegExp.$1)])); + } + this.fail("Test failed on assertion " + this.assertCount + ": " + comment); + } + }; + + var testNull = function(values) { + return (values[0] === null); + }; + + Test.prototype.assertNull = function() { + assert.apply(this, [arguments, 1, testNull, "Expected to be null but was {0}"]); + } + + var testNotNull = function(values) { + return (values[0] !== null); + }; + + Test.prototype.assertNotNull = function() { + assert.apply(this, [arguments, 1, testNotNull, "Expected not to be null but was {0}"]); + } + + var testBoolean = function(values) { + return (Boolean(values[0])); + }; + + Test.prototype.assert = function() { + assert.apply(this, [arguments, 1, testBoolean, "Expected not to be equivalent to false"]); + }; + + var testTrue = function(values) { + return (values[0] === true); + }; + + Test.prototype.assertTrue = function() { + assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]); + }; + + Test.prototype.assert = function() { + assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]); + }; + + var testFalse = function(values) { + return (values[0] === false); + }; + + Test.prototype.assertFalse = function() { + assert.apply(this, [arguments, 1, testFalse, "Expected to be false but was {0}"]); + } + + var testEquivalent = function(values) { + return (values[0] === values[1]); + }; + + Test.prototype.assertEquivalent = function() { + assert.apply(this, [arguments, 2, testEquivalent, "Expected to be equal but values were {0} and {1}"]); + } + + var testNotEquivalent = function(values) { + return (values[0] !== values[1]); + }; + + Test.prototype.assertNotEquivalent = function() { + assert.apply(this, [arguments, 2, testNotEquivalent, "Expected to be not equal but values were {0} and {1}"]); + } + + var testEquals = function(values) { + return (values[0] == values[1]); + }; + + Test.prototype.assertEquals = function() { + assert.apply(this, [arguments, 2, testEquals, "Expected to be equal but values were {0} and {1}"]); + } + + var testNotEquals = function(values) { + return (values[0] != values[1]); + }; + + Test.prototype.assertNotEquals = function() { + assert.apply(this, [arguments, 2, testNotEquals, "Expected to be not equal but values were {0} and {1}"]); + } + + var testRegexMatches = function(values) { + return (values[0].test(values[1])); + }; + + Test.prototype.assertRegexMatches = function() { + assert.apply(this, [arguments, 2, testRegexMatches, "Expected regex {0} to match value {1} but it didn't"]); + } + + Test.prototype.assertError = function(f, errorType) { + try { + f(); + this.fail("Expected error to be thrown"); + } catch (e) { + if (errorType && (!(e instanceof errorType))) { + this.fail("Expected error of type " + errorType + " to be thrown but error thrown was " + e); + } + } + }; + + /** + * Execute a synchronous test + */ + xn.test = function(name, callback) { + xn.test.suite("Anonymous", function(s) { + s.test(name, callback); + }); + } + + /** + * Create a test suite with a given name + */ + xn.test.suite = function(name, callback, hideSuccessful) { + var s = new Suite(name, callback, hideSuccessful); + } +})(); \ No newline at end of file diff --git a/planetstack/core/static/planetstack.css b/planetstack/core/static/planetstack.css index 873a9d9..59b2199 100644 --- a/planetstack/core/static/planetstack.css +++ b/planetstack/core/static/planetstack.css @@ -535,3 +535,32 @@ background-image: url("Users_over.png"); .left-nav>ul>li.active>a>.icon-reservation , .left-nav>ul>li:hover>a>.icon-reservation , .left-nav>ul>li.focus>a>.icon-reservation{ background-image: url("Reservations_over.png"); } + +#dashboardHPC { + padding-bottom: 10px; +} +.summary-attr { + padding-right: 20px; +} +.summary-attr-util { + padding-right: 20px; + color: green; +} +.SiteDetail { +color: darkBlue; + font-size: 1.5em; +} +#addSlivers { + color: green; +text-decoration: underline; + padding-right: 20px; +} +#remSlivers { + color: red; + text-decoration: underline; +} +#map-us { + padding-top: 10px; + width: 700px; + height: 400px; +} diff --git a/planetstack/templates/admin/dashboard/welcome.html b/planetstack/templates/admin/dashboard/welcome.html index 707ee96..bec703d 100644 --- a/planetstack/templates/admin/dashboard/welcome.html +++ b/planetstack/templates/admin/dashboard/welcome.html @@ -22,4 +22,100 @@ {% endif %} {% endfor %} + +

HPC Dashboard

+ + Active Slivers: 78 + Overall Throughput: 58Gbps + CPU Utilization: 45% + + +
+ + + + + + {% endblock %}