Documentation Menu

<jsnlog> / JsnlogConfiguration

The root for all JSNLog configuration elements.


        productionLibraryPath="string" >

Child Elements

<ajaxAppender> / AjaxAppenderConfigures an AjaxAppender.
<consoleAppender> / ConsoleAppenderConfigures a ConsoleAppender.
<logger> / LoggerConfigures a logger.
public class JsnlogConfiguration
    public bool enabled { get; set; }
    public uint maxMessages { get; set; }
    public string defaultAjaxUrl { get; set; }
    public string corsAllowedOriginsRegex { get; set; }
    public string serverSideLogger { get; set; }
    public string serverSideLevel { get; set; }
    public string serverSideMessageFormat { get; set; }
    public string dateFormat { get; set; }
    public string productionLibraryPath { get; set; }
public List<Logger> loggers { get; set; } public List<AjaxAppender> ajaxAppenders { get; set; } public List<ConsoleAppender> consoleAppenders { get; set; } }


This element has two sets of attributes:

  • Those that apply to JSNLog's client side library jsnlog.js, dealing with loggers and appenders;
  • Those that apply to JSNLog's server side component, dealing with CORS and processing of log messages.

Client side attributes

Attribute Default Description
true If false, all loggers are disabled.
no maximum Limits total number of messages sent to the server. See remarks below.
see remarks Default url used by ajax appenders when no url is set. See remarks below.

Server side attributes

Attribute Default Description
see remarks CORS related. Matches allowed domains. See remarks below.
(empty) By default, all log messages from your JavaScript code are passed on to your server side logging package with the name of the JavaScript logger.

However, if you want to use a specific logger name for all your JavaScript log messages, you can specify that with this attribute.

(empty) By default, all log messages from your JavaScript code are passed on to your server side logging package with the same level as the original JavaScript log message.

However, if you want to use a specific level, you can specify that with this attribute.

%message See remarks.
o Custom or standard date format string that determines how dates are formatted in the log. The default adheres to the ISO 8601 standard.
(empty) Only used with ASP.NET 4.x. Path to the jsnlog.min.js file. If this is given, the Configure method generates a <script> tag with this url (alternatives).


Provides the default url if no url is set on the AjaxAppender. Also sets the url for the default appender.

If defaultAjaxUrl is not set, the url /jsnlog.logger is used.

However, if your site sits in an application below the root application, then it will have a url like rather than JSNLog caters for this situation by adding the application path to the default url, resulting in a default url like /site/jsnlog.logger.


When setting defaultAjaxUrl or the url attribute on an AjaxAppender, you can use a url with a domain different from the domain you use for your site. For example, your site is on, but you want to send log entries to or

To make this happen, set corsAllowedOriginsRegex to a regular expression that matches all domains that JSNLog should accept log requests from. Otherwise your log requests will be ignored (examples).

This only applies to cross domain logging. You don't have to set corsAllowedOriginsRegex if you send log entries to the same domain as where your site is located (the most common case).

maxMessages and buffering

You use maxMessages to limit the number of messages sent to the server, per page load. When the page is loaded by the client, a counter is set to maxMessages. Each time messages are sent to the server, that counter is decremented by the number of messages sent. When the counter gets to zero or below, no more messages will be sent.

However, this is affected by batching and buffering.

Take a situation where maxMessages is set to 5 and 2 messages have already been sent - so the message counter is now 3. If 8 messages had been stored in a buffer and those messages are now sent, they will be all sent. That means the server will receive a total of 2 + 8 = 10 messages. After this, no more messages will be sent, because the number of messages sent (10) exceeds maxMessages (5).

This means that maxMessages is not a precise limit on the number of messages sent to the server. On the other hand, buffered messages are sent together in a single request to the server, minimizing bandwidth. And buffered messages are often useful in solving exceptions, so there is value in receiving them.


Your server not only receives the the original message passed into the JavaScript logger, but also the logger, the level, a timestamp, etc.

You can choose to have this additional information logged on the server along with the original message, by setting serverSideMessageFormat to a format string with one or more place holders:

Place holder Is replaced by
%message Original message given to the JavaScript logger.
%jsonmessage Original message given to the JavaScript logger, as a valid JSON value. See below.
%utcDate Date and time in UTC when the message was generated, according to the client's clock.
%utcDateServer Date and time in UTC when the message was received by the server, according to the server's clock.
%date Date and time when the message was generated, according to the client's clock. This equals %utcDate converted to the server's local time.
%dateServer Date and time in the server's local time when the message was received by the server, according to the server's clock.
%level Level of the message, as provided by the JavaScript code.
%userAgent Identifies the make of the browser.
%userHostAddress IP address(es) of the sender of the request (details below).
%url Url of the page on which the message was generated.
%logger JavaScript logger that generated the message.
%requestId Identifies the request for which the log message was created.

If you use server side configuration this request id will be generated for you. Otherwise, set this request id in your JavaScript using the JL.setOptions method.

%newline* Newline character

* If you use Elmah, %newline won't result in a newline in the elmah.axd page, because Elmah doesn't convert line breaks to HTML <br /> tags.

An alternative way to add information to your log messages is writing your own logging event handler. This gives you access to the cookies, request headers and query parameters of the incoming log request. It also allows you stop a message from being logged based on its content.

%message and %jsonmessage

Most people store log messages as unstructured strings of text. If that is you, you can skip this section. However, if you store log messages as valid JSON objects, read on.

Both %message and %jsonmessage are replaced by a string that represents the message that was logged. The difference is that whereas %message is replaced by the log message as-is, %jsonmessage is replaced by a string that can be used in a JSON message.

To clarify the issue, see the table below:

JavaScript %message %jsonmessage
JL().error("O'Connell"); O'Connell "O\u0027Connell"
JL().error({"f1": "v1", "f2": "v2"}); {"f1": "v1", "f2": "v2"} {"f1": "v1", "f2": "v2"}

As you see, there is no difference when logging an object (in the second row). But when logging a simple string, %message is replaced by the string, while for %jsonmessage the string is escaped and quoted.

This is important if you want to write valid JSON strings to your log. Suppose you attempted to do that using:

serverSideMessageFormat="{ 'Message': %message }"

That would work well if you only logged objects. But if you logged the string O'Connell, that would result in:

{ 'Message': O'Connell }

Which is not a valid JSON string. However, if you'd use:

serverSideMessageFormat="{ 'Message': %jsonmessage }"

The result would be a valid JSON string:

{ 'Message': "O\u0027Connell" }

serverSideMessageFormat and structured logging

If you create structured logs using Serilog, make sure that your format string results in a valid JSON string. Otherwise it will be logged as a string rather than an object.

Take for example:

serverSideMessageFormat="Sent: %date, Browser: %userAgent, Message: %message"

This will result in a string such as this in your log:

"{ 'Sent': 2014-08-19 21:02:42,603, 'Browser': 'Mozilla/5.0 ...', 'Message': {\"x\":5,\"y\":88} }"

To get a structured object instead, make sure that the result of your format string is a valid JSON string. For example:

serverSideMessageFormat="{ 'Sent': '%date', 'Browser': '%userAgent', 'Message': %jsonmessage }"


  • The curly braces;
  • Field names have been quoted.
  • %date and %userAgent have been quoted as well, to make them strings.
  • %message has been replaced by %jsonmessage, which has not been quoted. That way, when you log objects, they will be logged as objects rather than strings.

This will result in an object such as this in your log:

{ "Sent" : "2014-08-19 21:02:42,603", "Browser" : "Mozilla/5.0 ...", "Message" : { "x" : 5, "y" : 88 } }

Finally, the default value of serverSideMessageFormat gives you structured logging out of the box, even though the default is %message. The reason is that the Serilog adapter that is used by JSNLog to log to Serilog regards all strings that are not valid JSON strings as simple strings that are to be logged as-is.

Working out the IP address of the sender of a request

Working out the IP address of original sender of an HTTP request (that is, the user's browser) is not 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.

JSNLog reports the IP address(es) of the sender(s) of the request as a string of text containing a comma separated list. First is the browser itself, then intermediate proxies (in the order in which they were reached) and then the load balancer if there is one:

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


This shows the date and time that the log message was created on the client as well as the user agent in each log message.

<jsnlog serverSideMessageFormat="Sent: % date, Brower: % userAgent - % message" >
  new JsnlogConfiguration {
      serverSideMessageFormat="Sent: % date, Brower: % userAgent - % message"

This processes all client side JavaScript log messages via the server side logger "jslogger".

<jsnlog serverSideLogger="jslogger">
  new JsnlogConfiguration {

This disables all JavaScript loggers.

<jsnlog enabled="false">
  new JsnlogConfiguration {