14

The NLog.config file does not set the connection string.

<?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="Warn"
      internalLogFile="c:\temp\internal-nlog.txt">

  <!-- Load the ASP.NET Core plugin -->
  <extensions>
    <add assembly="NLog.Web.AspNetCore" />
  </extensions>
  <variable name="SirNLogDb" value="data source=SQL_MULALLEY;initial catalog=LogFiles;User ID=xxx;Password=yyy;">
  </variable>
  <!--  providerName="System.Data.SqlClient"-->

  <!-- the targets to write to -->
  <targets>
    <target name="db"
            xsi:type="Database"
            dbProvider="System.Data.SqlClient"
            connectionString="${var:SirNLogDb}"
            commandType="StoredProcedure"
            commandText="[dbo].[NLog_AddEntry_p]">
      <parameter name="@machineName"    layout="${machinename}" />
      <parameter name="@siteName"       layout="${iis-site-name}" />
      <parameter name="@logged"         layout="${date}" />
      <parameter name="@level"          layout="${level}" />
      <parameter name="@username"       layout="${aspnet-user-identity}" />
      <parameter name="@message"        layout="${message}" />
      <parameter name="@logger"         layout="${logger}" />
      <parameter name="@properties"     layout="${all-event-properties:separator=|}" />
      <parameter name="@serverName"     layout="${aspnet-request:serverVariable=SERVER_NAME}" />
      <parameter name="@port"           layout="${aspnet-request:serverVariable=SERVER_PORT}" />
      <parameter name="@url"            layout="${aspnet-request:serverVariable=HTTP_URL}" />
      <parameter name="@https"          layout="${when:inner=1:when='${aspnet-request:serverVariable=HTTPS}' == 'on'}${when:inner=0:when='${aspnet-request:serverVariable=HTTPS}' != 'on'}" />
      <parameter name="@serverAddress"  layout="${aspnet-request:serverVariable=LOCAL_ADDR}" />
      <parameter name="@remoteAddress"  layout="${aspnet-request:serverVariable=REMOTE_ADDR}:${aspnet-request:serverVariable=REMOTE_PORT}" />
      <parameter name="@callSite"       layout="${callsite}" />
      <parameter name="@exception"      layout="${exception:tostring}" />
    </target>
  </targets>

  <!-- rules to map from logger name to target -->
  <rules>
    <!--All logs, including from Microsoft-->
    <logger name="*" minlevel="Trace" writeTo="database" />
  </rules>
</nlog>

I put a breakpoint and the connection string is null; enter image description here

My Startup method is as follows;

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvcCore()
            .AddMvcOptions(o => o.OutputFormatters.Add(
                new JsonOutputFormatter(new JsonSerializerSettings(), ArrayPool<char>.Shared)));
        var connectionStringMSurveyV2 = Configuration.GetConnectionString("MSurveyV2Db");
        services.AddScoped<MSurveyV2Db>(_ => new MSurveyV2Db(connectionStringMSurveyV2));
        var connectionStringSir = Configuration.GetConnectionString("SirDb");
        services.AddScoped<SirDb>(_ => new SirDb(connectionStringSir));
        services.AddScoped<IPropertiesRepo, PropertiesRepo>();
        services.AddScoped<ISirUoW, SirUoW>();
        services.AddScoped<Services.IMailService, Services.MailService>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole();
        loggerFactory.AddDebug();
        loggerFactory.AddNLog();
        //add NLog.Web
        app.AddNLogWeb();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler();
        }

        app.UseMvc();
        AutoMapper.Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<Exception, OperationStatus>();
            cfg.CreateMap<ViewSelectedContracts, ContractDto>();
        });
        var logger = LogManager.GetCurrentClassLogger();
        logger.Info("Logged in");
    }
}

EDIT - I change the logger rule to <logger name="*" minlevel="Trace" writeTo="db" /> but still it didn't output anything. However I looked for the c:\temp\internal-nlog.txt and it had not been created. So it appears the nlog.config file is being ignored. But it is in my project next to the Startup.cs file.

EDIT2: - the null configuration can be solved by setting "Copy to output directory" to "copy always". From the comments underneath I have now got this working.

Julian
  • 33,915
  • 22
  • 119
  • 174
arame3333
  • 9,887
  • 26
  • 122
  • 205
  • "does not work" is very vague, if you want help to make it work. Have you verified with the NLog Internal-Log that the connection string is picked up? Maybe it is something else that prevents you from logging to the database. – Rolf Kristensen May 11 '17 at 15:09
  • Hi Rolf, what I mean is that nothing is output to the database. I have edited my question to show what the watch values are for the logger object. – arame3333 May 11 '17 at 15:30
  • Think the problem is that your logging-rule is writing to "database" but your target is called "db". Change your logging-rule to write to "db". – Rolf Kristensen May 11 '17 at 15:34
  • I changed the rule to --- logger name="*" minlevel="Trace" writeTo="db" --- but this made no difference – arame3333 May 11 '17 at 15:45
  • 1
    Can only repeat myself. Have you verified with the NLog Internal-Log that the connection string is picked up? – Rolf Kristensen May 11 '17 at 15:52
  • OK, so I have found this; 2017-05-08 15:43:00.9879 Error Error loading extensions. Exception: System.IO.FileNotFoundException: Could not load file or assembly 'NLog.Web.AspNetCore' or one of its dependencies. The system cannot find the file specified. File name: 'NLog.Web.AspNetCore' I have installed 'NLog.Web.AspNetCore' in my project via Nuget – arame3333 May 11 '17 at 16:01
  • Guess you should update the question then (Also how you detected the missing AspNetCore). Have you checked if the dll is located in your bin-folder? – Rolf Kristensen May 11 '17 at 18:16
  • 1
    Maybe read: https://github.com/NLog/NLog.Web/wiki/Getting-started-with-ASP.NET-Core-(csproj---vs2017) – Rolf Kristensen May 11 '17 at 19:08
  • `app.AddNLogWeb();` is also missing? – Julian May 11 '17 at 22:44
  • I fixed the 'NLog.Web.AspNetCore' problem, the nlog.Config file was in the wrong place. The problem now is that I cannot set the connection string and I get this error: NLog.NLogConfigurationException: Target database not found. When I put a breakpoint, if I set a variable then the connectionstring is set to "${var:SirNLogDb}" - it does not translate the name into the connection string. If I set the connection string directly, then I find that for the logger it is null – arame3333 May 15 '17 at 14:11
  • 1
    Again I think the problem is that your logging-rule is writing to "database" but your target is called "db". Change your logging-rule to write to "db" (Or did you forget to update/remove your screenshot of debugger?) – Rolf Kristensen May 15 '17 at 18:13
  • I changed the logger rule to but still nothing is output. I have edited the question to give you more information. – arame3333 May 16 '17 at 06:04
  • I found the problem! I tried deleting and recreating the nlog.config file and I forgot to set "Copy to output directory" to "copy always". Having made that change, now it works! – arame3333 May 16 '17 at 07:37

2 Answers2

21

Updated answer

Since NLog.Web.AspNetCore 4.8 (NLog.Extensions.Logging 1.4 for .NET Core console programs) you could directly read from your appSettings.json

${configsetting:name=MyConnectionString}

see docs


Original answer

Unfortunately reading connectionstrings/settings from appSettings.json / app.config is not yet supported in NLog for .NET core.

Two options:

  1. Set the connectionstring programmatically, by using variables. In your nlog.config:

    <target ... connectionString="${var:myConnectionstring}"  ... />
    

    and in code: (e.g. in Configure)

    LogManager.Configuration.Variables["myConnectionstring"] = "...."; //read config here
    
  2. Or, set the connectionstring in nlog.config.

    In your nlog.config:

    <variable name="myConnectionstring" value="...." />  
    

    and using in your target in nlog.config:

    <target ... connectionString="${var:myConnectionstring}" ... />
    
Rolf Kristensen
  • 17,785
  • 1
  • 51
  • 70
Julian
  • 33,915
  • 22
  • 119
  • 174
  • This is the correct answer. The real problem I had was that on my development database it was using the US date setting and on the staging and live servers it was the UK date setting. This caused Nlog not to work until I found out what the problem was. – arame3333 Sep 25 '17 at 07:07
  • @Julian: Do you have also a solution for that with asp.net core 2.0? – Stephu Nov 23 '17 at 20:49
  • 5
    The updated answer worked great for me using the dot notation: connectionString="${configsetting:name=ConnectionStrings.Logs}" This allowed me to get rid of the call to GlobalDiagnosticsContext in Startup.cs – Chris Porter Apr 17 '19 at 04:10
  • @Julian - its not working in .net core 6.0 – Rahul Hendawe Sep 16 '22 at 09:18
  • @RahulHendawe maybe check details here: https://github.com/NLog/NLog/wiki/ConfigSetting-Layout-Renderer – Julian Sep 16 '22 at 17:23
2

Another option is to create and register a custom NLog layout-renderer (startup.cs):

https://github.com/NLog/NLog/wiki/How-to-write-a-custom-layout-renderer

Which outputs the ConnectionString after having read it from your favorite configuration-location. Then you don't have the connectionstring in your nlog.config, but just refer to your custom layout-renderer.

Maybe cheer for this pending issue:

https://github.com/NLog/NLog.Web/issues/107

Rolf Kristensen
  • 17,785
  • 1
  • 51
  • 70