JavaScript Logging – A Record Aside

When you spend a lot time working with JavaScript, there’ll ultimately come a day when you must know the worth of a variable (or an object’s subject) because the execution of the script progresses, or why a script terminates unexpectedly. In easy scripts, you’ll be able to accomplish this with JavaScript’s alert operate, which instructs the browser to create a dialog field with the argument set because the field’s caption. The message will be something that helps you perceive your script’s operation.

Article Continues Beneath

For instance, the assertion:

alert(
"Node #" + i + "'s class is:" + nodes[ i ].getClass()
);

may produce one thing like the next when executed:

An example of using JavaScript's alert() function to display information about an executing JavaScript

When alert() is used just a few occasions all through a script’s execution, it’s simple for the writer to maintain monitor of precisely what’s being displayed within the dialog bins. Nevertheless, as soon as nested loops and different superior methods equivalent to recursion are launched to the script, utilizing alert() to debug your script can shortly degrade into losing your time clicking an “OK” button as shortly as doable to dismiss pointless dialog bins whereas attempting to find the one field that you simply’re occupied with.

A number of browsers embody instruments that may support in debugging your code, together with these from Opera and the Mozilla mission. The Mozilla browsers and up to date variations of Opera embody JavaScript consoles that help script authors find the error that brought on a script to terminate unexpectedly:

Firefox's JavaScript console

To its credit score, Web Explorer on Home windows may notify the viewer of JavaScript errors (though its messages are usually just a little cryptic when in comparison with Mozilla’s and Opera’s consoles).

Firefox’s older brother, Mozilla, additionally features a full-blown JavaScript debugger, dubbed Venkman, to help scripters find out precisely what their code is doing. Nevertheless, the artwork of setting breakpoints and stepping by your code function-by-function and instruction-by-instruction is extra tedious and sophisticated than many would love it to be. Though there are a number of wonderful tutorials that cowl how one can use Venkman, turning into accustomed to the best way a debugger works and how one can use one successfully requires a big time dedication.

Mozilla's Venkman utility

The complexity and overhead of utilizing a debugger isn’t distinctive to Venkman; almost each IDE (Built-in Improvement Atmosphere) contains some form of debugger, however these are sometimes ignored by builders as a result of quantity of effort that should be expended to really use the debugger and step by their code.

Nevertheless there’s, actually, an even bigger drawback in utilizing the JavaScript consoles and debuggers: they don’t reveal why a script operates as anticipated in Browser A, however crashes and burns in Browser B, or vice-versa. The debugger/console will solely let you understand what’s occurring in Browser A.

One other, easier debugging technique has come into style lately, though the precept behind it should be as outdated because the artwork of programming itself. This technique is named logging, and it really works by echoing as a lot info to the display as is important to learn how your code and information constructions are behaving. The echoed info can embody the whole lot from descriptive statements which might be used to let the programmer know what is occurring within the script to the worth of a variable or the sector of an object; it may be any info that may inform the writer of what’s occurring within the code.

The truth is, by utilizing JavaScript’s alert operate to show snapshots of our script because it executes, we’re primarily utilizing a very fundamental logging technique; as an alternative of displaying the knowledge in a terminal window or appending it to a file on the laborious drive, we’re presenting it on to the viewer. But utilizing alert() proves to be extra of a hinderance than a profit when used typically as a result of quantity of mouse clicks which might be wanted to dismiss the dialogs. What’s wanted is a correct logging mechanism for JavaScript and the browsers that it runs in.

The idea of logging was popularized by Apache’s Log4J bundle for Java, and its important concepts have since been ported to different languages, together with however not restricted to:

This text will introduce fvlogger (obtainable for obtain right here), a library that brings easy logging performance to JavaScript and the browser.

Logging in JavaScript with fvlogger#section4

Whereas logging packages within the languages listed above present a fancy class/bundle construction constructed on high of inheritance and different object-oriented ideas, fvlogger borrows ideas from Log4J and its cousins, however eschews their complexity by offering a easy API and offloading the heavy lifting onto the DOM.

The library defines 4 fundamental features (and supplies just a few others that may be thought-about optionally available), just a few flags that may be set to outline its behaviour, and a number of other CSS lessons that can be utilized to manipulate how the log will seem. It requires only one particular component to be positioned within the doc, and together with fvlogger in your pages is as simple as including the next two traces to the head of your paperwork:

<script sort="textual content/javascript"
src="https://alistapart.com/fvlogger/logger.js" />
<hyperlink rel="stylesheet" sort="textual content/css"
href="https://alistapart.com/fvlogger/logger.css" />

Basically, all fvlogger does is append new components to a particular component within the doc. These new components include the logging messages that may help you in debugging your script(s). The 4 features used to create the log messages are: debug(msg), data(msg), warn(msg), and error(msg). Every operate expects a single string that can be appended to the doc.

Logging ranges and lessons#section5

One of many basic concepts behind logging is the flexibility to set the granularity of what info can be logged: Ought to solely errors be displayed? What about info to point which branches and/or loops are being executed?

Whereas it’s doable to get away with solely utilizing one operate to log messages to the browser, by utilizing all 4 it is possible for you to to filter your log messages primarily based on their significance; debug messages are the least essential and may typically be dismissed, whereas error messages are a very powerful and may all the time be considered.

By default, all messages can be appended to the component whose id is “fvlogger” (though this will simply be modified). The log messages are wrapped in <p> components—which, just like the id, will be modified—and have a single class utilized to them that corresponds to the logging operate that was used to create it. Debug messages could have the debug class utilized to them, error messages could have the error class utilized to them, et cetera. These lessons help you fashion your log messages any means you want utilizing CSS; the mission features a default stylesheet and supporting pictures to get you began however you might be, after all, free to vary its look to your coronary heart’s content material.

The comfort features talked about above help you shortly filter which log messages are displayed within the browser:

  • showAll() reveals all log messages,
  • showDebug() reveals all debug messages, and hides all others,
  • showInfo() reveals all data messages, and hides all others,
  • showWarn() reveals all warn messages, and hides all others,
  • showError() reveals all error messages, and hides all others,
  • eraseLog() will erase all messages from the log.

(The filter strategies work by merely setting the show fashion of a log message to both be seen or invisible primarily based on the message’s class.)

Getting began#section6

That being stated, let’s check out the steps required to arrange fvlogger. The next snippet of XHTML defines the weather that can be used to work together with fvlogger, though we may get a means with only a easy <div> if we actually needed to. You’ll discover that not one of the log messages within the <div> under are proven; it is because the messages are created dynamically by fvlogger and apppended to the doc after it was loaded into the browser.

<div id="fvlogger">
  <dl>
    <dt>fvlogger</dt>
    <dd class="all">
      <a href="#fvlogger" onclick="showAll();" 
        title="present all">all</a>
    </dd>
    <dd class="debug">
      <a href="#fvlogger" onclick="showDebug();" 
        title="present debug">debug</a>
    </dd>
    <dd class="data">
      <a href="#fvlogger" onclick="showInfo();" 
        title="present data">data</a>
    </dd>
    <dd class="warn">
      <a href="#fvlogger" onclick="showWarn();" 
        title="present warnings">warn</a>
    </dd>
    <dd class="error">
      <a href="#fvlogger" onclick="showError();" 
        title="present errors">error</a>
    </dd>
    <dd class="deadly">
      <a href="#fvlogger" onclick="showFatal();" 
        title="present fatals">deadly</a>
    </dd>
    <dd>
      <a href="#fvlogger" onclick="eraseLog(true);" 
        title="erase">erase</a>
      </dd>
  </dl>
</div>

Nothing too superior, actually. Though the markup required to stand up and working may be as minimal as…

<div id="fvlogger" />

…in the event you don’t require all of the bells and whistles. As for the log messages themselves, the next code snippet illustrates how one can create log messages and descriptions which degree of severity needs to be used to your log messages.

debug('Scatter debug messages all through your
  code to offer a high-level overview of
  what your code is doing, equivalent to which
  operate is presently in scope and the
  values of loop counters.');

data('Info messages are the meat and
  potatoes of logging messages; sprinkle them
  round to disclose extra detailed info
  about your script's execution, such because the
  values of variables and performance/technique
  return values.');

warn('Warning messages are used to point
  doubtlessly hazardous conditions, equivalent to
  lacking operate arguments...');

error('Whereas error messages are used to
  point out that one thing unhealthy is about to
  occur; observe that these sorts of errors
  are thought-about to be run-time errors,
  that are a unique sort of beast from
  the parse errors talked about under.');

…and the next is how they seem after having the default fvlogger kinds utilized:

debug(‘Scatter debug messages all through your code to offer a high-level overview of what your code is doing, equivalent to which operate is presently in scope and the values of loop counters.’);

data(‘Info messages are the meat and potatoes of logging messages; sprinkle them round to disclose extra detailed details about your script’s execution, such because the values of variables and performance/technique return values.’);

warn(‘Warning messages are used to point doubtlessly hazardous conditions, equivalent to lacking operate arguments…’);

error(‘Whereas error messages are used to point that one thing unhealthy is about to occur; observe that these sorts of errors are thought-about to be run-time errors, that are a unique sort of beast from the parse errors talked about under.’);

Notice: For these builders who’re testing their scripts in IE or one of many many Mozilla-based browsers, JavaScript parse errors may also be appended to the log as deadly errors. This feat is achieved by merely overriding the <physique>’s onerror handler so as to add one other message to the log.

Now you’re most likely asking what that different gunk within the log is. These are the log messages generated by code included later within the article. Which brings me to the second half of the article. Now that you simply’re accustomed to the speculation and apply behind creating with fvlogger, I’ll stroll by a real-life instance—one which I got here throughout within the improvement of the bundle—of the best way logging can support in debugging your scripts.

Creating with fvlogger#section7

Included within the kinds of this web page is the next rule:

.labrat { font-weight: daring; colour: pink; }

So, theoretically, any components within the doc whose class is “labrat”—whether or not they be part of the doc when the web page is loaded into the browser or appended sooner or later thereafter—ought to seem in bold-faced pink sort, together with the next two examples.

That is the primary instance.

That is the second instance.

Straightforward-peasy, proper? Nearly, however not fairly.

The issue#section8

The examples proven above are included within the doc (ie: they have been created when authoring the remainder of this web page), so it ought to come as no shock that they seem as they need to in each browser that helps CSS. Nevertheless, with the cross-browser assist of the DOM, dynamically creating components and appending them to the doc has turn out to be commonplace—even required—by many web sites and functions, this text being certainly one of them. Let’s make it possible for we are able to apply lessons to those dynamic components as effectively.

The code to perform our activity ought to look one thing like the next:

var p = doc.createElement("p");
p.appendChild(
  doc.createTextNode(
    "This paragraph (#3) is created dynamically and seems
    with the right bold-faced pink sort in nearly all
    fashionable browsers apart from Web Explorer, the place the
    paragraph is created and the textual content is appended, however the
    kinds aren't correctly utilized. Why?")
);
p.setAttribute("class", "labrat");
doc.appendChild(p);

The above snippet of code works in all fashionable browser households—WebKit, Gecko, and Opera—besides for IE. With Web Explorer, the next paragraph could have the identical font as all common paragraphs, regardless that it has the “labrat” class utilized (go forward and cargo this web page in IE and one other browser and examine the variations).
var bottle = doc.getElementById(“bottle”);
var p = doc.createElement(“p”);
p.setAttribute(“class”, “labrat”);
p.appendChild(
doc.createTextNode(“This paragraph (#3) is created dynamically and seems with the right bold-faced pink sort in nearly all fashionable browsers apart from Web Explorer, the place the paragraph is created and the textual content is appended, however the kinds aren’t correctly utilized. Why?”));
bottle.appendChild(p);

After just a little investigating, the trigger is IE’s implementation of the setAttribute and createElement strategies. Check out the next code (which comprises the logging statements proven in daring) which is used to create instance paragraph #4…

// create and append the paragraph to the doc
var p2 = doc.createElement(“p”);
p2.appendChild(
doc.createTextNode(
“That is instance paragraph #4.”)
);
p2.setAttribute(“class”, “labrat”);
var bottle = doc.getElementById(“bottle”);
bottle.appendChild(p2);

// use fvlogger to log all attributes to the doc
var i = 0; var attrs = p.attributes;
for (i = 0; i < attrs.size; i++) {
debug(“attribute #” + i + “: ” +
attrs[i].title + “=” + attrs[i].worth);
}
// show a abstract of attrs size
if (i == 0) { error(“new component has no attributes”); }
else { data(“p has ” + i + ” attribute(s)”); }
// the code is mirrored under for show functions

// create and append the paragraph to the doc
var p2 = doc.createElement("p");
p2.appendChild(
  doc.createTextNode(
    "That is instance paragraph #4.")
);
p2.setAttribute("class", "labrat");
var bottle = doc.getElementById("bottle");
bottle.appendChild(p2);

// use fvlogger to log all attributes to the doc
var i = 0; var attrs = p2.attributes;
for (i = 0; i < attrs.size; i++) {
  debug("attribute #" + i + ": " +
    attrs[i].title + "=" + attrs[i].worth);
}

// show a abstract of attrs size
if (i == 0) {
  error("new component has no attributes");
} else {
  data("p has " + i + " attribute(s)");
}

…and the log message that it generates, proven beforehand within the web page. In Opera, Mozilla, and WebKit-based browsers, there are solely two logging statements produced by this snippet of code: one debug assertion that reveals the category of the component that we created, and the opposite indicating the variety of attributes belonging to the component. As a result of we’re solely assigning one attribute to the component (its class), the output is precisely what we might anticipate it to be: the paragraph has one attribute named—not surprisingly—“labrat.”

Nevertheless, Web Explorer is “particular” in the best way that it creates components. As an alternative of getting zero attributes (as one would anticipate) instantly after creation, new components inherit all attributes and their default values as outlined in Web Explorer’s default DTD. So as an alternative of our new component having a single attribute after setting its class, it really has 84. Zoinks!

However what’s equally as odd is that when making an attempt to set the class of a brand new component by its setAttribute() technique, IE will really create one other attribute node as an alternative of changing the worth of the present class attribute. Thus, we find yourself with two class attributes as an alternative of 1 in IE (attributes #3 and #83 within the log statements proven above).

The answer#section9

Fortunately, there’s, a comparatively easy repair for IE’s drawback: as an alternative of merely setting the worth of an attribute primarily based on its title, we are able to loop by all present attributes till we discover the one which we’re on the lookout for after which set its worth primarily based on its numeric index within the node’s attributes array. The next snippet of JavaScript will get the job accomplished:

var className="labrat";
var p3 = doc.createElement('p');
p3.appendChild(
  doc.createTextNode(
    "And guess what. It really works!" 
  )
);

// if the node's class already exists
// then substitute its worth
if (p3.getAttributeNode("class")) {
  for (var i = 0; i < p3.attributes.size; i++) {
    var attrName = p3.attributes[i].title.toUpperCase();
    if (attrName == 'CLASS') {
      p3.attributes[i].worth = className;
    }
  }
// in any other case create a brand new attribute
} else {
  p3.setAttribute("class", className);
}
    

var className=”labrat”;
var p3 = doc.createElement(‘p’);
p3.appendChild(
doc.createTextNode(
“And guess what. It really works!”
)
);
// if the node’s class already exists
// then substitute its worth
if (p3.getAttributeNode(“class”)) {
for (var i = 0; i < p3.attributes.size; i++) {
var attrName = p3.attributes[i].title.toUpperCase();
if (attrName == ‘CLASS’) {
p3.attributes[i].worth = className;
}
}
// in any other case create a brand new attribute
} else {
p3.setAttribute(“class”, className);
}
var bottle = doc.getElementById(“bottle”);
bottle.appendChild(p3);

The ethical of the story#section10

On this article we noticed how logging unveiled certainly one of Web Explorer’s many quirks. However extra importantly, we noticed how logging supplies a simple strategy to create clear code—you, the writer, can keep on high of your information constructions as they go by every line of your code and know precisely what is occurring contained in the black field of an online browser’s JavaScript engine (or, equally, your Dashboard widget). This transparency can show invaluable since your code is prone to run in three or extra totally different browsers that, whereas related, are in no way equivalent.

Leave a Comment