We need to push certain log messages (e.g. ERROR, FATAL) to an external server which does not reside on the same domain and therefore faces cross-domain issues.
I'll try the AJAX appender, but I believe the messages won't be received. A workaround is to "download" a 1x1 image and attach the message to the request (e.g. http://example.com/image.gif?message=foo).
My questions:
1. Any plans for an image src appender? I can try and code one up, but then I'll be stuck on a branch of the library…
2. Is there any callback functionality? (e.g. whenever an ERROR log occurs, call myFunction that does the image src manually)
Cheers,
Daniel.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Indeed, the AjaxAppender uses plain old XMLHttpRequest and won't work cross-domain. Another possibility would be to write a simple proxying script on the server the page is served from to proxy requests to the logging server. Failing that, the image idea could work for small logging messages but you could easily run into limitations in the length of GET request URLs for larger messages, so I'm not too keen on that idea in general. Finally, in recent browsers there is CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). In the next version of log4javascript I may abstract the transport layer of the AjaxAppender to allow different mechanisms to be plugged in.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2012-12-26
Thanks for the response.
1. Unfortunately we don't have control of the server where the page is executed (distributed code) so can't implement a reverse proxy
2. The maximum IE GET request would be 2,048 characters inclusive of the URL
3. Non-IE can use up to 16kB, which is the IIS default (everything else is 100kB and higher). This limit could be configured.
4. Longer messages would need to be trimmed, which may be acceptable (as opposed to no remote logging)
5. CORS isn't ready yet because of a lack of support for IE7
If you don't mind, I will have a go at extending the framework to support img - which I would be happy to contribute back.
* For messages over 2,048 characters in IE, it will break up the message and send multiple pieces with the prefix "Part 1/3:"
* Non-IE browsers allow around 100kB+ which are not broken up
* Sent messages are encoded
* To avoid IE browsers displaying a broken image it's best for the external logging page to actually return a 1x1 image
* Tested working in IE7, FF and Chrome
* Heavily commented code
Code:
/* ---------------------------------------------------------------------- *///ImageSrcAppender/** * Appender that dynamically creates an empty image on the page while sending the log message as a parameter. Useful * for pushing messages to an external server while bypassing cross-domain issues associated with normal AJAX. * * @param url URL of the external server and param (e.g. "http://example.com?message=") * @constructor */functionImageSrcAppender(url){//IEhasa2,048characterGETURLlimitwhileotherbrowsersaremuchhigher(16kB+)varURL_MAX_LENGTH_IE=2048;//Ifamessagehastobebrokenup,includeaprefixtoindicatetheorder.TheplaceholdersPOSandMAXwillby//dynamicallyreplacedwithcurrentvaluesvarPREFIX_TEXT="PartPOS/MAX:"; // TRUE if a URL is provided on initialisation var isSupported = true; if (!url) { handleError("ImageSrcAppender:URLmustbespecifiedinconstructor"); isSupported = false; } /** * Returns TRUE if browser is Internet Explorer. * * @return Boolean TRUE if browser is IE */ function isIe() { if (navigator.userAgent.indexOf("MSIE") === -1) { return false; } return true; }; /** * Splits input text into parts based on a provided length. Used to send multiple messages overcoming the * IE limit of 2,048 characters. * * @param input String to be split up * @param length Length of each chunk * @return Array Array of split strings */ function splitStringByLength(input, length) { // Need to use the RegExp object when injecting a variable into the regular expression (IE anyway) // Regular expression splits a string every N characters: .{1,N} var re = new RegExp(".{1," + length + "}", "g"); // Return an array of strings return input.match(re); }; /** * Generates the image SRC URL based on the inital URL, if the message is split, and the message. * * @param message Log message * @param pos If split, position in the array (default is 1) * @param size If split, size of array (default is 1) * @return String Image SRC URL */ function buildUrl(message, pos, size) { // If the message is being split up for IE if (size > 1) { // Replace placeholders with dynamic values var prefix = PREFIX_TEXT.replace("POS", pos).replace("MAX", size); message = prefix + message; } return url + message; } /** * Encodes the message and returns in an array -- split into smaller pieces if browser (e.g. IE) limits * the URL length. * * @param message Message to encode and put in array * @return Array Array of strings depending on browser limits */ function generateMessageArray(message) { // Encode the URL for sending var message = encodeURIComponent(message); // Place message in array, even if the only element var messages = [message]; // Check if IE and we need to split the message if (isIe()) { // Max length less the URL path and "PartX/X" prefix var maxUrlGetLength = URL_MAX_LENGTH_IE - url.length - PREFIX_TEXT.length; messages = splitStringByLength(message, maxUrlGetLength); } return messages; } /** * For each message in the array, dynamically create an image (pointing to a remote server) and append to the page. * * @param messages Array of messages to send */ function sendMessages(messages) { var numMessages = messages.length; // Iterate over each message for (var i = 0; i < numMessages; i++) { // Dynamically create an image var img = document.createElement("img"); // Point to the logging server with the data img.setAttribute('src', buildUrl(messages[i], i + 1, numMessages)); // Set the 1 pixel to be invisible img.setAttribute('height', '1px'); img.setAttribute('width', '1px'); // Dynamically append to the DOM, which will make a request to an external server document.body.appendChild(img); } } /** * Format and send the log message to an external server as an image SRC location with * the message as a paramter. * * @param loggingEvent */ this.append = function(loggingEvent) { if (isSupported) { var formattedMessage = this.getLayout().format(loggingEvent); if (this.getLayout().ignoresThrowable()) { formattedMessage += loggingEvent.getThrowableStrRep(); } var messages = generateMessageArray(formattedMessage); sendMessages(messages); } }; } ImageSrcAppender.prototype = new Appender(); ImageSrcAppender.prototype.layout = new SimpleLayout(); ImageSrcAppender.prototype.toString = function() { return "ImageSrcAppender";};log4javascript.ImageSrcAppender=ImageSrcAppender;/* ---------------------------------------------------------------------- */
Cheers.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi,
Good job on the library!
We need to push certain log messages (e.g. ERROR, FATAL) to an external server which does not reside on the same domain and therefore faces cross-domain issues.
I'll try the AJAX appender, but I believe the messages won't be received. A workaround is to "download" a 1x1 image and attach the message to the request (e.g. http://example.com/image.gif?message=foo).
My questions:
1. Any plans for an image src appender? I can try and code one up, but then I'll be stuck on a branch of the library…
2. Is there any callback functionality? (e.g. whenever an ERROR log occurs, call myFunction that does the image src manually)
Cheers,
Daniel.
Indeed, the AjaxAppender uses plain old XMLHttpRequest and won't work cross-domain. Another possibility would be to write a simple proxying script on the server the page is served from to proxy requests to the logging server. Failing that, the image idea could work for small logging messages but you could easily run into limitations in the length of GET request URLs for larger messages, so I'm not too keen on that idea in general. Finally, in recent browsers there is CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). In the next version of log4javascript I may abstract the transport layer of the AjaxAppender to allow different mechanisms to be plugged in.
Thanks for the response.
1. Unfortunately we don't have control of the server where the page is executed (distributed code) so can't implement a reverse proxy
2. The maximum IE GET request would be 2,048 characters inclusive of the URL
3. Non-IE can use up to 16kB, which is the IIS default (everything else is 100kB and higher). This limit could be configured.
4. Longer messages would need to be trimmed, which may be acceptable (as opposed to no remote logging)
5. CORS isn't ready yet because of a lack of support for IE7
If you don't mind, I will have a go at extending the framework to support img - which I would be happy to contribute back.
Cheers.
====================================================
Appreciation of a 2,048 character GET request:
http://www.example.com/log.gif?m=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Here is my extension to the library, which I have placed after AlertAppender.
Usage:
Comments:
* For messages over 2,048 characters in IE, it will break up the message and send multiple pieces with the prefix "Part 1/3:"
* Non-IE browsers allow around 100kB+ which are not broken up
* Sent messages are encoded
* To avoid IE browsers displaying a broken image it's best for the external logging page to actually return a 1x1 image
* Tested working in IE7, FF and Chrome
* Heavily commented code
Code:
Cheers.