1

I'm using NLog with a PowerShell script, where messages are logged to a file in a directory that is relative to the script.

I'd like to be able to specify a relative path in the Xml configuration file, but this syntax doesn't work:

<target name="logfile" xsi:type="File" fileName="./Logs/${logger}/${logger}.${date:format=yyyyMMdd}.${date:format=HHmmss}.log" createDirs="true" layout="${machinename}|${environment-user}|${logger}|${date:format=yyyy-MM-dd HH\:mm\:ss}|${level:uppercase=true}|${message}"/>

Currently, I'm doing this:

$ScriptName = (Get-Item $PSCommandPath).Basename
$Here = Split-Path -Parent $MyInvocation.MyCommand.Path

# create logger
$Logger = [NLog.LogManager]::GetLogger($ScriptName)

# load Xml configuration file (in the same directory as script)
$Configuration = [NLog.Config.XmlLoggingConfiguration]::new("$Here/$ScriptName.NLog.config")    
[NLog.LogManager]::Configuration = $Configuration

# reconfigure the file target
$target = $Configuration.FindTargetByName("logfile")
$target.FileName = "$Here/Logs/$ScriptName/$ScriptName.$( (get-date).tostring('yyyyMMdd.HHmmss') ).log"
[NLog.LogManager]::ReconfigExistingLoggers()

Is there a way to use a relative path in the Xml configuration file?

Rolf Kristensen
  • 17,785
  • 1
  • 51
  • 70
craig
  • 25,664
  • 27
  • 119
  • 205

2 Answers2

1

By default the NLog FileTarget will use the AppDomain.BaseDirectory as "root", and all relative-paths are relative to this "root".

I guess for PowerShell-scripts then AppDomain.BaseDirectory will be the PowerShell-Executable-Directory, and not the current directory as expected.

I think you will get the expected directory by using ${currentdir}:

<target name="logfile" xsi:type="File" fileName="${currentdir:cached=true}/Logs/${logger}/${logger}.${date:format=yyyyMMdd}.${date:format=HHmmss}.log" />

Alternative you can just write to ConsoleTarget and then use the default command-prompt logic to pipe the output from the powershell-stdout to the wanted filename.

Rolf Kristensen
  • 17,785
  • 1
  • 51
  • 70
  • Unfortunately, that didn't work. If there is a way to set the `currentdir` value in code, that would help. Setting `[System.Io.Directory]::SetCurrentDirectory($Here)` worked to set the `currentdir` to the script's folder. – craig Dec 21 '20 at 18:46
  • @craig Added another answer after having understood that you want the directory of the script-location and not the current-directory. – Rolf Kristensen Dec 21 '20 at 21:53
1

Alternative you can make use of NLog-Config-Variables:

<nlog>
    <variable name="ScriptDirectory" value="${currentdir}" />

    <targets>
       <target name="logfile" xsi:type="File" fileName="${var:ScriptDirectory}/Logs/${logger}/${logger}.${date:format=yyyyMMdd}.${date:format=HHmmss}.log" />
    </targets>

    <rules>
       <logger name="*" minLevel="Debug" writeTo="logfile" />
    </rules>
</nlog>

And then just assign the

NLog.LogManager.Configuration.Variables["ScriptDirectory"] = absolutePath;

Then you will not need to adjust current-directory, that might have unwanted side-effects.

Rolf Kristensen
  • 17,785
  • 1
  • 51
  • 70
  • This works. Why is `var:` required? I've used other variables without needing to qualify them in this manner. – craig Dec 23 '20 at 15:16
  • @craig NLog Config Variables are special. When used without `var:` then they work as carbon-copy replacement tokens, but are completely static. When using with `${var:` then they can be dynamically updated, but they only work with properties of type NLog `Layout` like the NLog FileTarget FileName-property. – Rolf Kristensen Dec 27 '20 at 21:27