From 47d5ce5d85c9d99b9c2e32f259321cdf4bcb676b Mon Sep 17 00:00:00 2001 From: benpriebe Date: Mon, 10 Aug 2015 09:19:12 +1000 Subject: [PATCH 1/3] removed 1.4.9 files --- README.md | 6 - changelog.txt | 388 -- console.html | 263 - console_uncompressed.html | 2279 ------- demos/basic.html | 159 - demos/blank.html | 4 - demos/index.html | 49 - demos/inpage.html | 174 - demos/lite.html | 148 - demos/logger.php | 9 - demos/sessionlog.php | 7 - docs/backwardsincompatibilities.html | 90 - docs/distribution.html | 87 - docs/index.html | 190 - docs/lite.html | 182 - docs/manual.html | 3194 --------- docs/manual_lite.html | 383 -- docs/quickstart.html | 230 - docs/whatsnew.html | 86 - examples/demo.html | 16 - examples/example_manual.html | 31 - examples/example_quickstart_1.html | 36 - examples/myloggingservlet.do | 0 js/console.html | 263 - js/console_uncompressed.html | 2279 ------- js/liteconsole.html | 41 - js/liteconsole_uncompressed.html | 194 - js/log4javascript.js | 272 - js/log4javascript_lite.js | 55 - js/log4javascript_lite_uncompressed.js | 620 -- js/log4javascript_production.js | 188 - js/log4javascript_production_uncompressed.js | 2303 ------- js/log4javascript_uncompressed.js | 5892 ----------------- js/stubs/log4javascript.js | 23 - js/stubs/log4javascript_lite.js | 21 - js/stubs/log4javascript_lite_uncompressed.js | 102 - js/stubs/log4javascript_production.js | 22 - .../log4javascript_production_uncompressed.js | 253 - js/stubs/log4javascript_uncompressed.js | 341 - js/tests/log4javascript.js | 32 - js/tests/log4javascript_lite.js | 16 - js/tests/log4javascript_lite_uncompressed.js | 16 - js/tests/log4javascript_production.js | 28 - .../log4javascript_production_uncompressed.js | 728 -- js/tests/log4javascript_uncompressed.js | 862 --- license.txt | 201 - log4javascript.js | 272 - log4javascript_uncompressed.js | 5892 ----------------- main.css | 300 - test/index.html | 15 - test/log4javascript.html | 16 - test/log4javascript_lite.html | 16 - test/log4javascript_lite_uncompressed.html | 16 - test/log4javascript_production.html | 16 - ...og4javascript_production_uncompressed.html | 16 - test/log4javascript_uncompressed.html | 16 - test/main.html | 16 - test/tests.css | 88 - test/xntest.js | 739 --- 59 files changed, 30181 deletions(-) delete mode 100644 README.md delete mode 100644 changelog.txt delete mode 100644 console.html delete mode 100644 console_uncompressed.html delete mode 100644 demos/basic.html delete mode 100644 demos/blank.html delete mode 100644 demos/index.html delete mode 100644 demos/inpage.html delete mode 100644 demos/lite.html delete mode 100644 demos/logger.php delete mode 100644 demos/sessionlog.php delete mode 100644 docs/backwardsincompatibilities.html delete mode 100644 docs/distribution.html delete mode 100644 docs/index.html delete mode 100644 docs/lite.html delete mode 100644 docs/manual.html delete mode 100644 docs/manual_lite.html delete mode 100644 docs/quickstart.html delete mode 100644 docs/whatsnew.html delete mode 100644 examples/demo.html delete mode 100644 examples/example_manual.html delete mode 100644 examples/example_quickstart_1.html delete mode 100644 examples/myloggingservlet.do delete mode 100644 js/console.html delete mode 100644 js/console_uncompressed.html delete mode 100644 js/liteconsole.html delete mode 100644 js/liteconsole_uncompressed.html delete mode 100644 js/log4javascript.js delete mode 100644 js/log4javascript_lite.js delete mode 100644 js/log4javascript_lite_uncompressed.js delete mode 100644 js/log4javascript_production.js delete mode 100644 js/log4javascript_production_uncompressed.js delete mode 100644 js/log4javascript_uncompressed.js delete mode 100644 js/stubs/log4javascript.js delete mode 100644 js/stubs/log4javascript_lite.js delete mode 100644 js/stubs/log4javascript_lite_uncompressed.js delete mode 100644 js/stubs/log4javascript_production.js delete mode 100644 js/stubs/log4javascript_production_uncompressed.js delete mode 100644 js/stubs/log4javascript_uncompressed.js delete mode 100644 js/tests/log4javascript.js delete mode 100644 js/tests/log4javascript_lite.js delete mode 100644 js/tests/log4javascript_lite_uncompressed.js delete mode 100644 js/tests/log4javascript_production.js delete mode 100644 js/tests/log4javascript_production_uncompressed.js delete mode 100644 js/tests/log4javascript_uncompressed.js delete mode 100644 license.txt delete mode 100644 log4javascript.js delete mode 100644 log4javascript_uncompressed.js delete mode 100644 main.css delete mode 100644 test/index.html delete mode 100644 test/log4javascript.html delete mode 100644 test/log4javascript_lite.html delete mode 100644 test/log4javascript_lite_uncompressed.html delete mode 100644 test/log4javascript_production.html delete mode 100644 test/log4javascript_production_uncompressed.html delete mode 100644 test/log4javascript_uncompressed.html delete mode 100644 test/main.html delete mode 100644 test/tests.css delete mode 100644 test/xntest.js diff --git a/README.md b/README.md deleted file mode 100644 index 54105a4..0000000 --- a/README.md +++ /dev/null @@ -1,6 +0,0 @@ -log4javascript -============== - -http://log4javascript.org - -It contains the log4javascript lib prepared to be used with npm diff --git a/changelog.txt b/changelog.txt deleted file mode 100644 index abf21c2..0000000 --- a/changelog.txt +++ /dev/null @@ -1,388 +0,0 @@ -log4javascript change log -------------------------- - -1.4.9 (12/5/2014) -- Fix for typo in BrowserConsoleAppender - -1.4.8 (18/4/2014) -- Added support for XMLHttpRequest's withCredentials to AjaxAppender - -1.4.7 (7/6/2013) -- Improved multiple browser console argument handling as per feature request #4 - -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/console.html b/console.html deleted file mode 100644 index 476d272..0000000 --- a/console.html +++ /dev/null @@ -1,263 +0,0 @@ - - - -log4javascript - - - - - - - - - - -
-
-
-Filters: - - - - - - - -
- -
-Options: - - - - - - - -
-
-
-
-
-
- - -
-
- - diff --git a/console_uncompressed.html b/console_uncompressed.html deleted file mode 100644 index 55679f8..0000000 --- a/console_uncompressed.html +++ /dev/null @@ -1,2279 +0,0 @@ - - - - log4javascript - - - - - - - - - - - -
-
-
- Filters: - - - - - - - -
- -
- Options: - - - - - - - -
-
-
-
-
-
- - -
-
- - diff --git a/demos/basic.html b/demos/basic.html deleted file mode 100644 index 51d5857..0000000 --- a/demos/basic.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - 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/demos/blank.html b/demos/blank.html deleted file mode 100644 index 7e8ac56..0000000 --- a/demos/blank.html +++ /dev/null @@ -1,4 +0,0 @@ - -Blank page - - \ No newline at end of file diff --git a/demos/index.html b/demos/index.html deleted file mode 100644 index 00e84ac..0000000 --- a/demos/index.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - log4javascript demos - - - - - - - -
- -
- -

log4javascript demos

- -
-
- -
- - - diff --git a/demos/inpage.html b/demos/inpage.html deleted file mode 100644 index 8e47d72..0000000 --- a/demos/inpage.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - 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/demos/lite.html b/demos/lite.html deleted file mode 100644 index a1d2dd3..0000000 --- a/demos/lite.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - 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/demos/logger.php b/demos/logger.php deleted file mode 100644 index 68349d0..0000000 --- a/demos/logger.php +++ /dev/null @@ -1,9 +0,0 @@ - \ No newline at end of file diff --git a/demos/sessionlog.php b/demos/sessionlog.php deleted file mode 100644 index dd36e72..0000000 --- a/demos/sessionlog.php +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/docs/backwardsincompatibilities.html b/docs/backwardsincompatibilities.html deleted file mode 100644 index f212fd4..0000000 --- a/docs/backwardsincompatibilities.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - 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/docs/distribution.html b/docs/distribution.html deleted file mode 100644 index 8f6cdfd..0000000 --- a/docs/distribution.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - 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/docs/index.html b/docs/index.html deleted file mode 100644 index 126f027..0000000 --- a/docs/index.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - 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/docs/lite.html b/docs/lite.html deleted file mode 100644 index 13a942d..0000000 --- a/docs/lite.html +++ /dev/null @@ -1,182 +0,0 @@ - - - - - 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/docs/manual.html b/docs/manual.html deleted file mode 100644 index 54057fb..0000000 --- a/docs/manual.html +++ /dev/null @@ -1,3194 +0,0 @@ - - - - - log4javascript 1.4 manual - - - - - - - -
- -
- -

log4javascript 1.4 manual

-

Contents

- -
-

Introduction

-

- log4javascript currently exists to provide more flexible and configurable JavaScript logging - than that provided by browser developer tools. It works a very wide range of browsers. It was - originally written to ease the pain of JavaScript debugging in the days before browsers came - with advanced developer tools. -

-

- 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. -

-

- 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. -

-

- 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.5, it is possible to override this behaviour so that logging data - is sent as the request payload rather than as a posted form variable. This is done - by setting the Content-Type header sent with each Ajax request - explicitly. For example, if using a - JsonLayout: -

    -
    ajaxApender.addHeader("Content-Type", "application/json");
    -
  • -
  • - 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. -

    -
  • -
  • - From version 1.4.8, AjaxAppender supports the sending of cookies in CORS requests via - the new withCredentials constructor parameter. -
  • -
-

Constructor

-
    -
  • -
    AjaxAppender
    -
    - AjaxAppender(String url[, Boolean withCredentials]) -
    -
    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. -
      -
    • -
    • - withCredentials -

      - Since: 1.4.8 -

      -
      - Specifies whether cookies should be sent with each 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 -

    -

    - From 1.4.5, specifying the Content-Type header using this method - will force logging data to be sent as the Ajax request payload rather than as a - posted form field. -

    -
    -
  • -
  • -
    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/docs/manual_lite.html b/docs/manual_lite.html deleted file mode 100644 index 74e5a7d..0000000 --- a/docs/manual_lite.html +++ /dev/null @@ -1,383 +0,0 @@ - - - - - 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/docs/quickstart.html b/docs/quickstart.html deleted file mode 100644 index 3bffff5..0000000 --- a/docs/quickstart.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - 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/docs/whatsnew.html b/docs/whatsnew.html deleted file mode 100644 index 6e4e06f..0000000 --- a/docs/whatsnew.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - 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/examples/demo.html b/examples/demo.html deleted file mode 100644 index 118b879..0000000 --- a/examples/demo.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - 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/examples/example_manual.html b/examples/example_manual.html deleted file mode 100644 index 68189e3..0000000 --- a/examples/example_manual.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - log4javascript example from manual - - - - - - - - -

log4javascript example from manual

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

log4javascript quick start example 1

- - - - diff --git a/examples/myloggingservlet.do b/examples/myloggingservlet.do deleted file mode 100644 index e69de29..0000000 diff --git a/js/console.html b/js/console.html deleted file mode 100644 index 476d272..0000000 --- a/js/console.html +++ /dev/null @@ -1,263 +0,0 @@ - - - -log4javascript - - - - - - - - - - -
-
-
-Filters: - - - - - - - -
- -
-Options: - - - - - - - -
-
-
-
-
-
- - -
-
- - diff --git a/js/console_uncompressed.html b/js/console_uncompressed.html deleted file mode 100644 index 55679f8..0000000 --- a/js/console_uncompressed.html +++ /dev/null @@ -1,2279 +0,0 @@ - - - - log4javascript - - - - - - - - - - - -
-
-
- Filters: - - - - - - - -
- -
- Options: - - - - - - - -
-
-
-
-
-
- - -
-
- - diff --git a/js/liteconsole.html b/js/liteconsole.html deleted file mode 100644 index 840a59b..0000000 --- a/js/liteconsole.html +++ /dev/null @@ -1,41 +0,0 @@ - - - -log4javascript - - - - - - - -
-Options: - - - -
-
- - \ No newline at end of file diff --git a/js/liteconsole_uncompressed.html b/js/liteconsole_uncompressed.html deleted file mode 100644 index df5275f..0000000 --- a/js/liteconsole_uncompressed.html +++ /dev/null @@ -1,194 +0,0 @@ - - - - log4javascript - - - - - - - - -
- Options: - - - -
-
- - \ No newline at end of file diff --git a/js/log4javascript.js b/js/log4javascript.js deleted file mode 100644 index 2b8424e..0000000 --- a/js/log4javascript.js +++ /dev/null @@ -1,272 +0,0 @@ -/** - * Copyright 2014 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);},formatWithException:function(loggingEvent){var formatted=this.format(loggingEvent);if(loggingEvent.exception&&this.ignoresThrowable()){formatted+=loggingEvent.getThrowableStrRep();} -return formatted;},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.formatWithException=function(loggingEvent){var messages=loggingEvent.messages,ex=loggingEvent.exception;return ex?messages.concat([ex]):messages;};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,withCredentials){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())){formattedMessages.push(appender.getLayout().formatWithException(currentLoggingEvent));} -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(withCredentials&&withCredentialsSupported){xmlHttp.withCredentials=true;} -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().formatWithException(loggingEvent);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/js/log4javascript_lite_uncompressed.js b/js/log4javascript_lite_uncompressed.js deleted file mode 100644 index 7607ea1..0000000 --- a/js/log4javascript_lite_uncompressed.js +++ /dev/null @@ -1,620 +0,0 @@ -/** - * Copyright 2014 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.9"; - 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/js/log4javascript_production.js b/js/log4javascript_production.js deleted file mode 100644 index f2e0f40..0000000 --- a/js/log4javascript_production.js +++ /dev/null @@ -1,188 +0,0 @@ -/** - * Copyright 2014 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);},formatWithException:function(loggingEvent){var formatted=this.format(loggingEvent);if(loggingEvent.exception&&this.ignoresThrowable()){formatted+=loggingEvent.getThrowableStrRep();} -return formatted;},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.formatWithException=function(loggingEvent){var messages=loggingEvent.messages,ex=loggingEvent.exception;return ex?messages.concat([ex]):messages;};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,withCredentials){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())){formattedMessages.push(appender.getLayout().formatWithException(currentLoggingEvent));} -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(withCredentials&&withCredentialsSupported){xmlHttp.withCredentials=true;} -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/js/log4javascript_production_uncompressed.js b/js/log4javascript_production_uncompressed.js deleted file mode 100644 index cdd9d98..0000000 --- a/js/log4javascript_production_uncompressed.js +++ /dev/null @@ -1,2303 +0,0 @@ -/** - * Copyright 2014 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.9 - * Edition: log4javascript_production - * Build date: 12 May 2014 - * 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.9"; - 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); - }, - - formatWithException: function(loggingEvent) { - var formatted = this.format(loggingEvent); - if (loggingEvent.exception && this.ignoresThrowable()) { - formatted += loggingEvent.getThrowableStrRep(); - } - return formatted; - }, - - 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.formatWithException = function(loggingEvent) { - var messages = loggingEvent.messages, ex = loggingEvent.exception; - return ex ? messages.concat([ex]) : messages; - }; - - 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 xhrFactory = function() { return new XMLHttpRequest(); }; - var xmlHttpFactories = [ - xhrFactory, - function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, - function() { return new ActiveXObject("Microsoft.XMLHTTP"); } - ]; - - var withCredentialsSupported = false; - 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(); - withCredentialsSupported = (factory == xhrFactory && ("withCredentials" in xmlHttp)); - 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, withCredentials) { - 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())) { - formattedMessages.push( appender.getLayout().formatWithException(currentLoggingEvent) ); - } - // 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) { - // Add withCredentials to facilitate CORS requests with cookies - if (withCredentials && withCredentialsSupported) { - xmlHttp.withCredentials = true; - } - 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/js/log4javascript_uncompressed.js b/js/log4javascript_uncompressed.js deleted file mode 100644 index e0edaa5..0000000 --- a/js/log4javascript_uncompressed.js +++ /dev/null @@ -1,5892 +0,0 @@ -/** - * Copyright 2014 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.9 - * Edition: log4javascript - * Build date: 12 May 2014 - * 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.9"; - 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); - }, - - formatWithException: function(loggingEvent) { - var formatted = this.format(loggingEvent); - if (loggingEvent.exception && this.ignoresThrowable()) { - formatted += loggingEvent.getThrowableStrRep(); - } - return formatted; - }, - - 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.formatWithException = function(loggingEvent) { - var messages = loggingEvent.messages, ex = loggingEvent.exception; - return ex ? messages.concat([ex]) : messages; - }; - - 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) { - alert( this.getLayout().formatWithException(loggingEvent) ); - }; - - 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 formattedMessage = appender.getLayout().formatWithException(loggingEvent); - return (typeof formattedMessage == "string") ? [formattedMessage] : formattedMessage; - }; - - var console; - - if ( (console = window.console) && console.log) { // Safari and Firebug - var formattedMessage = getFormattedMessage(); - - // Log to Firebug or the browser console using specific logging - // methods or revert to console.log otherwise - var consoleMethodName; - - if (console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) { - consoleMethodName = "debug"; - } else if (console.info && Level.INFO.equals(loggingEvent.level)) { - consoleMethodName = "info"; - } else if (console.warn && Level.WARN.equals(loggingEvent.level)) { - consoleMethodName = "warn"; - } else if (console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) { - consoleMethodName = "error"; - } else { - consoleMethodName = "log"; - } - - if (console[consoleMethodName].apply) { - console[consoleMethodName].apply(console, formattedMessage); - } else { - console[consoleMethodName](formattedMessage); - } - } else if ((typeof opera != "undefined") && opera.postError) { // Opera - opera.postError(getFormattedMessage()); - } - }; - - 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 xhrFactory = function() { return new XMLHttpRequest(); }; - var xmlHttpFactories = [ - xhrFactory, - function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, - function() { return new ActiveXObject("Microsoft.XMLHTTP"); } - ]; - - var withCredentialsSupported = false; - 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(); - withCredentialsSupported = (factory == xhrFactory && ("withCredentials" in xmlHttp)); - 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, withCredentials) { - 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())) { - formattedMessages.push( appender.getLayout().formatWithException(currentLoggingEvent) ); - } - // 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) { - // Add withCredentials to facilitate CORS requests with cookies - if (withCredentials && withCredentialsSupported) { - xmlHttp.withCredentials = true; - } - 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().formatWithException(loggingEvent); - 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/js/stubs/log4javascript.js b/js/stubs/log4javascript.js deleted file mode 100644 index 2f5eec0..0000000 --- a/js/stubs/log4javascript.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright 2014 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.9",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/js/stubs/log4javascript_lite.js b/js/stubs/log4javascript_lite.js deleted file mode 100644 index 8955589..0000000 --- a/js/stubs/log4javascript_lite.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright 2014 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.9",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/js/stubs/log4javascript_lite_uncompressed.js b/js/stubs/log4javascript_lite_uncompressed.js deleted file mode 100644 index 213e386..0000000 --- a/js/stubs/log4javascript_lite_uncompressed.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright 2014 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.9", - 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/js/stubs/log4javascript_production.js b/js/stubs/log4javascript_production.js deleted file mode 100644 index 29ea121..0000000 --- a/js/stubs/log4javascript_production.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright 2014 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.9",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/js/stubs/log4javascript_production_uncompressed.js b/js/stubs/log4javascript_production_uncompressed.js deleted file mode 100644 index 02e31e7..0000000 --- a/js/stubs/log4javascript_production_uncompressed.js +++ /dev/null @@ -1,253 +0,0 @@ -/** - * Copyright 2014 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.9", - 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/js/stubs/log4javascript_uncompressed.js b/js/stubs/log4javascript_uncompressed.js deleted file mode 100644 index 3d2eecd..0000000 --- a/js/stubs/log4javascript_uncompressed.js +++ /dev/null @@ -1,341 +0,0 @@ -/** - * Copyright 2014 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.9", - 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/js/tests/log4javascript.js b/js/tests/log4javascript.js deleted file mode 100644 index dc1a32f..0000000 --- a/js/tests/log4javascript.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2014 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/js/tests/log4javascript_lite.js b/js/tests/log4javascript_lite.js deleted file mode 100644 index ecfb7ec..0000000 --- a/js/tests/log4javascript_lite.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright 2014 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/js/tests/log4javascript_lite_uncompressed.js b/js/tests/log4javascript_lite_uncompressed.js deleted file mode 100644 index ecfb7ec..0000000 --- a/js/tests/log4javascript_lite_uncompressed.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright 2014 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/js/tests/log4javascript_production.js b/js/tests/log4javascript_production.js deleted file mode 100644 index e4cf8f9..0000000 --- a/js/tests/log4javascript_production.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright 2014 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/js/tests/log4javascript_production_uncompressed.js b/js/tests/log4javascript_production_uncompressed.js deleted file mode 100644 index a44cb1b..0000000 --- a/js/tests/log4javascript_production_uncompressed.js +++ /dev/null @@ -1,728 +0,0 @@ -/** - * Copyright 2014 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/js/tests/log4javascript_uncompressed.js b/js/tests/log4javascript_uncompressed.js deleted file mode 100644 index 2fd9d27..0000000 --- a/js/tests/log4javascript_uncompressed.js +++ /dev/null @@ -1,862 +0,0 @@ -/** - * Copyright 2014 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/license.txt b/license.txt deleted file mode 100644 index 29f81d8..0000000 --- a/license.txt +++ /dev/null @@ -1,201 +0,0 @@ - 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/log4javascript.js b/log4javascript.js deleted file mode 100644 index 2b8424e..0000000 --- a/log4javascript.js +++ /dev/null @@ -1,272 +0,0 @@ -/** - * Copyright 2014 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);},formatWithException:function(loggingEvent){var formatted=this.format(loggingEvent);if(loggingEvent.exception&&this.ignoresThrowable()){formatted+=loggingEvent.getThrowableStrRep();} -return formatted;},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.formatWithException=function(loggingEvent){var messages=loggingEvent.messages,ex=loggingEvent.exception;return ex?messages.concat([ex]):messages;};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,withCredentials){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())){formattedMessages.push(appender.getLayout().formatWithException(currentLoggingEvent));} -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(withCredentials&&withCredentialsSupported){xmlHttp.withCredentials=true;} -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().formatWithException(loggingEvent);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.9 - * Edition: log4javascript - * Build date: 12 May 2014 - * 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.9"; - 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); - }, - - formatWithException: function(loggingEvent) { - var formatted = this.format(loggingEvent); - if (loggingEvent.exception && this.ignoresThrowable()) { - formatted += loggingEvent.getThrowableStrRep(); - } - return formatted; - }, - - 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.formatWithException = function(loggingEvent) { - var messages = loggingEvent.messages, ex = loggingEvent.exception; - return ex ? messages.concat([ex]) : messages; - }; - - 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) { - alert( this.getLayout().formatWithException(loggingEvent) ); - }; - - 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 formattedMessage = appender.getLayout().formatWithException(loggingEvent); - return (typeof formattedMessage == "string") ? [formattedMessage] : formattedMessage; - }; - - var console; - - if ( (console = window.console) && console.log) { // Safari and Firebug - var formattedMessage = getFormattedMessage(); - - // Log to Firebug or the browser console using specific logging - // methods or revert to console.log otherwise - var consoleMethodName; - - if (console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) { - consoleMethodName = "debug"; - } else if (console.info && Level.INFO.equals(loggingEvent.level)) { - consoleMethodName = "info"; - } else if (console.warn && Level.WARN.equals(loggingEvent.level)) { - consoleMethodName = "warn"; - } else if (console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) { - consoleMethodName = "error"; - } else { - consoleMethodName = "log"; - } - - if (console[consoleMethodName].apply) { - console[consoleMethodName].apply(console, formattedMessage); - } else { - console[consoleMethodName](formattedMessage); - } - } else if ((typeof opera != "undefined") && opera.postError) { // Opera - opera.postError(getFormattedMessage()); - } - }; - - 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 xhrFactory = function() { return new XMLHttpRequest(); }; - var xmlHttpFactories = [ - xhrFactory, - function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, - function() { return new ActiveXObject("Microsoft.XMLHTTP"); } - ]; - - var withCredentialsSupported = false; - 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(); - withCredentialsSupported = (factory == xhrFactory && ("withCredentials" in xmlHttp)); - 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, withCredentials) { - 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())) { - formattedMessages.push( appender.getLayout().formatWithException(currentLoggingEvent) ); - } - // 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) { - // Add withCredentials to facilitate CORS requests with cookies - if (withCredentials && withCredentialsSupported) { - xmlHttp.withCredentials = true; - } - 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().formatWithException(loggingEvent); - 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/main.css b/main.css deleted file mode 100644 index 5ac3df3..0000000 --- a/main.css +++ /dev/null @@ -1,300 +0,0 @@ -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/test/index.html b/test/index.html deleted file mode 100644 index e01f13c..0000000 --- a/test/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - log4javascript - Tests - - - - - diff --git a/test/log4javascript.html b/test/log4javascript.html deleted file mode 100644 index 8e426b9..0000000 --- a/test/log4javascript.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - log4javascript - log4javascript - Tests - - - - - - - -
-
- - diff --git a/test/log4javascript_lite.html b/test/log4javascript_lite.html deleted file mode 100644 index 508dc83..0000000 --- a/test/log4javascript_lite.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - log4javascript - log4javascript_lite - Tests - - - - - - - -
-
- - diff --git a/test/log4javascript_lite_uncompressed.html b/test/log4javascript_lite_uncompressed.html deleted file mode 100644 index 968019c..0000000 --- a/test/log4javascript_lite_uncompressed.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - log4javascript - log4javascript_lite_uncompressed - Tests - - - - - - - -
-
- - diff --git a/test/log4javascript_production.html b/test/log4javascript_production.html deleted file mode 100644 index e5308b1..0000000 --- a/test/log4javascript_production.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - log4javascript - log4javascript_production - Tests - - - - - - - -
-
- - diff --git a/test/log4javascript_production_uncompressed.html b/test/log4javascript_production_uncompressed.html deleted file mode 100644 index 21f84d7..0000000 --- a/test/log4javascript_production_uncompressed.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - log4javascript - log4javascript_production_uncompressed - Tests - - - - - - - -
-
- - diff --git a/test/log4javascript_uncompressed.html b/test/log4javascript_uncompressed.html deleted file mode 100644 index 3db9241..0000000 --- a/test/log4javascript_uncompressed.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - log4javascript - log4javascript_uncompressed - Tests - - - - - - - -
-
- - diff --git a/test/main.html b/test/main.html deleted file mode 100644 index 176098f..0000000 --- a/test/main.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - log4javascript - %%build:edition%% - Tests - - - - - - - -
-
- - diff --git a/test/tests.css b/test/tests.css deleted file mode 100644 index 9cddef8..0000000 --- a/test/tests.css +++ /dev/null @@ -1,88 +0,0 @@ -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/test/xntest.js b/test/xntest.js deleted file mode 100644 index 1b8f475..0000000 --- a/test/xntest.js +++ /dev/null @@ -1,739 +0,0 @@ -// 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 From 36d620693ff2033de60847d950bd11c826595f4a Mon Sep 17 00:00:00 2001 From: benpriebe Date: Mon, 10 Aug 2015 09:20:33 +1000 Subject: [PATCH 2/3] v 1.4.13 files --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 59b6358..69adfd9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name" : "log4javascript", "title" : "log4javascript", - "version" : "1.4.9", + "version" : "1.4.13", "author" : { "name" : "Tim Down", "email" : "tim@log4javascript.org", @@ -17,6 +17,6 @@ ], "repository" : { "type": "git", - "url" : "https://github.com/DECK36/log4javascript.git" + "url" : "https://github.com/benpriebe/log4javascript.git" } } From 8d1d2d9e7399e0cfde5b11b39945ae0e8b6b5ef6 Mon Sep 17 00:00:00 2001 From: benpriebe Date: Mon, 10 Aug 2015 09:21:04 +1000 Subject: [PATCH 3/3] v 1.4.13 files --- LICENSE | 202 + README.md | 7 + changelog.txt | 403 ++ console.html | 263 + console_uncompressed.html | 2279 +++++++ demos/basic.html | 159 + demos/blank.html | 4 + demos/index.html | 49 + demos/inpage.html | 174 + demos/lite.html | 148 + demos/logger.php | 9 + demos/sessionlog.php | 7 + docs/backwardsincompatibilities.html | 90 + docs/distribution.html | 87 + docs/index.html | 190 + docs/lite.html | 182 + docs/manual.html | 3217 +++++++++ docs/manual_lite.html | 383 ++ docs/quickstart.html | 230 + docs/whatsnew.html | 86 + examples/demo.html | 16 + examples/example_manual.html | 31 + examples/example_quickstart_1.html | 36 + examples/myloggingservlet.do | 0 js/console.html | 263 + js/console_uncompressed.html | 2279 +++++++ js/liteconsole.html | 41 + js/liteconsole_uncompressed.html | 194 + js/log4javascript.js | 266 + js/log4javascript_lite.js | 55 + js/log4javascript_lite_uncompressed.js | 620 ++ js/log4javascript_production.js | 182 + js/log4javascript_production_uncompressed.js | 2238 +++++++ js/log4javascript_uncompressed.js | 5826 +++++++++++++++++ js/stubs/log4javascript.js | 23 + js/stubs/log4javascript_lite.js | 21 + js/stubs/log4javascript_lite_uncompressed.js | 102 + js/stubs/log4javascript_production.js | 22 + .../log4javascript_production_uncompressed.js | 253 + js/stubs/log4javascript_uncompressed.js | 341 + js/tests/log4javascript.js | 32 + js/tests/log4javascript_lite.js | 16 + js/tests/log4javascript_lite_uncompressed.js | 16 + js/tests/log4javascript_production.js | 28 + .../log4javascript_production_uncompressed.js | 728 ++ js/tests/log4javascript_uncompressed.js | 862 +++ license.txt | 201 + log4javascript.js | 266 + log4javascript_uncompressed.js | 5826 +++++++++++++++++ main.css | 300 + test/index.html | 15 + test/log4javascript.html | 16 + test/log4javascript_lite.html | 16 + test/log4javascript_lite_uncompressed.html | 16 + test/log4javascript_production.html | 16 + ...og4javascript_production_uncompressed.html | 16 + test/log4javascript_uncompressed.html | 16 + test/main.html | 16 + test/tests.css | 88 + test/xntest.js | 739 +++ 60 files changed, 30207 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 changelog.txt create mode 100644 console.html create mode 100644 console_uncompressed.html create mode 100644 demos/basic.html create mode 100644 demos/blank.html create mode 100644 demos/index.html create mode 100644 demos/inpage.html create mode 100644 demos/lite.html create mode 100644 demos/logger.php create mode 100644 demos/sessionlog.php create mode 100644 docs/backwardsincompatibilities.html create mode 100644 docs/distribution.html create mode 100644 docs/index.html create mode 100644 docs/lite.html create mode 100644 docs/manual.html create mode 100644 docs/manual_lite.html create mode 100644 docs/quickstart.html create mode 100644 docs/whatsnew.html create mode 100644 examples/demo.html create mode 100644 examples/example_manual.html create mode 100644 examples/example_quickstart_1.html create mode 100644 examples/myloggingservlet.do create mode 100644 js/console.html create mode 100644 js/console_uncompressed.html create mode 100644 js/liteconsole.html create mode 100644 js/liteconsole_uncompressed.html create mode 100644 js/log4javascript.js create mode 100644 js/log4javascript_lite.js create mode 100644 js/log4javascript_lite_uncompressed.js create mode 100644 js/log4javascript_production.js create mode 100644 js/log4javascript_production_uncompressed.js create mode 100644 js/log4javascript_uncompressed.js create mode 100644 js/stubs/log4javascript.js create mode 100644 js/stubs/log4javascript_lite.js create mode 100644 js/stubs/log4javascript_lite_uncompressed.js create mode 100644 js/stubs/log4javascript_production.js create mode 100644 js/stubs/log4javascript_production_uncompressed.js create mode 100644 js/stubs/log4javascript_uncompressed.js create mode 100644 js/tests/log4javascript.js create mode 100644 js/tests/log4javascript_lite.js create mode 100644 js/tests/log4javascript_lite_uncompressed.js create mode 100644 js/tests/log4javascript_production.js create mode 100644 js/tests/log4javascript_production_uncompressed.js create mode 100644 js/tests/log4javascript_uncompressed.js create mode 100644 license.txt create mode 100644 log4javascript.js create mode 100644 log4javascript_uncompressed.js create mode 100644 main.css create mode 100644 test/index.html create mode 100644 test/log4javascript.html create mode 100644 test/log4javascript_lite.html create mode 100644 test/log4javascript_lite_uncompressed.html create mode 100644 test/log4javascript_production.html create mode 100644 test/log4javascript_production_uncompressed.html create mode 100644 test/log4javascript_uncompressed.html create mode 100644 test/main.html create mode 100644 test/tests.css create mode 100644 test/xntest.js diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + 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/README.md b/README.md new file mode 100644 index 0000000..333d81f --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# log4javascript + +http://log4javascript.org + +npm/bower enabled copy of log4javascript + +current version: 1.4.13 diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..873ffa0 --- /dev/null +++ b/changelog.txt @@ -0,0 +1,403 @@ +log4javascript change log +------------------------- + +1.4.13 (23/5/2015) +- Fix for BrowserConsolerAppender regression in last version (feature request + 14) + +1.4.12 (14/5/2015) +- Fix for BrowserConsolerAppender error in IE <= 8 (issue 18) + +1.4.11 (19/2/2015) +- Fix for CORS requests in IE 10+ +- Remove message when sending remaining Ajax log messages when unloading + +1.4.10 (28/9/2014) +- AMD support added +- Fix for issue 16: getDefaultLogger() broken in production edition + +1.4.9 (12/5/2014) +- Fix for typo in BrowserConsoleAppender + +1.4.8 (18/4/2014) +- Added support for XMLHttpRequest's withCredentials to AjaxAppender + +1.4.7 (7/6/2013) +- Improved multiple browser console argument handling as per feature request #4 + +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/console.html b/console.html new file mode 100644 index 0000000..0859d04 --- /dev/null +++ b/console.html @@ -0,0 +1,263 @@ + + + +log4javascript + + + + + + + + + + +
+
+
+Filters: + + + + + + + +
+ +
+Options: + + + + + + + +
+
+
+
+
+
+ + +
+
+ + diff --git a/console_uncompressed.html b/console_uncompressed.html new file mode 100644 index 0000000..f18e8e7 --- /dev/null +++ b/console_uncompressed.html @@ -0,0 +1,2279 @@ + + + + log4javascript + + + + + + + + + + + +
+
+
+ Filters: + + + + + + + +
+ +
+ Options: + + + + + + + +
+
+
+
+
+
+ + +
+
+ + diff --git a/demos/basic.html b/demos/basic.html new file mode 100644 index 0000000..bd47935 --- /dev/null +++ b/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/demos/blank.html b/demos/blank.html new file mode 100644 index 0000000..52f69c0 --- /dev/null +++ b/demos/blank.html @@ -0,0 +1,4 @@ + +Blank page + + \ No newline at end of file diff --git a/demos/index.html b/demos/index.html new file mode 100644 index 0000000..abd43fe --- /dev/null +++ b/demos/index.html @@ -0,0 +1,49 @@ + + + + + log4javascript demos + + + + + + + +
+ +
+ +

log4javascript demos

+ +
+
+ +
+ + + diff --git a/demos/inpage.html b/demos/inpage.html new file mode 100644 index 0000000..da39246 --- /dev/null +++ b/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/demos/lite.html b/demos/lite.html new file mode 100644 index 0000000..f49990d --- /dev/null +++ b/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/demos/logger.php b/demos/logger.php new file mode 100644 index 0000000..68349d0 --- /dev/null +++ b/demos/logger.php @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/demos/sessionlog.php b/demos/sessionlog.php new file mode 100644 index 0000000..dd36e72 --- /dev/null +++ b/demos/sessionlog.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/docs/backwardsincompatibilities.html b/docs/backwardsincompatibilities.html new file mode 100644 index 0000000..c26d7ce --- /dev/null +++ b/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/docs/distribution.html b/docs/distribution.html new file mode 100644 index 0000000..65455b0 --- /dev/null +++ b/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/docs/index.html b/docs/index.html new file mode 100644 index 0000000..b16c474 --- /dev/null +++ b/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/docs/lite.html b/docs/lite.html new file mode 100644 index 0000000..65b8bf0 --- /dev/null +++ b/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/docs/manual.html b/docs/manual.html new file mode 100644 index 0000000..aebcb4c --- /dev/null +++ b/docs/manual.html @@ -0,0 +1,3217 @@ + + + + + log4javascript 1.4 manual + + + + + + + +
+ +
+ +

log4javascript 1.4 manual

+

Contents

+ +
+

Introduction

+

+ log4javascript currently exists to provide more flexible and configurable JavaScript logging + than that provided by browser developer tools. It works a very wide range of browsers. It was + originally written to ease the pain of JavaScript debugging in the days before browsers came + with advanced developer tools. +

+

+ 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. +

+

+ Top +

+
+
+

AMD

+

+ Since version 1.4.10, log4javascript comes with AMD support hence can be loaded by a script + loader such as RequireJS. +

+

+ The current version of JavaScript is designed only to run in a browser. If not using AMD, + log4javascript creates a single property of the global object (to all intents and purposes, a + global variable) called log4javascript. +

+

+ 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. In the standard edition, 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. +

    +

    + In the production edition, the default logger has no appenders. +

    +
    +
  • +
  • +
    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
    +
    Boolean getAdditivity()
    +
    + 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. +

+

+ 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.5, it is possible to override this behaviour so that logging data + is sent as the request payload rather than as a posted form variable. This is done + by setting the Content-Type header sent with each Ajax request + explicitly. For example, if using a + JsonLayout: +

    +
    ajaxApender.addHeader("Content-Type", "application/json");
    +
  • +
  • + 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. +

    +
  • +
  • + From version 1.4.8, AjaxAppender supports the sending of cookies in CORS requests via + the new withCredentials constructor parameter. +
  • +
+

Constructor

+
    +
  • +
    AjaxAppender
    +
    + AjaxAppender(String url[, Boolean withCredentials]) +
    +
    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. +
      +
    • +
    • + withCredentials +

      + Since: 1.4.8 +

      +
      + Specifies whether cookies should be sent with each 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 +

    +

    + From 1.4.5, specifying the Content-Type header using this method + will force logging data to be sent as the Ajax request payload rather than as a + posted form field. +

    +
    +
  • +
  • +
    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/docs/manual_lite.html b/docs/manual_lite.html new file mode 100644 index 0000000..019b18b --- /dev/null +++ b/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/docs/quickstart.html b/docs/quickstart.html new file mode 100644 index 0000000..6ed6dd8 --- /dev/null +++ b/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/docs/whatsnew.html b/docs/whatsnew.html new file mode 100644 index 0000000..bd6be87 --- /dev/null +++ b/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/examples/demo.html b/examples/demo.html new file mode 100644 index 0000000..d928f1c --- /dev/null +++ b/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/examples/example_manual.html b/examples/example_manual.html new file mode 100644 index 0000000..fa7d187 --- /dev/null +++ b/examples/example_manual.html @@ -0,0 +1,31 @@ + + + + + log4javascript example from manual + + + + + + + + +

log4javascript example from manual

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

log4javascript quick start example 1

+ + + + diff --git a/examples/myloggingservlet.do b/examples/myloggingservlet.do new file mode 100644 index 0000000..e69de29 diff --git a/js/console.html b/js/console.html new file mode 100644 index 0000000..0859d04 --- /dev/null +++ b/js/console.html @@ -0,0 +1,263 @@ + + + +log4javascript + + + + + + + + + + +
+
+
+Filters: + + + + + + + +
+ +
+Options: + + + + + + + +
+
+
+
+
+
+ + +
+
+ + diff --git a/js/console_uncompressed.html b/js/console_uncompressed.html new file mode 100644 index 0000000..f18e8e7 --- /dev/null +++ b/js/console_uncompressed.html @@ -0,0 +1,2279 @@ + + + + log4javascript + + + + + + + + + + + +
+
+
+ Filters: + + + + + + + +
+ +
+ Options: + + + + + + + +
+
+
+
+
+
+ + +
+
+ + diff --git a/js/liteconsole.html b/js/liteconsole.html new file mode 100644 index 0000000..7bf0314 --- /dev/null +++ b/js/liteconsole.html @@ -0,0 +1,41 @@ + + + +log4javascript + + + + + + + +
+Options: + + + +
+
+ + \ No newline at end of file diff --git a/js/liteconsole_uncompressed.html b/js/liteconsole_uncompressed.html new file mode 100644 index 0000000..8751d28 --- /dev/null +++ b/js/liteconsole_uncompressed.html @@ -0,0 +1,194 @@ + + + + log4javascript + + + + + + + + +
+ Options: + + + +
+
+ + \ No newline at end of file diff --git a/js/log4javascript.js b/js/log4javascript.js new file mode 100644 index 0000000..bad0f66 --- /dev/null +++ b/js/log4javascript.js @@ -0,0 +1,266 @@ +/** + * Copyright 2015 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(factory,root){if(typeof define=="function"&&define.amd){define(factory);}else if(typeof module!="undefined"&&typeof exports=="object"){module.exports=factory();}else{root.log4javascript=factory();}})(function(){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=0){arr.splice(index,1);return true;}else{return false;}} +function array_contains(arr,val){for(var i=0,len=arr.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=createDefaultLogger();} +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);},formatWithException:function(loggingEvent){var formatted=this.format(loggingEvent);if(loggingEvent.exception&&this.ignoresThrowable()){formatted+=loggingEvent.getThrowableStrRep();} +return formatted;},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.formatWithException=function(loggingEvent){var messages=loggingEvent.messages,ex=loggingEvent.exception;return ex?messages.concat([ex]):messages;};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,withCredentials){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())){formattedMessages.push(appender.getLayout().formatWithException(currentLoggingEvent));} +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){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);if(withCredentials&&withCredentialsSupported){xmlHttp.withCredentials=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();} +sendAllRemaining();};} +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;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().formatWithException(loggingEvent);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(){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,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=">";var i,len;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(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/js/log4javascript_lite_uncompressed.js b/js/log4javascript_lite_uncompressed.js new file mode 100644 index 0000000..83de1c0 --- /dev/null +++ b/js/log4javascript_lite_uncompressed.js @@ -0,0 +1,620 @@ +/** + * Copyright 2015 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.13"; + 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/js/log4javascript_production.js b/js/log4javascript_production.js new file mode 100644 index 0000000..4336cd2 --- /dev/null +++ b/js/log4javascript_production.js @@ -0,0 +1,182 @@ +/** + * Copyright 2015 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(factory,root){if(typeof define=="function"&&define.amd){define(factory);}else if(typeof module!="undefined"&&typeof exports=="object"){module.exports=factory();}else{root.log4javascript=factory();}})(function(){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=0){arr.splice(index,1);return true;}else{return false;}} +function array_contains(arr,val){for(var i=0,len=arr.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=createDefaultLogger();} +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);},formatWithException:function(loggingEvent){var formatted=this.format(loggingEvent);if(loggingEvent.exception&&this.ignoresThrowable()){formatted+=loggingEvent.getThrowableStrRep();} +return formatted;},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.formatWithException=function(loggingEvent){var messages=loggingEvent.messages,ex=loggingEvent.exception;return ex?messages.concat([ex]):messages;};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,withCredentials){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())){formattedMessages.push(appender.getLayout().formatWithException(currentLoggingEvent));} +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){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);if(withCredentials&&withCredentialsSupported){xmlHttp.withCredentials=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();} +sendAllRemaining();};} +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 createDefaultLogger(){return log4javascript.getLogger(defaultLoggerName);} +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();};}} +return log4javascript;},this); diff --git a/js/log4javascript_production_uncompressed.js b/js/log4javascript_production_uncompressed.js new file mode 100644 index 0000000..605b280 --- /dev/null +++ b/js/log4javascript_production_uncompressed.js @@ -0,0 +1,2238 @@ +/** + * Copyright 2015 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.13 + * Edition: log4javascript_production + * Build date: 23 May 2015 + * Website: http://log4javascript.org + */ + +(function(factory, root) { + if (typeof define == "function" && define.amd) { + // AMD. Register as an anonymous module. + define(factory); + } else if (typeof module != "undefined" && typeof exports == "object") { + // Node/CommonJS style + module.exports = factory(); + } else { + // No AMD or CommonJS support so we place log4javascript in (probably) the global variable + root.log4javascript = factory(); + } +})(function() { + // 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; + }; + } + + /* ---------------------------------------------------------------------- */ + + 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(); + + var log4javascript = new Log4JavaScript(); + log4javascript.version = "1.4.13"; + 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"); + }; + + 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); + }; + } + + /* ---------------------------------------------------------------------- */ + // 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 = createDefaultLogger(); + } + 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); + }, + + formatWithException: function(loggingEvent) { + var formatted = this.format(loggingEvent); + if (loggingEvent.exception && this.ignoresThrowable()) { + formatted += loggingEvent.getThrowableStrRep(); + } + return formatted; + }, + + 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.formatWithException = function(loggingEvent) { + var messages = loggingEvent.messages, ex = loggingEvent.exception; + return ex ? messages.concat([ex]) : messages; + }; + + 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, 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 xhrFactory = function() { return new XMLHttpRequest(); }; + var xmlHttpFactories = [ + xhrFactory, + function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, + function() { return new ActiveXObject("Microsoft.XMLHTTP"); } + ]; + + var withCredentialsSupported = false; + 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(); + withCredentialsSupported = (factory == xhrFactory && ("withCredentials" in xmlHttp)); + 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, withCredentials) { + 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())) { + formattedMessages.push( appender.getLayout().formatWithException(currentLoggingEvent) ); + } + // 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) { + 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); + // Add withCredentials to facilitate CORS requests with cookies + if (withCredentials && withCredentialsSupported) { + xmlHttp.withCredentials = 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(); + } + sendAllRemaining(); + }; + } + // 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; + + /* ---------------------------------------------------------------------- */ + + function createDefaultLogger() { + return log4javascript.getLogger(defaultLoggerName); + } + + /* ---------------------------------------------------------------------- */ + // 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(); + }; + } + } + + return log4javascript; +}, this); \ No newline at end of file diff --git a/js/log4javascript_uncompressed.js b/js/log4javascript_uncompressed.js new file mode 100644 index 0000000..1d78789 --- /dev/null +++ b/js/log4javascript_uncompressed.js @@ -0,0 +1,5826 @@ +/** + * Copyright 2015 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.13 + * Edition: log4javascript + * Build date: 23 May 2015 + * Website: http://log4javascript.org + */ + +(function(factory, root) { + if (typeof define == "function" && define.amd) { + // AMD. Register as an anonymous module. + define(factory); + } else if (typeof module != "undefined" && typeof exports == "object") { + // Node/CommonJS style + module.exports = factory(); + } else { + // No AMD or CommonJS support so we place log4javascript in (probably) the global variable + root.log4javascript = factory(); + } +})(function() { + // 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; + }; + } + + /* ---------------------------------------------------------------------- */ + + 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(); + + var log4javascript = new Log4JavaScript(); + log4javascript.version = "1.4.13"; + 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"); + }; + + 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); + }; + } + + /* ---------------------------------------------------------------------- */ + // 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 = createDefaultLogger(); + } + 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); + }, + + formatWithException: function(loggingEvent) { + var formatted = this.format(loggingEvent); + if (loggingEvent.exception && this.ignoresThrowable()) { + formatted += loggingEvent.getThrowableStrRep(); + } + return formatted; + }, + + 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.formatWithException = function(loggingEvent) { + var messages = loggingEvent.messages, ex = loggingEvent.exception; + return ex ? messages.concat([ex]) : messages; + }; + + 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, 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) { + alert( this.getLayout().formatWithException(loggingEvent) ); + }; + + 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(concatenate) { + var formattedMessage = appender.getLayout().formatWithException(loggingEvent); + return (typeof formattedMessage == "string") ? + (concatenate ? formattedMessage : [formattedMessage]) : + (concatenate ? formattedMessage.join(" ") : formattedMessage); + }; + + var console = window.console; + + if (console && console.log) { + // Log to Firebug or the browser console using specific logging + // methods or revert to console.log otherwise + var consoleMethodName; + + if (console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) { + consoleMethodName = "debug"; + } else if (console.info && Level.INFO.equals(loggingEvent.level)) { + consoleMethodName = "info"; + } else if (console.warn && Level.WARN.equals(loggingEvent.level)) { + consoleMethodName = "warn"; + } else if (console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) { + consoleMethodName = "error"; + } else { + consoleMethodName = "log"; + } + + if (typeof console[consoleMethodName].apply == "function") { + console[consoleMethodName].apply(console, getFormattedMessage(false)); + } else { + console[consoleMethodName]( getFormattedMessage(true) ); + } + } else if ((typeof opera != "undefined") && opera.postError) { // Opera + opera.postError( getFormattedMessage(true) ); + } + }; + + 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 xhrFactory = function() { return new XMLHttpRequest(); }; + var xmlHttpFactories = [ + xhrFactory, + function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, + function() { return new ActiveXObject("Microsoft.XMLHTTP"); } + ]; + + var withCredentialsSupported = false; + 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(); + withCredentialsSupported = (factory == xhrFactory && ("withCredentials" in xmlHttp)); + 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, withCredentials) { + 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())) { + formattedMessages.push( appender.getLayout().formatWithException(currentLoggingEvent) ); + } + // 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) { + 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); + // Add withCredentials to facilitate CORS requests with cookies + if (withCredentials && withCredentialsSupported) { + xmlHttp.withCredentials = 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(); + } + sendAllRemaining(); + }; + } + // 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; + + 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().formatWithException(loggingEvent); + 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() { + 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, + 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 = ">"; + var i, len; + + 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 (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 (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 (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 (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++) { + 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(); + })(); + + /* ---------------------------------------------------------------------- */ + + function createDefaultLogger() { + var logger = log4javascript.getLogger(defaultLoggerName); + var a = new log4javascript.PopUpAppender(); + logger.addAppender(a); + return logger; + } + + /* ---------------------------------------------------------------------- */ + // 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(); + }; + } + } + + return log4javascript; +}, this); \ No newline at end of file diff --git a/js/stubs/log4javascript.js b/js/stubs/log4javascript.js new file mode 100644 index 0000000..79a7cd1 --- /dev/null +++ b/js/stubs/log4javascript.js @@ -0,0 +1,23 @@ +/** + * Copyright 2015 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.13",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/js/stubs/log4javascript_lite.js b/js/stubs/log4javascript_lite.js new file mode 100644 index 0000000..86f70f1 --- /dev/null +++ b/js/stubs/log4javascript_lite.js @@ -0,0 +1,21 @@ +/** + * Copyright 2015 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.13",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/js/stubs/log4javascript_lite_uncompressed.js b/js/stubs/log4javascript_lite_uncompressed.js new file mode 100644 index 0000000..1691069 --- /dev/null +++ b/js/stubs/log4javascript_lite_uncompressed.js @@ -0,0 +1,102 @@ +/** + * Copyright 2015 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.13", + 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/js/stubs/log4javascript_production.js b/js/stubs/log4javascript_production.js new file mode 100644 index 0000000..e3d50cf --- /dev/null +++ b/js/stubs/log4javascript_production.js @@ -0,0 +1,22 @@ +/** + * Copyright 2015 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.13",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/js/stubs/log4javascript_production_uncompressed.js b/js/stubs/log4javascript_production_uncompressed.js new file mode 100644 index 0000000..dfff7e2 --- /dev/null +++ b/js/stubs/log4javascript_production_uncompressed.js @@ -0,0 +1,253 @@ +/** + * Copyright 2015 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.13", + 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/js/stubs/log4javascript_uncompressed.js b/js/stubs/log4javascript_uncompressed.js new file mode 100644 index 0000000..262a5ba --- /dev/null +++ b/js/stubs/log4javascript_uncompressed.js @@ -0,0 +1,341 @@ +/** + * Copyright 2015 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.13", + 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/js/tests/log4javascript.js b/js/tests/log4javascript.js new file mode 100644 index 0000000..bd297a1 --- /dev/null +++ b/js/tests/log4javascript.js @@ -0,0 +1,32 @@ +/** + * Copyright 2015 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/js/tests/log4javascript_lite.js b/js/tests/log4javascript_lite.js new file mode 100644 index 0000000..5dcf046 --- /dev/null +++ b/js/tests/log4javascript_lite.js @@ -0,0 +1,16 @@ +/** + * Copyright 2015 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/js/tests/log4javascript_lite_uncompressed.js b/js/tests/log4javascript_lite_uncompressed.js new file mode 100644 index 0000000..5dcf046 --- /dev/null +++ b/js/tests/log4javascript_lite_uncompressed.js @@ -0,0 +1,16 @@ +/** + * Copyright 2015 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/js/tests/log4javascript_production.js b/js/tests/log4javascript_production.js new file mode 100644 index 0000000..428bff1 --- /dev/null +++ b/js/tests/log4javascript_production.js @@ -0,0 +1,28 @@ +/** + * Copyright 2015 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/js/tests/log4javascript_production_uncompressed.js b/js/tests/log4javascript_production_uncompressed.js new file mode 100644 index 0000000..def9a48 --- /dev/null +++ b/js/tests/log4javascript_production_uncompressed.js @@ -0,0 +1,728 @@ +/** + * Copyright 2015 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/js/tests/log4javascript_uncompressed.js b/js/tests/log4javascript_uncompressed.js new file mode 100644 index 0000000..f206a71 --- /dev/null +++ b/js/tests/log4javascript_uncompressed.js @@ -0,0 +1,862 @@ +/** + * Copyright 2015 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/license.txt b/license.txt new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/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/log4javascript.js b/log4javascript.js new file mode 100644 index 0000000..bad0f66 --- /dev/null +++ b/log4javascript.js @@ -0,0 +1,266 @@ +/** + * Copyright 2015 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(factory,root){if(typeof define=="function"&&define.amd){define(factory);}else if(typeof module!="undefined"&&typeof exports=="object"){module.exports=factory();}else{root.log4javascript=factory();}})(function(){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=0){arr.splice(index,1);return true;}else{return false;}} +function array_contains(arr,val){for(var i=0,len=arr.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=createDefaultLogger();} +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);},formatWithException:function(loggingEvent){var formatted=this.format(loggingEvent);if(loggingEvent.exception&&this.ignoresThrowable()){formatted+=loggingEvent.getThrowableStrRep();} +return formatted;},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.formatWithException=function(loggingEvent){var messages=loggingEvent.messages,ex=loggingEvent.exception;return ex?messages.concat([ex]):messages;};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,withCredentials){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())){formattedMessages.push(appender.getLayout().formatWithException(currentLoggingEvent));} +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){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);if(withCredentials&&withCredentialsSupported){xmlHttp.withCredentials=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();} +sendAllRemaining();};} +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;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().formatWithException(loggingEvent);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(){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,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=">";var i,len;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(i=0,len=rootNode.childNodes.length;i + * Version: 1.4.13 + * Edition: log4javascript + * Build date: 23 May 2015 + * Website: http://log4javascript.org + */ + +(function(factory, root) { + if (typeof define == "function" && define.amd) { + // AMD. Register as an anonymous module. + define(factory); + } else if (typeof module != "undefined" && typeof exports == "object") { + // Node/CommonJS style + module.exports = factory(); + } else { + // No AMD or CommonJS support so we place log4javascript in (probably) the global variable + root.log4javascript = factory(); + } +})(function() { + // 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; + }; + } + + /* ---------------------------------------------------------------------- */ + + 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(); + + var log4javascript = new Log4JavaScript(); + log4javascript.version = "1.4.13"; + 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"); + }; + + 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); + }; + } + + /* ---------------------------------------------------------------------- */ + // 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 = createDefaultLogger(); + } + 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); + }, + + formatWithException: function(loggingEvent) { + var formatted = this.format(loggingEvent); + if (loggingEvent.exception && this.ignoresThrowable()) { + formatted += loggingEvent.getThrowableStrRep(); + } + return formatted; + }, + + 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.formatWithException = function(loggingEvent) { + var messages = loggingEvent.messages, ex = loggingEvent.exception; + return ex ? messages.concat([ex]) : messages; + }; + + 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, 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) { + alert( this.getLayout().formatWithException(loggingEvent) ); + }; + + 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(concatenate) { + var formattedMessage = appender.getLayout().formatWithException(loggingEvent); + return (typeof formattedMessage == "string") ? + (concatenate ? formattedMessage : [formattedMessage]) : + (concatenate ? formattedMessage.join(" ") : formattedMessage); + }; + + var console = window.console; + + if (console && console.log) { + // Log to Firebug or the browser console using specific logging + // methods or revert to console.log otherwise + var consoleMethodName; + + if (console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) { + consoleMethodName = "debug"; + } else if (console.info && Level.INFO.equals(loggingEvent.level)) { + consoleMethodName = "info"; + } else if (console.warn && Level.WARN.equals(loggingEvent.level)) { + consoleMethodName = "warn"; + } else if (console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) { + consoleMethodName = "error"; + } else { + consoleMethodName = "log"; + } + + if (typeof console[consoleMethodName].apply == "function") { + console[consoleMethodName].apply(console, getFormattedMessage(false)); + } else { + console[consoleMethodName]( getFormattedMessage(true) ); + } + } else if ((typeof opera != "undefined") && opera.postError) { // Opera + opera.postError( getFormattedMessage(true) ); + } + }; + + 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 xhrFactory = function() { return new XMLHttpRequest(); }; + var xmlHttpFactories = [ + xhrFactory, + function() { return new ActiveXObject("Msxml2.XMLHTTP"); }, + function() { return new ActiveXObject("Microsoft.XMLHTTP"); } + ]; + + var withCredentialsSupported = false; + 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(); + withCredentialsSupported = (factory == xhrFactory && ("withCredentials" in xmlHttp)); + 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, withCredentials) { + 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())) { + formattedMessages.push( appender.getLayout().formatWithException(currentLoggingEvent) ); + } + // 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) { + 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); + // Add withCredentials to facilitate CORS requests with cookies + if (withCredentials && withCredentialsSupported) { + xmlHttp.withCredentials = 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(); + } + sendAllRemaining(); + }; + } + // 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; + + 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().formatWithException(loggingEvent); + 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() { + 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, + 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 = ">"; + var i, len; + + 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 (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 (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 (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 (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++) { + 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(); + })(); + + /* ---------------------------------------------------------------------- */ + + function createDefaultLogger() { + var logger = log4javascript.getLogger(defaultLoggerName); + var a = new log4javascript.PopUpAppender(); + logger.addAppender(a); + return logger; + } + + /* ---------------------------------------------------------------------- */ + // 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(); + }; + } + } + + return log4javascript; +}, this); \ No newline at end of file diff --git a/main.css b/main.css new file mode 100644 index 0000000..5556209 --- /dev/null +++ b/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/test/index.html b/test/index.html new file mode 100644 index 0000000..f4574ff --- /dev/null +++ b/test/index.html @@ -0,0 +1,15 @@ + + + + + log4javascript - Tests + + + + + diff --git a/test/log4javascript.html b/test/log4javascript.html new file mode 100644 index 0000000..a82038a --- /dev/null +++ b/test/log4javascript.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript - Tests + + + + + + + +
+
+ + diff --git a/test/log4javascript_lite.html b/test/log4javascript_lite.html new file mode 100644 index 0000000..21fe67d --- /dev/null +++ b/test/log4javascript_lite.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_lite - Tests + + + + + + + +
+
+ + diff --git a/test/log4javascript_lite_uncompressed.html b/test/log4javascript_lite_uncompressed.html new file mode 100644 index 0000000..d6f48a1 --- /dev/null +++ b/test/log4javascript_lite_uncompressed.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_lite_uncompressed - Tests + + + + + + + +
+
+ + diff --git a/test/log4javascript_production.html b/test/log4javascript_production.html new file mode 100644 index 0000000..60878a0 --- /dev/null +++ b/test/log4javascript_production.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_production - Tests + + + + + + + +
+
+ + diff --git a/test/log4javascript_production_uncompressed.html b/test/log4javascript_production_uncompressed.html new file mode 100644 index 0000000..efd68d9 --- /dev/null +++ b/test/log4javascript_production_uncompressed.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_production_uncompressed - Tests + + + + + + + +
+
+ + diff --git a/test/log4javascript_uncompressed.html b/test/log4javascript_uncompressed.html new file mode 100644 index 0000000..e1fab8c --- /dev/null +++ b/test/log4javascript_uncompressed.html @@ -0,0 +1,16 @@ + + + + + log4javascript - log4javascript_uncompressed - Tests + + + + + + + +
+
+ + diff --git a/test/main.html b/test/main.html new file mode 100644 index 0000000..4087263 --- /dev/null +++ b/test/main.html @@ -0,0 +1,16 @@ + + + + + log4javascript - %%build:edition%% - Tests + + + + + + + +
+
+ + diff --git a/test/tests.css b/test/tests.css new file mode 100644 index 0000000..97b04ab --- /dev/null +++ b/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/test/xntest.js b/test/xntest.js new file mode 100644 index 0000000..1b8f475 --- /dev/null +++ b/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