65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 JSNLog 在 JavaScript 中插入日志记录器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (9投票s)

2012年11月28日

CPOL

13分钟阅读

viewsIcon

29358

展示了如何使用 JSNLog 在 JavaScript 中插入日志记录器。JSNLog 是一个 JavaScript 日志记录库,可以很好地与您的 .Net 站点集成。

展示了如何使用 JSNLog 在 JavaScript 中插入日志记录器。JSNLog 是一个 JavaScript 日志记录库,可以很好地与 .Net 集成。它允许您在 web.config 中配置日志记录器。它还可以让您在不进行任何编码的情况下,从客户端接收日志消息并将其存储在服务器端。

本系列内容

本文内容

JL 命名空间

Logger 对象

Exception 对象

JL 命名空间

允许您创建日志记录器并配置 JSNLog 库本身。

JL 方法

创建和检索日志记录器

定义

JL(loggerName?: string): Logger
参数
loggerName
日志记录器的名称,或为空表示根日志记录器。
返回值

具有给定名称的日志记录器,或者在未给出名称时为根日志记录器。如果日志记录器不存在,则会创建它。

备注

在您的服务器端日志中,根日志记录器称为 ClientRoot

示例

这会返回名为“a.b”的日志记录器。

var logger = JL('a.b');

这会返回根日志记录器。

var rootlogger = JL();

setOptions 方法

设置库范围的选项

定义

setOptions(options: any): void
参数
options
一个包含选项的 JSON 对象。请参阅下面的“备注”部分。
返回值

本身。

备注

JSON 对象可以包含以下字段

字段 类型 默认值 描述
enabled
optional
bool true 如果为 false,则禁用所有日志记录器。
maxMessages
optional
number 无最大值 限制发送到服务器的消息总数。请参阅下面的备注。
requestId
optional
字符串 (空) 与所有日志消息一起发送到服务器,以便更容易识别给定请求的所有日志消息。通过 <jsnlog> 元素serverSideMessageFormat 属性中的 %requestId 占位符报告。
maxMessages 和缓冲

您可以使用 maxMessages 来限制发送到服务器的消息数量。当您通过调用 setOptions 设置 maxMessages 时,计数器会设置为 maxMessages。每次将消息发送到服务器时,该计数器都会减去发送的消息数量。当计数器降至零或以下时,将不再发送更多消息。

但是,这会受到 批量和缓冲 的影响。

考虑一个情况,maxMessages 设置为 5,并且已经发送了 2 条消息 - 因此消息计数器现在是 3。如果缓冲区中存储了 8 条消息,并且这些消息现在被发送,那么它们将被全部发送。这意味着服务器将总共收到 2 + 8 = 10 条消息。之后,将不再发送更多消息,因为发送的消息数量(10)超过了 maxMessages(5)。

这意味着 maxMessages 不是发送到服务器的消息数量的精确限制。另一方面,缓冲的消息会一起在一个请求中发送到服务器,从而最大程度地减少带宽。并且缓冲的消息通常有助于解决异常,因此接收它们是有价值的。

示例

这将 requestId 设置为与所有日志消息一起发送到服务器。

JL.setOptions({
    "requestId": "35F7416D-86F1-47FA-A9EC-547FFF510086"
});

Logger 对象

trace 方法

创建严重级别为 TRACE 的日志项

定义

trace<text>(logObject: any): Logger</text>
参数
logObject
要记录的字符串或对象,或者返回要记录的字符串或对象的函数(详细信息)。
返回值

Logger 本身。

示例

这会创建一个严重级别为 TRACE 的日志消息“log message”。

JL().trace<text>("log message");</text>

debug 方法

创建严重级别为 DEBUG 的日志项

定义

debug<text>(logObject: any): Logger</text>
参数
logObject
要记录的字符串或对象,或者返回要记录的字符串或对象的函数(详细信息)。
返回值

Logger 本身。

示例

这会创建一个严重级别为 DEBUG 的日志消息“log message”。

JL().debug<text>("log message");</text>

info 方法

创建严重级别为 INFO 的日志项

定义

info<text>(logObject: any): Logger</text>
参数
logObject
要记录的字符串或对象,或者返回要记录的字符串或对象的函数(详细信息)。
返回值

Logger 本身。

示例

这会创建一个严重级别为 INFO 的日志消息“log message”。

JL().info<text>("log message");</text>

warn 方法

创建严重级别为 WARN 的日志项

定义

warn<text>(logObject: any): Logger</text>
参数
logObject
要记录的字符串或对象,或者返回要记录的字符串或对象的函数(详细信息)。
返回值

Logger 本身。

示例

这会创建一个严重级别为 WARN 的日志消息“log message”。

JL().warn<text>("log message");</text>

error 方法

创建严重级别为 ERROR 的日志项

定义

error<text>(logObject: any): Logger</text>
参数
logObject
要记录的字符串或对象,或者返回要记录的字符串或对象的函数(详细信息)。
返回值

Logger 本身。

示例

这会创建一个严重级别为 ERROR 的日志消息“log message”。

JL().error<text>("log message");</text>

fatal 方法

创建严重级别为 FATAL 的日志项

定义

fatal<text>(logObject: any): Logger</text>
参数
logObject
要记录的字符串或对象,或者返回要记录的字符串或对象的函数(详细信息)。
返回值

Logger 本身。

示例

这会创建一个严重级别为 FATAL 的日志消息“log message”。

JL().fatal<text>("log message");</text>

fatalException 方法

创建严重级别为 FATAL 的日志项,包含消息和异常

定义

fatalException(logObject: any, e: any): Logger
参数
logObject
要记录的字符串或对象,或者返回要记录的字符串或对象的函数(详细信息)。
e
将与 logObject 一起记录的 Exception。在 Chrome、Firefox 和 IE10 及更高版本中,还会记录堆栈跟踪。但是,请参阅下面的备注。
返回值

Logger 本身。

备注

fatalException 函数会在以下情况下记录异常的堆栈跟踪(显示异常在代码中的发生位置)

  • 异常是由浏览器抛出的,例如尝试读取未定义变量时
    try {
        // Browser throws exception
        i.dont.exist = 666;
    } catch(e) {
        // Logs stack trace
        JL().fatalException("Exception was thrown!", e);
    }
  • 您抛出了 Error 对象Exception 对象:
    try {
        // Throwing Error object
        throw new Error("Whoops!");
    } catch(e) {
        // Logs stack trace
        JL().fatalException("Exception was thrown!", e);
    }

如果您抛出了不是 Error 对象或 Exception 对象的任何内容,fatalException 函数将*不会*记录堆栈跟踪。

try {
    // Throwing something that is not an Error Object or 
    // Exception Object (in this case a string)
    throw "Whoops!";
} catch(e) {
    // Does not log stack trace
    JL().fatalException("Exception was thrown!", e);
}

Exception 对象是 JSNLog 的内置对象。它为更好的异常处理打开了大门。详细信息 在此.

示例

此代码会捕获任何异常并记录它们。

try {
    ...
}
catch (e) {
    JL().fatalException("Exception was thrown!", e);
}

此代码会捕获任何异常,并将其与某些变量的值一起记录,以方便调试。

function f1(i, j) {
    try {
        ...
    }
    catch (e) {
        JL('f1').fatalException({ "i": i, "j": j}, e);
    }
}

setOptions 方法

为日志记录器设置选项

定义

setOptions(options: any): Logger
参数
options
一个包含选项的 JSON 对象。请参阅下面的“备注”部分。
返回值

Logger 本身。

备注

JSON 对象可以包含以下字段

字段 类型 默认值 描述
level
optional
number (继承自父日志记录器) 只有严重级别等于或高于此级别的日志消息才能发送到服务器。
userAgentRegex
optional
正则表达式 (继承自父日志记录器) 如果非空,则仅当此正则表达式与浏览器的 用户代理字符串 匹配时,才会处理日志消息。
ipRegex
optional
正则表达式 (继承自父日志记录器) 如果非空,则仅当此正则表达式与浏览器的 IP 地址匹配时,才会处理日志消息。如果使用此选项,请务必通过 JL 对象的 setOptions 方法 设置 IP 地址。
disallow
optional
正则表达式 (继承自父日志记录器) 如果非空,则在日志消息匹配此正则表达式时将其抑制。如果要记录的对象,它会被转换为 JSON 字符串,然后进行匹配。
appenders
optional
Appender 数组 (继承自父日志记录器) 一个或多个 Appender,供日志记录器发送其日志消息。请参阅示例。
onceOnly
optional
字符串数组 (继承自父日志记录器) 一个或多个正则表达式。当消息匹配正则表达式时,任何后续匹配同一正则表达式的消息都将被抑制。请参阅备注和示例。
Logger 名称和选项继承

日志记录器不仅通过 setOptions 方法获取其选项,还通过继承获取。这基于每个日志记录器的名称。

假设您在“namespace1”命名空间中有一个名为“method1”的方法。那么使用此类命名方案来命名您的日志记录器是有意义的:“namespace1.method1.logger1”、“namespace1.method1.logger2”等。这样,就不会有名称冲突,并且可以轻松跟踪您的日志记录器。

就像命名空间可以包含方法,方法可以包含日志记录器一样,您可以将这些日志记录器名称视为构成一个层次结构。

  • “namespace1.method1.logger1”的父级是“namespace1.method1”;
  • “namespace1.method1”的父级是“namespace1”;
  • “namespace1”的父级是根日志记录器(没有名称的日志记录器)。

您不限于只有 3 个级别,您可以拥有任意多个。

如果您不使用 setOptions 方法设置选项,该日志记录器会从其父级继承该选项。如果您根本不使用 setOptions 方法,每个日志记录器都将具有与根日志记录器相同的选项。

根日志记录器和默认 Appender

当库加载时,它会创建根日志记录器。它还为根日志记录器创建一个默认的 Appender。

由于每个日志记录器都继承自根日志记录器(除非您使用 setOptions 方法覆盖此设置),因此您可以立即开始日志记录,而无需创建 Appender。

根日志记录器使用以下选项创建

选项 默认值
level DEBUG
userAgentRegex (空)
ipRegex (空)
disallow (空)
appenders (默认 Appender)

请注意,由于根日志记录器的默认 level 是 DEBUG,因此默认情况下,只有严重级别为 DEBUG 或更高的日志消息才会得到处理。

您可以使用 setOptions 方法以与任何其他日志记录器相同的方式更改根日志记录器的选项。请参阅下面的示例。

选项 默认值
level TRACE
userAgentRegex (空)
ipRegex (空)
disallow (空)
storeInBufferLevel ALL
sendWithBufferLevel
bufferSize 0
batchSize 1
url jsnlog.logger
使用 onceOnly 抑制重复消息

您可能在会被多次调用的代码中拥有日志记录器。因此,您可能会收到一系列本质上相同的消息。使用 onceOnly,您可以抑制重复的消息,因此只有第一条消息会发送到服务器。

这通过设置一个或多个正则表达式来实现。当一条日志消息匹配其中一个正则表达式时,日志记录器会记住有一条消息匹配该正则表达式。然后,当另一条消息到达并匹配同一正则表达式时,它将被抑制。

例如,如果您收到以下消息

    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

那么您可以使用正则表达式

    Parameter x too high - x = 

以只接收第一条消息

    Parameter x too high - x = 5

有关如何设置正则表达式的示例,请参阅示例。

您可以设置多个正则表达式。它们独立工作。因此,如果一条消息匹配第一个正则表达式,然后第二条消息匹配第二个正则表达式但不匹配第一个,那么第二条消息就会通过,因为它不是第一条消息的重复。

正如 此处 所示,您不仅可以记录字符串,还可以记录对象。如果您记录一个对象,该对象会被转换为 JSON 字符串。然后将该字符串与正则表达式进行匹配。

与其他属性类似,日志记录器会从其父级继承 onceOnly。但是,这是全有或全无的。如果您为日志记录器设置了 onceOnly 正则表达式,那么其父级可能拥有的任何 onceOnly 正则表达式都将被忽略。

示例

这会将日志记录器“a.b”的级别设置为 3000。

var logger = JL("a.b");
logger.setOptions({
    "level": 3000
});

这会设置根日志记录器的级别。

var rootlogger = JL();
rootlogger.setOptions({
    "level": 3000
});

这会将日志记录器“a.b”的级别设置为 INFO(与设置为 3000 相同)。此代码表明您无需使用 logger 变量。

JL("a.b").setOptions({
    "level": JL.getInfoLevel()
});

这会将级别设置为 OFF,从而完全关闭该日志记录器。

JL("a.b").setOptions({
    "level": JL.getOffLevel()
});

这会将级别设置为 4000。它还禁用所有浏览器中的日志记录器,但那些用户代理字符串包含 MSIE 7|MSIE 8(即 Internet Explorer 的 7 或 8 版本)的浏览器。

var logger = JL("a.b");
logger.setOptions({
    "level": 4000,
    "userAgentRegex": "MSIE 7|MSIE 8"
});

这会创建一个名为“appender”的 Appender,然后告诉日志记录器“a.b”将所有日志消息发送给它。

var appender=JL.createAjaxAppender('appender');
var logger = JL("a.b");
logger.setOptions({
    "appenders": [appender]
});

这会创建 AjaxAppender 和 ConsoleAppender,然后告诉日志记录器“mylogger”将所有日志消息同时发送给它们。

var ajaxAppender=JL.createAjaxAppender('ajaxAppender');
var consoleAppender=JL.createConsoleAppender('consoleAppender');
JL("mylogger").setOptions({"appenders": [ajaxAppender,consoleAppender]});

抑制与正则表达式“Parameter x too high - x =”匹配的重复消息。

JL("a").setOptions({
    "onceOnly": [ "Parameter x too high - x =" ]
});

抑制与正则表达式“Parameter x too high - x =”匹配的重复消息。还抑制与“x = \d+ and y = \d+”匹配的重复消息。

JL("a").setOptions({
    "onceOnly": [ "Parameter x too high - x =", "x = \\d+ and y = \\d+" ]
});

日志记录器从其父级继承 onceOnly。假设您有一个日志记录器“a.b”,其父级“a”会抑制重复项,但您希望日志记录器“a.b”不抑制重复项。要实现这一点,请为其提供一个*不*包含任何正则表达式的 onceOnly 集合。

JL("a.b").setOptions({
    "onceOnly": [ ]
});

log 方法

创建日志项

定义

log(level: number, logObject: any): Logger

参数

level
要记录的消息的严重级别。
logObject
要记录的字符串或对象,或者返回要记录的字符串或对象的函数。请参阅备注。

返回值

Logger 本身。

备注

您不限于只记录字符串。您可以记录对象、数组、日期、数字、布尔值甚至正则表达式。这些都会在记录之前转换为字符串。

如果生成日志信息成本很高,那么您只会希望在信息实际被记录时才这样做 - 即,所记录信息的严重级别超过日志记录器的级别等。

为了解决这个问题,您可以传递一个函数而不是信息本身。此函数必须返回信息。只有当日志信息实际被记录时才会调用它。

您甚至可以让函数返回另一个返回实际信息的函数 - 或者另一个函数,依此类推。请确保此链中没有循环引用,否则会导致堆栈溢出。

示例

这会创建一个严重级别为 2500 的日志消息“log message”。

JL().log(2500, "log message");

这会记录一个对象。

var obj = {"f1": "v1", "f2": "v2"};
JL().log(2500, obj);

这会传递一个生成日志信息的函数。只有当日志信息实际被记录时才会调用该函数。

JL().log(2500, function() { return "log message"; });

Exception 对象

允许您创建包含 JSON 对象和内部异常的自定义异常。

备注

标准 Error 对象 类似,Exception 对象允许您在出现问题时抛出自定义异常。

function f(i, j) {
    if (i < 10) { 
        throw new JL.Exception("i is too small!");
    }
    ...
}

添加信息以辅助调试

但是,您可以传递一个包含更多信息的 JSON 对象,而不是字符串,以帮助您解决问题。

function f(i, j) {
    if (i < 10) { 
        throw new JL.Exception({
            "message": "i is too small!",
            "i": i,
            "j": j    
        });
    }
    ...
}

添加内部异常

Exception 对象支持内部异常 - 基本上是将一个异常存储在另一个异常内。要了解其工作原理,请考虑此代码:

function f2(v) {
    var x, y;
    ... some code
    if (somethingWentWrong) {
        throw new JL.Exception({ "x": x, "y": y, "v": v });
    }
}

function f1(anArray) {
    var i;    
    for(i = 0; i < anArray.length; i++) {
        f2(anArray[i]);
    }
}

try {
    f1([1, 2, 3]);
} catch(e) {
    JL().fatalException("Exception was thrown!", e);
}

函数 f2 可能会抛出异常。如果这样做,它会将所有相关信息放入异常中,以使解决问题更容易。

但是,函数 f1 也包含可能相关的信息,例如索引 i 的值。最好以某种方式将该信息添加到异常中。

在函数 f1 中捕获异常,然后抛出一个包含函数 f2 存储的所有信息以及索引 i 的新异常是可能的。但这将很复杂,并且我们会丢失原始异常的堆栈跟踪。

最简单的解决方案是在函数 f2 中捕获异常,然后抛出一个包含原始异常以及任何附加信息的新异常。这样,我们可以保留原始异常中存储的所有信息,包括其堆栈跟踪。更改将在下方以红色显示。

function f2(v) {
    var x, y;
    ... some code
    if (somethingWentWrong) {
        throw new JL.Exception({ "x": x, "y": y, "v": v });
    }
}

function f1(anArray) {
    var i;    
                try {
        for(i = 0; i < anArray.length; i++) {
            f2(anArray[i]);
        }
                } catch(e) {
        // Throw new exception that contains the original one
        throw new JL.Exception({ "i": i }, e);
    }
}

try {
    f1([1, 2, 3]);
} catch(e) {
    JL().fatalException("Exception was thrown!", e);
}

fatalException 函数能够读取 Exception 对象中的附加信息和内部异常,并将它们全部记录下来。

如果您愿意,没有什么可以阻止您拥有一个本身具有内部异常的内部异常。您可以深入任意级别。

下一部分

在 JSNLog 的第二部分中,您详细了解了 JSNLog 提供的所有 JavaScript 函数。 下一部分 将介绍您可以在 web.config 中使用的所有元素和属性来配置您的 JavaScript 日志记录器。

如果您喜欢这篇文章,请投它一票。

© . All rights reserved.