Menu

Image src adapter?

Help
Anonymous
2012-12-20
2013-04-29
  • Anonymous

    Anonymous - 2012-12-20

    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.

     
  • Tim Down

    Tim Down - 2012-12-20

    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.

     
  • Anonymous

    Anonymous - 2012-12-28

    Here is my extension to the library, which I have placed after AlertAppender.

    Usage:

    var appender = new log4javascript.ImageSrcAppender("http://www.example.com/log.png?message=");
    

    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:

    /* ---------------------------------------------------------------------- */
        // 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
         */
        function ImageSrcAppender(url) {
            // IE has a 2,048 character GET URL limit while other browsers are much higher (16kB+)
            var URL_MAX_LENGTH_IE = 2048;
            // If a message has to be broken up, include a prefix to indicate the order. The placeholders POS and MAX will by
            // dynamically replaced with current values
            var PREFIX_TEXT = "Part POS/MAX: ";
            // TRUE if a URL is provided on initialisation
            var isSupported = true;
    
            if (!url) {
                handleError("ImageSrcAppender: URL must be specified in constructor");
                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 "Part X/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.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.