Documentation Menu

Logger

Configures a logger.

Definition

<configuration> 
    <jsnlog>
        <logger 
            name="string" 
            level="number|TRACE|DEBUG|INFO|WARN|ERROR|FATAL|OFF|ALL"
            userAgentRegex="regular expression"
            ipRegex="regular expression"
            disallow="regular expression" 
            appenders="Appender Name(s)" >
            <onceOnly regex="regular expression" />
        </logger> 
    </jsnlog>
</configuration> 
public class Logger
{
    public string level { get; set; }
    public string ipRegex { get; set; }
    public string userAgentRegex { get; set; }
    public string disallow { get; set; }
    public string appenders { get; set; }
    public string name { get; set; }
    public List<OnceOnlyOptions> onceOnlies { get; set; }
}
public class OnceOnlyOptions { public string regex { get; set; } }

Remarks

This element can have the following attributes:

Attribute Default Description
name
optional
(empty) Name of the logger you want to configure. To configure the root logger, simply omit the name attribute.

In your server side logs, the root logger is called ClientRoot.

level
optional
(inherited from parent logger) Numeric or named severity. Only log messages with a severity equal or higher than this can be sent to the server.
userAgentRegex
optional
(inherited from parent logger) If not empty, log messages only get processed if this regular expression matches the user agent string of the browser.
ipRegex
optional
(inherited from parent logger) If not empty, log messages only get processed if this regular expression matches the IP address(es) from which the page was loaded (details below).
disallow
optional
(inherited from parent logger) If not empty, log messages are suppressed if they match this regular expression. If an object is being logged, it is converted to a JSON string, which is then matched.
appenders
optional
(inherited from parent logger) One or more appenders for the logger to send its log messages to. See the examples.
onceOnly
optional
(inherited from parent logger) One or more regular expressions. When a message matches a regular expression, then any subsequent messages matching that same regular expression will be suppressed. See the remarks and examples.

Logger names and option inheritance

JavaScript loggers not only get their options through this element, but also through inheritance. This is based on the name of each logger.

Assume that you have a method "method1" in a namespace "namespace1". Then it would make sense to use a naming scheme for your loggers like this: "namespace1.method1.logger1", "namespace1.method1.logger2", etc. This way, there are no name clashes and it makes keeping track of your loggers easy.

Just as a namespace may contain methods, and a method may contain JavaScript loggers, so you can think of these logger names as making up a hierarchy:

  • The parent of "namespace1.method1.logger1" is "namespace1.method1";
  • The parent of "namespace1.method1" is "namespace1";
  • The parent of "namespace1" is the root logger (the logger without a name).

You're not limited to just 3 levels, you can have as many as want.

If you don't set an option using this element, the logger inherits that option from its parent. If you do not use this element at all, every JavaScript logger will have the same options as the root logger.

Root logger and default appender

When the library loads, it creates the root logger. It also creates a default AjaxAppender for use by the root logger.

Because every logger inherits from the root logger (unless you override this with this element), you can start logging right away without having to create an appender.

The root logger is created with these options:

Option Default Value
level DEBUG
userAgentRegex (empty)
ipRegex (empty)
disallow (empty)
appenders (default appender)

Note that because the default level for root logger is DEBUG, by default only log messages with severity DEBUG or higher get processed.

You can change the options used with the root logger in the same way as any other logger, using this element. See the examples below.

The default appender is created with these options (description of options):

Option Default Value
level TRACE
userAgentRegex (empty)
ipRegex (empty)
disallow (empty)
storeInBufferLevel ALL
sendWithBufferLevel OFF
bufferSize 0
batchSize 1
batchTimeout (no timeout)
url defaultAjaxUrl

ipRegex

The ipRegex feature lets you switch loggers and appenders on or off depending on the IP address from which the page was loaded. For example, you only want to receive log messages from a live site, but not from a staging site.

For this to work, jsnlog.js on the client has to know that IP address. Options to make that happen:

  1. On the server, set insertJsnlogInHtmlResponses to true in the JSNLog server side configuration. JSNLog will insert JavaScript in the page html going to the browser that sets the IP address.
  2. On the client, call JL.setOptions and pass in the IP address via the clientIP field.

How JSNLog works out the IP address of the page request

When JSNLog works out the IP address where the page request was received (that is, the IP address of the user's browser), this may not be as simple as looking at the source address in the request.

If your web server sits behind a load balancer, the source of the final request to the web server is not the browser, but the load balancer. The request may also have been passed on through intermediate proxies, causing the same issue.

The most common (but non-standard) solution to this is that proxies and load balancers (such as AWS' Elastic Load Balancer) send an X-Forwarded-For request header with the IP addresses of the browser and any proxies that the request passed through, except for the final source address. JSNLog uses this request header to work out the IP address of the actual browser and the proxies and/or load balancer that the request passed through.

In that case, the "IP address" is actually a string with a comma separated list of IP addresses. First is the IP address of the browser itself, then intermediate proxies (in the order in which they were reached) and then the IP address of the load balancer if there is one:

Browser IP address, Proxy 1, ..., Proxy N [, Load Balancer]

Suppressing duplicate messages with onceOnly

You may have JavaScript loggers inside code that gets called multiple times. As a result, you may get a series of messages that are essentially the same. Using onceOnly, you can suppress the duplicate messages, so only the first message is sent to the server.

This works by setting one or more regular expressions. When a log message matches one of the regular expressions, the logger remembers that there has been a message that matched that regular expression. Then when another message arrives that matches that same regular expression, it is suppressed.

For example, if you receive these messages:

    Parameter x too high - x = 5
    Parameter x too high - x = 6
    Parameter x too high - x = 7
    ...
    Parameter x too high - x = 49
    Parameter x too high - x = 50

Then you can use the regular expression:

    Parameter x too high - x = 

To only receive the very first message:

    Parameter x too high - x = 5

See the examples for how to set the regular expression.

You can set multiple regular expressions. These work independently. So if a message matches the first regular expression, then if a second message matches the second regular expression but not the first, then the second message gets through because it is not a duplicate of the first message.

As shown here, you can log not only strings but also objects. If you log an object, the object is translated to a JSON string. That string is than matched against the regular expressions.

Similar to other attributes, JavaScript loggers inherit onceOnly from their parents. However, this is all or nothing. If you set onceOnly regular expressions for a logger, than any onceOnly regular expressions that its parent may have had are disregarded.

Examples

This sets the level of logger "a.b" to 3000.

<jsnlog>
    <logger name="a.b" level="3000" />
</jsnlog>
// Use in Configure method in Startup class
        var jsnlogConfiguration = 
  new JsnlogConfiguration {
      loggers=new List<Logger> {
          new Logger {
              name="a.b",
              level="3000"
          }
      }
  };

This sets the level of the root logger.

<jsnlog>
    <logger level="3000" />
</jsnlog>
// Use in Configure method in Startup class
        var jsnlogConfiguration = 
  new JsnlogConfiguration {
      loggers=new List<Logger> {
          new Logger {
              level="3000"
          }
      }
  };

This sets the level of logger "a.b" to INFO (which is the same as setting it to 3000).

<jsnlog>
    <logger name="a.b" level="INFO" />
</jsnlog>
// Use in Configure method in Startup class
        var jsnlogConfiguration = 
  new JsnlogConfiguration {
      loggers=new List<Logger> {
          new Logger {
              name="a.b",
              level="INFO"
          }
      }
  };

This sets the level to 4000. It also disables the logger for all browsers, except those whose user agent string contains MSIE 7|MSIE 8 (that is, it is version 7 or 8 of Internet Explorer).

<jsnlog>
    <logger name="a.b" userAgentRegex="MSIE 7|MSIE 8" level="4000" />
</jsnlog>
// Use in Configure method in Startup class
        var jsnlogConfiguration = 
  new JsnlogConfiguration {
      loggers=new List<Logger> {
          new Logger {
              name="a.b",
              userAgentRegex="MSIE 7|MSIE 8",
              level="4000"
          }
      }
  };

This creates an appender "appender" and then tells the logger "a.b" to send all log messages to it.

<jsnlog>
    <ajaxAppender name="appender" />
    <logger name="a.b" appenders="appender" />
</jsnlog>
// Use in Configure method in Startup class
        var jsnlogConfiguration = 
  // Production: loggers log to the server only
  new JsnlogConfiguration {
      ajaxAppenders=new List<AjaxAppender> {
          new AjaxAppender {
              name="appender"
          }
      },
      loggers=new List<Logger> {
          new Logger {
              name="a.b",
              appenders="appender"
          }
      }
  };

This creates two appenders and then tells the logger "a.b" to send all log messages to them.

<jsnlog>
    <ajaxAppender name="appender1" />
    <ajaxAppender name="appender2" />
    <logger name="a.b" appenders="apender1;appender2" />
</jsnlog>
// Use in Configure method in Startup class
        var jsnlogConfiguration = 
  // Production: loggers log to the server only
  new JsnlogConfiguration {
      ajaxAppenders=new List<AjaxAppender> {
          new AjaxAppender {
              name="appender1"
          },
          new AjaxAppender {
              name="appender2"
          }
      },
      loggers=new List<Logger> {
          new Logger {
              name="a.b",
              appenders="apender1;appender2"
          }
      }
  };

Suppress duplicate messages that match the regular expression "Parameter x too high - x =".

<jsnlog>
    <logger name="a">
        <onceOnly regex="Parameter x too high - x =" />
    </logger>
</jsnlog>
// Use in Configure method in Startup class
        var jsnlogConfiguration = 
  new JsnlogConfiguration {
      loggers=new List<Logger> {
          new Logger {
              name="a",
              onceOnlies = new List<OnceOnlyOptions> {
                  new OnceOnlyOptions {
                      regex="Parameter x too high - x ="
                  }
              }
          }
      }
  };

Suppress duplicate messages that match the regular expression "Parameter x too high - x =". Also suppress duplicate messages that match "x = \d+ and y = \d+".

<jsnlog>
    <logger name="a">
        <onceOnly regex="Parameter x too high - x =" />
        <onceOnly regex="x = \d+ and y = \d+" />
    </logger>
</jsnlog>
// Use in Configure method in Startup class
        var jsnlogConfiguration = 
  new JsnlogConfiguration {
      loggers=new List<Logger> {
          new Logger {
              name="a",
              onceOnlies = new List<OnceOnlyOptions> {
                  new OnceOnlyOptions {
                      regex="Parameter x too high - x ="
                  },
                  new OnceOnlyOptions {
                      regex="x = \\d+ and y = \\d+"
                  }
              }
          }
      }
  };

Loggers inherit onceOnly from their parents. Assume you have a logger "a.b" whose parent "a" suppresses duplicates, but you want logger "a.b" to not suppress duplicates. To make that happen, give it a onceOnly collection without any regular expressions:

<jsnlog>
    <logger name="a.b">
        <onceOnly />
    </logger>
</jsnlog>
// Use in Configure method in Startup class
        var jsnlogConfiguration = 
  new JsnlogConfiguration {
      loggers=new List<Logger> {
          new Logger {
              name="a.b",
              onceOnlies = new List<OnceOnlyOptions> {
                  new OnceOnlyOptions {
                  }
              }
          }
      }
  };