ElmahR = ELMAH + SignalR (1.0.0 已发布!)
ELMAH + SignalR = ElmahR,ASP.NET 实时错误监控聚合仪表板
本文最初撰写于数月前,但在 ElmahR 1.0.0 发布后经过了大量审查和整合。
引言
我一直在关注和阅读关于 SignalR 的信息,自项目开始以来,同时我也一直是 ELMAH 的用户,并且很荣幸能与 其作者 分享工作时间和午餐。在某个时刻,我有一个想法,将这两个库结合起来,为 ELMAH 提供的日志记录功能提供实时交互体验,特别侧重于仪表板应在一个地方聚合多个应用程序的错误信息。ELMAH + SignalR = ElmahR。
背景
ElmahR 是一个 Web 仪表板,您可以在其中聚合多个监控的应用程序;将其添加到 ElmahR 的配置中,它们就能发布错误事件,这些事件将实时显示在所有连接的客户端仪表板上。ElmahR 关注实时错误日志记录,为此,它在*错误日志记录*部分依赖 ELMAH,在*实时通知*部分依赖 SignalR。
与 ELMAH 的集成并非基于二进制依赖,而是基于数据交换。ELMAH 已经定义了一组描述错误的字段和集合,ElmahR 借用了这个数据结构并在此基础上构建其逻辑。这种方法使得 ElmahR 几乎独立于 ELMAH:任何能够生成符合 ELMAH 数据格式的错误描述的人都可以将错误事件发送到 ElmahR 并进行发布。它不一定是 ASP.NET 应用程序,可以是桌面客户端、移动应用程序,甚至可以在非 .NET 平台上开发,只要它能够通过 HTTP 发布数据。不过,使用 ElmahR 最方便的方式是在您需要监控的 ASP.NET Web 应用程序上启用 ELMAH,并将其配置为发布错误到 ElmahR,这样您就可以利用 ELMAH 已有的所有出色的日志记录功能。为此,您需要我编写的新的 ErrorPostModule,它不是官方 ELMAH 的一部分,而是属于 ElmahR 的 ElmahR.Elmah 组件。
SignalR 是一个允许一组客户端通过服务器实时通信的项目,但最有趣的部分是 SignalR 能够提供的网络细节抽象。有多种适用于不同平台的客户端,但第一个,至少在我们的案例中,最有趣的是 JavaScript 客户端,它可以在 Web 浏览器中使用,并且跨不同浏览器具有高兼容性,将它们转化为实时消息传递环境。在底层,SignalR 能够切换多种通信技术,例如*WebSockets*到*长轮询*,仅举几例。您可以在其项目网站上阅读更多相关信息。
集成 ELMAH
假设您已经在要监控的应用程序中正确配置了 ELMAH,要将其连接到仪表板实例,您只需要适当地配置 ErrorPostModule。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="elmah">
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorPost" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
</sectionGroup>
</configSections>
<elmah>
<errorLog type="Elmah.MemoryErrorLog, Elmah" />
<errorPost targetUrl="http://dashboardUrl/posterror.axd"
sourceId="SomeUniqueCode" />
</elmah>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorPost" type="ElmahR.Elmah.ErrorPostModule, ElmahR.Elmah"/>
</modules>
</system.webServer>
<system.web>
<compilation targetFramework="4.0" />
</system.web>
</configuration>
就这么简单。有两个相关部分:
- 在配置
errorPost
部分时,指定targetUrl
和sourceId
: targetUrl
:posterror.axd
的地址;posterror.axd
是您需要定位的 ElmahR 端点,用于 HTTP POST 错误,它能够解析 ELMAH 数据格式并接收和正确处理错误。sourceId
:您指定的用于标识应用程序的键,ElmahR 将使用它将来自该源的错误匹配到仪表板上的正确信息流。- 在
system.webServer
部分的标准 ASP.NET 模块中添加新的 http 模块:
请注意,ErrorPostModule 完全不依赖 SignalR,它只是按照一些数据打包约定执行普通的 HTTP POST。如果您愿意,可以将同一应用程序配置为同时运行监控和被监控角色(尽管出于多种原因不推荐这样做,但该特定场景由另一个名为 ErrorTrapModule 的内部模块处理,该模块避免了 HTTP POST)。您可以在 Bitbucket 上的项目站点上找到有关如何配置源应用程序以及如何将其连接到特定仪表板的更多信息。
引入 SignalR
让我们继续分析项目的 SignalR 部分,这是我所做的。
- 我编写了一个 SignalR *hub*,轻松实现了客户端-服务器通信。
- 我引入了一个
.axd
处理程序,错误在此处被发布和解包,其解析方式与 ELMAH 端使用的约定相同。 - 我编写了一个仪表板页面,您可以通过 SignalR 的 JavaScript 客户端功能实时看到错误弹出。
- 我添加了一些可选功能,用于将接收到的错误持久化到持久化设备,以便应用程序能够通知新客户端有关旧异常的信息。
当错误通过前面描述的发布步骤到达 ElmahR 后,服务器端使用 SignalR 将其重新分发给所有连接的客户端。当 SignalR 完成其工作时,错误会以 JSON 结构形式到达客户端,这些结构仍然类似于 ELMAH 的数据格式。我在这里设定的目标之一是达到高度的关注点分离和模块化,这将更容易实现新模块的无缝集成。因此,处理 SignalR 通知*底层*代码是*可覆盖*的,以便您可以在“核心”广播功能之上挂接更高级的客户端功能和用户体验。SignalR 在许多方面都很有帮助,例如服务器端过滤、为新客户端或重新连接的客户端进行智能历史记录持久化,甚至客户端插件交付,这些功能都得益于 SignalR 的*hub*、*持久化连接*或*组*等强大功能,使仪表板可用。
UI
随着 ElmahR 项目的不断发展,UI 改进变得越来越有必要。信息量开始变大,潜在的 UI 可扩展性问题也变得明显。最后,我们腾出时间专注于仪表板的视觉方面,试图使其更加响应式,更好地呈现正确的信息,并能随着监控应用程序数量的增加而扩展。最后一个问题最令我们担忧,容纳 ElmahR 可能处理的相当大的信息量并不容易。
我们从 Twitter 网站的用户体验中获得灵感,并利用 Twitter Bootstrap 框架来构建响应式布局。这是一个非常有趣的框架,它极大地改善了仪表板的外观,现在我们对不同设备和浏览器提供了更好的支持。
Twitter Bootstrap 非常简单,但它也能帮助实现复杂的 UI,为了实现这一点,它可能会变得相当复杂。我们不能说我们完全理解了它,但我们也想尽快交付,所以我们通过分析 Bootstrap 示例应用程序并根据我们的需求进行修改,找到了一个相当不错且快速的折衷方案。这很可能是在不久的将来会进行改进和更新的领域之一。
如果您尝试演示网站,您会注意到我们有一个响应式布局,通常由 3 列组成,当可用宽度低于某个限制时(例如在手机上),这些列会折叠成 1 列。
第一列由摘要框组成。第一个框显示总体信息,如错误总数、最新错误类型以及引发错误的应用程序名称。其余框类似,但特定于每个监控的应用程序。这些应用程序特定的框可以通过拖放进行排序,可以展开以显示属于它们的错误,并且可以暂停或恢复相应的错误流。您还可以通过*骷髅头*按钮从那里触发源应用程序的测试异常,以检查一切是否正常连接。
第二列是一个全局信息流,所有错误都堆叠在此处,最新的错误显示在顶部。此列让用户一目了然地了解最新发生的错误。每个错误都可以展开,在弹出窗口中查看完整详细信息,当仪表板在小型设备上运行时,此功能将被禁用(我们仍在寻找在这些设备上显示详细信息更好的方法)。
第三列用于托管附加组件,到目前为止,我们构建了 2 个统计“插件”,这些插件应该被视为关于如何使用 ElmahR 可扩展性功能构建此类扩展的示例。
模块化
如前所述,ElmahR 具有一定的可扩展性功能,这源于项目结构随着时间的推移变得越来越模块化。现在 ElmahR 仪表板由多个部分组成:
- ElmahR.Core:大部分逻辑都位于此处,从错误处理到广播,从默认持久化到可插入系统;在此级别提供简化的*实时*日志流。
- ElmahR.Modules.Dashboard:“真正的”实时交互式仪表板由此模块提供。
- ElmahR.IoC.*:ElmahR 拥有一个嵌入式依赖注入机制,这要归功于 TinyIoC,但它允许您覆盖它,以便与您喜欢的 IoC 集成,选择一个现有模块或构建您自己的模块(到目前为止,只有 NInject 有一个合适的模块可用)。
- ElmahR.Persistence.*:ElmahR 的默认持久化机制将错误存储在内存中,但这个子系统来自一个模块,如果您需要将错误存储到持久化系统,则可以替换它。我们有用于 EntityFramework 以支持关系数据库的模块,也有用于 MongoDB 以支持它的模块,并且与 IoC 容器一样,您可以轻松构建自己的模块来支持其他场景。
这种模块化对客户端 JavaScript 文件结构产生了一些积极影响,这些文件需要尽可能独立。所有这些因素都允许任何人通过新模块或插件扩展 ElmahR,添加服务器端和客户端功能,而无需修改其内部代码。有关如何利用此模块化来构建新模块或插件的文档将在项目网站上提供。
Nuget 包
得益于上述模块化,我们找到了分发仪表板实例和 ElmahR.Elmah 模块的方法,通过 Nuget 包,您可以在此处找到它们。
最新添加
在过去几个月里,添加了更多功能,最值得注意的是:
- 仪表板相关的 Nuget 包
- ElmahR.Elmah Nuget 包
- 测试异常启动器
- ElmahR 作为其自身的错误源
- 底层日志记录
- 历史错误统计和清理
- MongoDB 持久化
- 错误发布加密
- 模块化结构
- 插件系统
- CSS + JS 打包和最小化
- IoC 容器支持
项目性质和目标
在此项目上工作非常有趣,因为它让我有机会尝试了许多很棒的外部技术,例如:
- 当然是 ELMAH,为它编写了一个新模块。
- SignalR,一个非常惊人的库。
- Knockout 用于在浏览器中实现 MVVM,非常“神奇”。
- Raphaël 用于在浏览器中构建图形。
- Underscore.js 用于在客户端“类 LINQ”地“组合”统计数据。
- 当然还有 jQuery。
- Mercurial,用于 Google Code 上的 ELMAH Sandbox,以及 Bitbucket 上的官方 ElmahR 主页。
- AppHarbor,用于托管实时演示,这是一个很棒的平台,部署 .NET 应用程序从未如此简单!
- Trello 用于轻量级“项目管理”。
- ...还有更多!
我承认,我希望 ElmahR 能够发展成人们将其视为 ELMAH、SignalR 或 Knockout 等库的*优秀示例应用*。我无法确定这个目标是否会实现,如果你们中的一些人想帮助我实现这个目标(即使是简单的建议或意见也备受欢迎),我将非常乐意与你们一起尝试!
您可以
历史
- 2013-03-XX:1.0.0 版本终于可用!模块化和 Nuget 包等改进。
- 2012-11-11:0.9.7 版本,支持错误发布加密。
- 2012-10-24:0.9.6 版本,异步持久化 + MongoDB 持久化器。
- 2012-09-20:0.9.4 版本,错误统计和清理。
- 2012-07-18:我在 aspConf 上做了一个关于 ElmahR 的演讲,演讲录像可以在 Channel9 上观看。
- 2012-07-15:0.8.8 版本,插件系统,以及各种改进。
- 2012-06-01:0.7.2 版本,持久化用户偏好设置,如应用程序信息流状态。
- 2012-05-21:0.7.0 版本,新的持久化模块,写入数据库,并从中检索历史错误。
- 2012-05-17:0.6.5 版本,允许用户查询旧错误。
- 2012-05-16:0.6.1 版本,项目现在使用 SignalR 0.5。
- 2012-05-04:项目当前版本为 0.6。