I use .NET Core 6 with NLog used via ILogger, to access information in a SQL Server database.
I have two custom fields that I cannot save in the database. For these two fields I always got 0 in the database regardless of the passed values.
I can't figure out what's wrong and why it always saves me 0 in the Category and Action fields.
.csproj File
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<!-- Set this to true if you enable server-side prerendering -->
<BuildServerSideRenderer>false</BuildServerSideRenderer>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="11.0.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.2" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.2" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="4.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="NLog" Version="4.7.15" />
<PackageReference Include="NLog.Appsettings.Standard" Version="2.1.0" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0" />
<PackageReference Include="RestSharp" Version="107.3.0" />
</ItemGroup>
<ItemGroup>
<!-- Don't publish the SPA source files, but do show them in the project files list -->
<Content Remove="$(SpaRoot)**" />
<None Remove="$(SpaRoot)**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --configuration production" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --configuration production" Condition=" '$(BuildServerSideRenderer)' == 'true' " />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
<DistFiles Include="$(SpaRoot)node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project>
Program
public class Program
{
public static void Main(string[] args)
{
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
try
{
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
logger.Error(exception, "Stopped program because of exception");
throw;
}
finally
{
NLog.LogManager.Shutdown();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
}).UseNLog();
}
nlog.config
<?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="info" internalLogFile="internalLog.txt" internalLogToConsole="true">
<extensions>
<add assembly="NLog.Web.AspNetCore" />
</extensions>
<!-- the targets to write to -->
<targets>
<target name="DBLog" xsi:type="Database" dbProvider="Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient" connectionString="${appsettings:name=ConnectionStrings.default}">
<commandtext>INSERT INTO [dbo].[AtlassianEventLog] ([Date], [Level], [Category], [Action], [EventData]) VALUES (@Date, @Level, @Category, @Action, @EventData)</commandtext>
<parameter name="@Date" layout="${date}" dbType="SqlDbType.DateTime" />
<parameter name="@Level" layout="${level}" dbType="DbType.Int32" />
<parameter name="@Category" layout="${mdlc:Category}" dbType="DbType.Int32" /> <-- Custom Field Category
<parameter name="@Action" layout="${mdlc:Action}" dbType="DbType.Int32" /> <-- Custom Field Action
<parameter name="@EventData" layout="${message}" dbType="SqlDbType.NVarChar" size="500" />
</target>
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="Microsoft.*" maxlevel="off" final="true" />
<logger name="*" minlevel="Trace" writeTo="DBLog" />
</rules>
</nlog>
Log Class
public class LogSupport : ILogSupport
{
private readonly ILogger logger;
public LogSupport(ILogger<LogSupport> logger)
{
this.logger = logger;
}
public void LogServiceEvent(Interfaces.LogLevel logLevel, LogCategory logCategory, LogAction logAction, string eventData)
{
var config = new KeyValuePair<string, int>[]
{
new KeyValuePair<string, int>("Category", (int)logCategory),
new KeyValuePair<string, int>("Action", (int)logAction)
};
using (logger.BeginScope(config))
{
switch (logLevel)
{
case Interfaces.LogLevel.Trace:
logger.LogTrace(eventData);
break;
case Interfaces.LogLevel.Debug:
logger.LogDebug(eventData);
break;
case Interfaces.LogLevel.Information:
logger.LogInformation(eventData);
break;
case Interfaces.LogLevel.Warning:
logger.LogWarning(eventData);
break;
case Interfaces.LogLevel.Error:
logger.LogError(eventData);
break;
case Interfaces.LogLevel.Critical:
logger.LogCritical(eventData);
break;
}
}
}
}
EDIT #1
I tried accessing the file as suggested by Rolf Kristensen, and tried all types of mapping, I only got empty values except for the $ {ndlc} layout.
nlog.config updated
<?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="info" internalLogFile="internalLog.txt" internalLogToConsole="true">
<extensions>
<add assembly="NLog.Web.AspNetCore" />
</extensions>
<!-- the targets to write to -->
<targets>
<!-- <target name="DBLog" xsi:type="Database" dbProvider="Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient" connectionString="${appsettings:name=ConnectionStrings.default}">
<commandtext>INSERT INTO [dbo].[AtlassianEventLog] ([Date], [Level], [Category], [Action], [EventData]) VALUES (@Date, @Level, @Category, @Action, @EventData)</commandtext>
<parameter name="@Date" layout="${date}" dbType="SqlDbType.DateTime" />
<parameter name="@Level" layout="${level}" dbType="DbType.Int32" />
<parameter name="@Category" layout="${mdlc:item=Category}" dbType="DbType.Int32" />
<parameter name="@Action" layout="${mdlc:item=Action}" dbType="DbType.Int32" />
<parameter name="@EventData" layout="${message}" dbType="SqlDbType.NVarChar" size="500" />
</target> -->
<!-- local file target -->
<target xsi:type="File" name="file" fileName="log.txt" archiveFileName="log.{#}.txt" archiveNumbering="Date" archiveEvery="Day" archiveDateFormat="yyyyMMdd" layout="
-------------- ${level} (${longdate}) --------------${newline}${newline}
Category:
scopeproperty:item= ${scopeproperty:item=Category}${newline}
scopeproperty: ${scopeproperty:Category}${newline}
event-properties:item= ${event-properties:item=Category}${newline}
event-properties: ${event-properties:Category}${newline}
gdc:item= ${gdc:item=Category}${newline}
gdc: ${gdc:Category}${newline}
mdc:item= ${mdc:item=Category}${newline}
mdc: ${mdc:Category}${newline}
mdlc:item= ${mdlc:item=Category}${newline}
mdlc: ${mdlc:Category}${newline}
ndc:item= ${ndc:item=Category}${newline}
ndc: ${ndc:Category}${newline}
ndlc:item= ${ndlc:item=Category}${newline}
ndlc: ${ndlc:Category}${newline}
${newline}
Action:
scopeproperty:item= ${scopeproperty:item=Action}${newline}
scopeproperty: ${scopeproperty:Action}${newline}
event-properties:item= ${event-properties:item=Action}${newline}
event-properties: ${event-properties:Action}${newline}
gdc:item= ${gdc:item=Action}${newline}
gdc: ${gdc:Action}${newline}
mdc:item= ${mdc:item=Action}${newline}
mdc: ${mdc:Action}${newline}
mdlc:item= ${mdlc:item=Action}${newline}
mdlc = ${mdlc:Action}${newline}
ndc:item= ${ndc:item=Action}${newline}
ndc: ${ndc:Action}${newline}
ndlc:item= ${ndlc:item=Action}${newline}
ndlc: ${ndlc:Action}${newline}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="Microsoft.*" maxlevel="off" final="true" />
<!-- <logger name="*" minlevel="Trace" writeTo="DBLog" /> -->
<logger name="*" minlevel="Trace" writeTo="file"/>
</rules>
</nlog>
File Log
-------------- Warn (2022-04-05 18:08:49.4041) --------------
Category:
scopeproperty:item=
scopeproperty:
event-properties:item=
event-properties:
gdc:item=
gdc:
mdc:item=
mdc:
mdlc:item=
mdlc:
ndc:item=
ndc:
ndlc:item= TcAtlassianServices.ServerApp.Controllers.EventLogsController.GetEventLogs (TcAtlassianServices) System.Collections.Generic.KeyValuePair`2[System.String,System.Int32][]
ndlc: TcAtlassianServices.ServerApp.Controllers.EventLogsController.GetEventLogs (TcAtlassianServices) System.Collections.Generic.KeyValuePair`2[System.String,System.Int32][]
Action:
scopeproperty:item=
scopeproperty:
event-properties:item=
event-properties:
gdc:item=
gdc:
mdc:item=
mdc:
mdlc:item=
mdlc =
ndc:item=
ndc:
ndlc:item= TcAtlassianServices.ServerApp.Controllers.EventLogsController.GetEventLogs (TcAtlassianServices) System.Collections.Generic.KeyValuePair`2[System.String,System.Int32][]
ndlc: TcAtlassianServices.ServerApp.Controllers.EventLogsController.GetEventLogs (TcAtlassianServices) System.Collections.Generic.KeyValuePair`2[System.String,System.Int32][]
CodePudding user response:
Think you need to inject the scope-properties like this:
var config = new KeyValuePair<string, object>[]
{
new KeyValuePair<string, object>("Category", (object)(int)logCategory),
new KeyValuePair<string, object>("Action", (object)(int)logAction)
};
using (logger.BeginScope(config))
{
// Logging
}