Client-Side Logging for ASP.NET Core with Loupe
Client-side logging is the best way to effectively collect log data for any web application that relies on JavaScript to do the heavy lifting, specifically for single-page applications. That’s why we are happy to introduce client-side logging for ASP.NET Core in the most recent version of the Loupe Agent.
The new release of Loupe.Agent.AspNetCore adds support for client-side (i.e., JavaScript) logging, so logs generated in the browser can be sent to your Loupe server along with the messages from your .NET code. Here, we have some information that should help you get started.
Configuring the Server
To use client-side logging in your ASP.NET Core MVC application, with the
Loupe.Agent.AspNetCore package installed, you need to add a few lines to your Startup
configuration class.
In the ConfigureServices
method, append AddClientLogging()
to the AddLoupe()
call:
public void ConfigureServices(IServiceCollection services)
{
services.AddLoupe()
.AddClientLogging(); // Add client logging services
services.AddControllersWithViews();
}
In the Configure
method, you need to add the Loupe cookie-handling middleware into the
app pipeline. This should go in before Authentication and Routing, but after
Static Files if present.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.UseStaticFiles();
app.UseLoupeCookies(); // Add Loupe cookie-handling
app.UseRouting();
app.UseAuthorization();
// ...
}
Finally, you need to configure the endpoint where the Loupe client will send messages. The configuration process for .NET 5 and .NET Core 3.1 is the same, but .NET Core 2.1 requires a different setup. Here, we will go over both.
Add Endpoint in .NET Core 3.1 and .NET 5
In .NET 5 and .NET Core 3.1, this is handled in the UseEndpoints
callback with
MapLoupeClientLogger
. You can specify a custom path for the logger or leave the
default, which is /loupe/log
.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapLoupeClientLogger(); // Add the /loupe/log endpoint
});
}
MapLoupeClientLogger
returns an IEndpointConventionBuilder
instance, which you can
use to customize authentication, CORS and other concerns for the logging endpoint.
Add Endpoint in .NET Core 2.1
In .NET Core 2.1, you will need to add the Loupe client logger to the
IApplicationBuilder
instance. Again, you can optionally specify a custom path or
use the default /loupe/log
.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.UseLoupeClientLogger();
}
Client-side Use
Loupe provides two NPM packages for JavaScript and TypeScript clients: one for general purpose use and one specifically for Angular applications.
Using the General Purpose Client
The Loupe Agent for JavaScript & TypeScript is distributed on NPM as @gibraltarsoftware/loupe-typescript. Once installed in your project, you can import the Agent and use it for logging in your client app.
import { LoupeAgent } from '@gibraltarsoftware/loupe-typescript/dist/loupe.agent';
const loupe = new LoupeAgent(window, document);
loupe.information('App', 'Loaded', 'Application loaded');
Using the Angular Client
We developed a dedicated NPM package for Angular applications,
@gibraltarsoftware/loupe-angular, that provides an injectable Angular Service
and can integrate with Angular sub-systems. For example, to log a message every time
a Router navigation is triggered, you can subscribe to the router.events
observable,
as shown below.
import { Component } from '@angular/core';
import { Router, NavigationStart, RouterEvent } from '@angular/router';
import { LoupeService } from '@gibraltarsoftware/loupe-angular';
import { filter } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
title = 'app';
constructor(
private router: Router,
private loupe: LoupeService
) {
this.router.events.pipe(
filter(x => x instanceof NavigationStart)
).subscribe((evnt: RouterEvent) => {
this.loupe.information(
"Angular", "NavigationStart", evnt.url,
null, null, JSON.stringify(evnt), null
);
});
}
}
What This Means for You
Loupe treats client-side data the same way it treats all other data. You can find these logs through searches, set up notifications, look at the stack trace, use the same error triage process, and more.
An Example stack trace in Loupe Server for a JavaScript error
We are excited to add client-side for ASP.NET Core agent because developers can leverage the same Loupe features they have been using with .NET code for client-side JavaScript as well. Instead of disappearing in the browser, you can now save these logs, thanks to Loupe. We look forward to folks using this new feature and finding new ways to improve their applications.