使用 SignalR 2.0 流式传输日志





5.00/5 (6投票s)
实现 NLog 日志记录和 SignalR。
引言
有时你需要从你的网站读取在线日志流,但你并不总是有 FTP 访问权限来访问日志文件,或者有 Visual Studio 来附加到进程并读取调试输出。
在本文中,我们将使用 SignalR 和 NLog 将日志事件发送到 Web 浏览器。
背景
在很多情况下,你需要在线访问你的日志。在我的例子中,我有一个 webservice,它启动长时间运行的后台进程。此进程在进行时生成日志事件。我没有处理进度报告,而是决定扩展我的日志记录系统并将日志发送到浏览器。
SignalR 是一个 ASP.NET 框架,可以轻松开发实时 Web 应用程序。 SignalR 支持 WebSockets,但如果不支持 WebSockets,则会回退到其他兼容技术。 对我们来说重要的是它允许服务器将内容推送到连接的客户端/浏览器。
NLog 是 .NET 的日志记录平台。 它支持数十个日志目标(文件、事件日志、数据库、电子邮件等)。 最重要的是,任何开发人员都可以编写自定义目标。 它也部分兼容 Log4Net。
此示例使用使用 SignalR 实现日志流的最简单方法。
使用代码
服务器部分
通过 SignalR 2.0 添加日志记录是一个简单的过程。 唯一的要求是 .NET 4.5。 更改代码以使用 SignalR 1.0 将允许你使用 .NET 4.0。 附加的代码使用 Web Forms,但 SignalR 和 NLog 都可以与 MVC 一起使用,作为网站和 Web 应用程序。
首先,你需要添加 SignalR 和 NLog nuget 包。 这是一个简单且自动的步骤。 然后你需要添加 SignalR 启动类。 这设置了 SignalR 管道所需的所有配置。
[assembly: OwinStartup(typeof(SignalRStartup))]
public class SignalRStartup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
SignalR 使用所谓的 HUB 向客户端提供服务。 日志记录是一个单向过程,因此我们只需要将数据从服务器传输到客户端,而不是反过来。 为了更容易调试,有一个 Hello
方法,稍后可以更改该方法以实现(取消)订阅特定日志级别。
public class SignalRTargetHub : Hub
{
public void Hello()
{
this.Clients.Caller.logEvent(
DateTime.UtcNow.ToLongTimeString(),
"info",
"SignalR connected");
}
static IHubContext signalRHub;
public static void Send(string longdate, string logLevel, String message)
{
if (signalRHub == null)
{
signalRHub = GlobalHost.ConnectionManager.GetHubContext<SignalRTargetHub>();
}
if (signalRHub != null)
{
signalRHub.Clients.All.logEvent(longdate, logLevel, message);
}
}
}
NLog 支持开箱即用的 MethodCallTarget。 这允许我们将数据从日志记录系统传递回我们的代码。 此目标可以使用任意数量的参数调用任何静态方法。 在我们的例子中,被调用的方法是 SignalRTargetHub.Send(longdate, logLevel, message)
。 我们不能简单地创建 SignalRTargetHub 的新实例,但我们必须在 ConnectionManager
中找到上下文。 该上下文可用于将数据发送到连接的客户端。 如果找到上下文,我们会在所有连接的客户端上调用 javascript logEvent
函数。
Hello
方法仅用于更轻松的调试。 一旦客户端连接,浏览器就会调用 Hello
方法,服务器会使用字符串“SignalR 已连接”进行响应(调用调用者的 javascript 方法)。 这不是必需的,但稍后可以扩展并用于客户端注册。
客户端部分
唯一剩下的部分是客户端/浏览器的代码。 SignalR 自动生成 javascript 对象以访问 hub 方法。 此自动生成的 javascript 可以从 /signalr/hubs
下载。
<script src="/Scripts/jquery-1.6.4.min.js"></script>
<script src="/Scripts/jquery.signalR-2.0.3.min.js"></script>
<script src="/signalr/hubs"></script>
<script>
$(function () {
var logTable = $("#logTable");
var nlog = $.connection.signalRTargetHub;
nlog.client.logEvent = function (datetime, logLevel, message) {
var tr = $("<tr>");
tr.append($("<td>").text(datetime));
tr.append($("<td>").text(logLevel));
tr.append($("<td style='white-space: pre;'>").text(message));
logTable.append(tr);
};
$.connection.hub.start().done(function () {
nlog.server.hello();
});
});
</script>
<table id="logTable">
</table>
请注意 logEvent
函数定义。 每当 ASP.NET 调用方法 signalRHub.Clients.All.logEvent
时,都会从服务器调用此函数。
测试它
我们将向 global.asax 添加错误处理方法。 此方法将记录所有应用程序错误(例如,对不存在的网页的请求)
void Application_Error(object sender, EventArgs e)
{
Exception lastException = Server.GetLastError();
NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
logger.Fatal("Request: '{0}'\n Exception:{1}", HttpContext.Current.Request.Url, lastException);
}
现在我们可以加载 Log.aspx 网页并将第二个请求发送到一些随机页面。 在第一行,你将看到来自 Hello 方法的响应 - “SignalR 已连接”。
总结所有步骤
- 将 SignalR nuget 包添加到你的项目 (Microsoft.AspNet.SignalR)
- 添加 NLog nuget 包
- 添加 SignalRStartup.cs
- 添加 SignalRTargetHub.cs
- 更新你的 web.config (nlog 和 configSections)
- 添加 Log.aspx 页面
- 添加 global.asax
Hub 方法 Hello 不是必需的。它只是将第一个记录返回到你的网页。 你可以使用它来扩展你的 hub - 例如,允许用户仅注册某些级别的日志记录 - 检查 SignalR 对组的支持 - http://www.asp.net/signalr/overview/signalr-20/hubs-api/working-with-groups
要考虑的未来任务
- 你可能不希望每个人都可以访问你的日志。 SignalR 支持授权和身份验证 - 请参阅 http://www.asp.net/signalr/overview/signalr-20/security/hub-authorization
- 此实现仅发送在用户连接期间生成的日志。 获取日志历史记录不在本文的范围内。