Vue.js ASP.NET Core NLog JSNLog
▌Introduction
The scenario is that we want to log on the
front-end and write to the backend.
▋Related articles
▌Environment
▋Visual Studio 2017 community
▋NPM: 5.6.0
▋ASP.NET Core 2.2.101
▋Vue CLI: 3.5.1
▌Packages
We will install the following packages into our
ASP.NET Core project thru Nuget:
▌NLog config
We have to update NLog settings in NLog.config.
▋NLog.config
Copy the following content to your NLog.config,
and modify the file pathes, database connection string, targets and rules.
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Off"
internalLogFile="C:\Logs\internal-nlog.txt">
<!--
enable asp.net core layout renderers -->
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<!--LOG
format-->
<variable name="Layout" value="${longdate}
| ${level:uppercase=true} | ${logger} | ${message} ${newline}"/>
<variable name="LayoutFatal" value="${longdate}
| ${level:uppercase=true} | ${logger} | ${message} |
${exception:format=tostring} ${newline}"/>
<variable name="LayoutEvent" value="${date}:
${message} ${stacktrace}"/>
<!--LOG
path -->
<variable name="LogTxtLocation" value="${basedir}/App_Data/Logs/${shortdate}/${logger}.log"/>
<variable name="LogTxtLocationFatal" value="${basedir}/App_Data/Logs/${shortdate}/FatalFile.log"/>
<variable name="ProjectName" value="MyProject"/>
<targets>
<!--Text
file-->
<target name="File" xsi:type="File" fileName="${LogTxtLocation}" layout="${Layout}" />
<target name="FileFatal" xsi:type="File" fileName="${LogTxtLocationFatal}" layout="${LayoutFatal}"/>
<!--Event
log-->
<!--<target
name="Event" xsi:type="EventLog" source="${ProjectName}"
log="Application" layout="${LayoutEvent}" />-->
<!--Log
Viewer(Optional)-->
<target name="Sentinel" xsi:type="NLogViewer" address="udp://127.0.0.1:3333"/>
<!--Database-->
<target name="LogDatabase" xsi:type="Database" >
<connectionString>
Data
Source=Your-DB-Server-name;Initial Catalog=Your-DB-Name;Integrated
Security=True;
</connectionString>
<commandText>
INSERT
INTO AspnetCoreLog (
Application, Logged, Level, Message,
Logger, CallSite, Exception
)
values (
@Application, @Logged, @Level, @Message,
@Logger, @Callsite, @Exception
);
</commandText>
<parameter name="@application" layout="AspNetCoreNlog" />
<parameter name="@logged" layout="${date}" />
<parameter name="@level" layout="${level}" />
<parameter name="@message" layout="${message}" />
<parameter name="@logger" layout="${logger}" />
<parameter name="@callSite" layout="${callsite:filename=true}" />
<parameter name="@exception" layout="${exception:tostring}" />
</target>
</targets>
<rules>
<logger name="*" levels="Trace,
Debug, Info, Warn" writeTo="File" />
<logger name="*" levels="Error,
Fatal"
writeTo="FileFatal,LogDatabase" />
<logger name="*" levels="Trace,
Debug, Info, Warn, Error, Fatal" writeTo="Sentinel" />
</rules>
</nlog>
▌Config ASP.NET core
▋Program.cs
Use NLog for DI logger.
public static IWebHostBuilder
CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureLogging(logging
=>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
})
.UseNLog();
And we can have other NLog config, like NLog.Development.config,
for the development environment.
We can optionally load it depends on the
environment variable, ASPNETCORE_ENVIRONMENT.
public static IWebHostBuilder
CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureAppConfiguration((hostingContext,
config) =>
{
var env =
hostingContext.HostingEnvironment;
if
(env.IsDevelopment())
{
env.ConfigureNLog($"NLog.{environment}.config");
}
})
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
})
.UseNLog();
▋Optional: Cross-Origin
Resource Sharing (CORS)
If we are going to use the cross-domain logging server,
we need to set the allowed domain to JSNLog in backend.
Open Startup.cs and update the Configure function,
using JSNLog;
using
Microsoft.Extensions.Logging;
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory
loggerFactory)
{
// Configure
JSNLog
var
jsnlogConfiguration =
new JsnlogConfiguration
{
corsAllowedOriginsRegex = "^https?://localhost:8080"
};
app.UseJSNLog(new LoggingAdapter(loggerFactory),
jsnlogConfiguration);
//…skip
}
And don’t forget to enable CORS
on the ASP.NET Core.
▋Startup.js
public void ConfigureServices(IServiceCollection services)
{
//Enable CORS
services.AddCors(options
=>
{
options.AddPolicy("AllowSpecificOrigin",
builder
=>
builder.WithOrigins("http://localhost:8080")
//
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowCredentials()
.AllowAnyMethod()
);
});
#endregion
}
And applying CORS globally as
following,
public void Configure(IApplicationBuilder app)
{
app.UseCors("AllowSpecificOrigin");
app.UseMvc();
}
I made a mistake to enable
CORS ONLY ON Controller’s actions
(as following) and the cross-domain requests are denied from front-end logging.
//
Enable CORS for every MVC actions
services.Configure<MvcOptions>(options
=>
{
options.Filters.Add(new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
});
|
▌Start logging
▋Backend (MVC
controller)
[ApiController]
public partial class MyController
: ControllerBase
{
private readonly ILogger<MyController> _logger
= null;
public MyController(
ILogger<MyController> logger)
{
this._logger =
logger;
}
[HttpGet]
public async Task<IActionResult> Get()
{
this._logger.LogDebug("Testing");
//…skip
}
}
}
▋Frontend
$ npm
intall jsnlog
Now you can log like this,
import {JL} from "jsnlog";
JL().trace("Trace...");
JL().debug("Debug...");
JL().info("Info...");
JL().warn("Warn...");
JL().error("Error...");
JL().fatal("Fatal...");
If the front-end and back-end are cross-domain, create new AjaxAppender to
assign the specified logging server
▋jsnlogger.js
import {JL} from "jsnlog";
const appender = JL.createAjaxAppender("minitisAppender")
appender.setOptions!({
url: `${process.env.YOUR_HOST_BACKEND_URL}/jsnlog.logger`
});
export default JL("MiniTis-Vue").setOptions({
"appenders": [appender]
});
Then log by the custom JSNLog object,
import JL from "jsnlogger";
@Component({
components: {
},
})
export default class XXXX extends Vue {
public mounted() {
JL.trace("Trace...");
JL.debug("Debug...");
JL.info("Info...");
JL.warn("Warn...");
JL.error("Error...");
JL.fatal("Fatal...");
}
}
▋Result
▌Reference