3

在使用 F# Interactive 时,我需要捕获 F# 函数的输入和输出。当程序在 Visual Studio 下使用 F5 或 Ctrl-F5 运行时,我可以让 NLog 正常工作。同样,包含要输出到日志的语句的相同方法也可以正常工作,并在通过 F# Interactive 调用时被调用;日志文件中没有任何内容。

我还尝试使用 F# Interactive 设置对 NLog 的引用,但从 F# Interactive 运行时日志中仍然没有任何内容。

#I @"..\packages\NLog.2.0.0.2000\lib\net40" 
#r @"NLog.dll"

我什至发现让我尝试了这些

NLog.Config.SimpleConfigurator.ConfigureForConsoleLogging()
NLog.Config.SimpleConfigurator.ConfigureForFileLogging(<full file name>)

日志文件中仍然没有任何内容。

有人知道 Nlog 是否可以与 F# Interactive 一起使用吗?
如果是这样,它是如何完成的?

编辑

当单独运行时,我能够让 NLog 与 fsi.exe 一起工作。所以现在问题似乎是让 NLog 找到配置文件,因为 NLog 找不到从 Visual Studio 的 fsi.exe 位置开始的配置文件。查看在 NLog.dll 目录中使用 NLog.dll.nlog。

4

1 回答 1

11

问题

使用 F# Interactive 的 NLog 的问题在于,NLog 认为该Temp目录是可以找到的位置NLog.config并且永远不会成功。解决这个问题的方法是以编程方式定位NLog.configNLog。

解决这个问题需要知道的事情:

  1. 从 Visual Studio 中运行 F# Interactive 时,它​​会将当前工作目录设置为临时文件。

    > System.Environment.CurrentDirectory;; 
    val it : string = "C:\Users\Eric\AppData\Local\Temp"
    
  2. NLog 日志记录需要三个组件
    :参考 NLog.dll。
    湾。配置文件。
    C。从代码调用记录器方法。

  3. NLog 可以通过多种方式进行配置,包括编程方式和使用配置文件。
  4. AppData 是一个隐藏文件夹。猜猜在使用 Windows 资源管理器时这意味着什么。
  5. 要在 Visual Studio 中使用 F# Interactive 获取应用程序的位置,您需要__SOURCE_DIRECTORY__. 请参阅F# Spec 3.11 标识符替换
  6. NLog.conf 可以使用完整的文件路径。明显但必要。
  7. NLog文件目标有一个 autoFlush 选项。
  8. NLog 可以使用NuGet安装到Visual Studio 项目中。
  9. 这里的大部分信息来自NLog Wiki

无需直接跳入 F# Interactive 解决方案,而是使用以下进程,因为需要创建一个 DLL 来设置和保存用于 F# Interactive 的 NLog 的函数。

  1. 创建一个包含三个项目的解决方案并安装 NLog。
    解决方案名称:NLogExample
    项目 1 - 库,名称:Log - 包含调用 NLog
    项目 2 - 库的扩展函数,名称:MyLibrary - 用于生成使用 Log 函数的演示 DLL。
    项目 3 - 控制台应用程序,名称:Main - 用于生成使用日志功能的演示 EXE。

  2. 一种。手动创建 NLog.config
    b. 从正在运行的项目中访问 NLog.config
    c。将消息记录到文件

  3. 一种。以编程方式创建配置
    b. 为正在运行的项目创建配置并将消息记录到文件中

  4. 使用 F# Interactive 创建配置并将消息记录到文件中

1.创建一个包含三个项目的解决方案并安装NLog

使用 Visual Studio 创建三个项目。

在此处输入图像描述

为所有三个项目安装 NLog。

在此处输入图像描述

2.a. 手动创建 NLog.config

注意:为了让这些示例在从 F# Interactive 运行时能够正常工作,它应该报告作为项目一部分的目录__SOURCE_DIRECTORY__;;不是Temp目录。

注意:此答案中的所有路径都相对于解决方案目录。
当您<Solution directory>在实际解决方案目录中看到替代品时。

小路:<Solution director>\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"
      throwExceptions="true">

  <targets>
    <target xsi:type="File"
            name="file"
            fileName="<Solution directory>\log.txt"
            autoFlush="true"
      />
    </targets>

  <rules>
    <logger name="*"
            minlevel="Trace"
            writeTo="file"
    />
  </rules>
</nlog>

注意:记得更改<Solution directory>为实际路径并设置 autoFlush="true"

注意:添加NLog.config到解决方案可以更轻松地查看/修改文件。

在此处输入图像描述

2.b。从正在运行的项目中访问 NLog.config

在 Log.Library1.fs

namespace Log

module MyLog =

    let configureNLog () =
      let projectPath = __SOURCE_DIRECTORY__
      let soulutionPath = projectPath + "\.."
      let configPath = soulutionPath + @"\NLog.config"
      let xmlConfig = new NLog.Config.XmlLoggingConfiguration(configPath)
      NLog.LogManager.Configuration <- xmlConfig

    let NLogConfigToString () = 
      let targets = NLog.LogManager.Configuration.AllTargets
      let out = ""
      let out = Seq.fold (fun out target -> out + (sprintf "%A\n" target)) out targets
      let rules = NLog.LogManager.Configuration.LoggingRules
      let out = Seq.fold (fun out rule -> out + (sprintf "%A\n" rule)) out rules
      out

    let printNLogConfig () = 
       Printf.printfn "%s" (NLogConfigToString ())

并为 Log 项目添加对System.XML

在 Main.Program.fs

open Log

[<EntryPoint>]
let main argv = 

    MyLog.configureNLog ()
    MyLog.printNLogConfig ()

    0 // return an integer exit code

并为 Main 项目添加对该Log项目的引用并将 Main 项目设置为启动项目。

运行时应该输出到控制台:

File Target[file]
logNamePattern: (:All) levels: [ Trace Debug Info Warn Error Fatal ] appendTo: [ file ]

2.c。将消息记录到文件

在 Log.Library1.fs

namespace Log

open NLog

module MyLog =

    let configureNLog () =
      let projectPath = __SOURCE_DIRECTORY__
      let soulutionPath = projectPath + "\.."
      let configPath = soulutionPath + @"\NLog.config"
      let xmlConfig = new NLog.Config.XmlLoggingConfiguration(configPath)
      NLog.LogManager.Configuration <- xmlConfig

    let NLogConfigToString () = 
      let targets = NLog.LogManager.Configuration.AllTargets
      let out = ""
      let out = Seq.fold (fun out target -> out + (sprintf "%A\n" target)) out targets
      let rules = NLog.LogManager.Configuration.LoggingRules
      let out = Seq.fold (fun out rule -> out + (sprintf "%A\n" rule)) out rules
      out

    let printNLogConfig () = 
       Printf.printfn "%s" (NLogConfigToString ())

    let evalTracer = LogManager.GetLogger("file")

在 Main.Program.fs

open Log
open Library1

[<EntryPoint>]

    let main argv = 

        MyLog.configureNLog ()
        MyLog.printNLogConfig ()

        // Add as many of these as needed
        MyLog.evalTracer.Trace("In Main @1.")

        MyFunctions.test001 ()

        0 // return an integer exit code

并为 Main 项目添加对该MyLibrary项目的引用。

在 MyLibrary.Library1.fs

namespace Library1

open Log

module MyFunctions =

    let test001 () =
        MyLog.evalTracer.Trace("In Library @1.")

并为 MyLibrary 项目添加对该Log项目的引用。

运行时,日志文件log.txt应包含类似以下内容:

2016-03-28 11:03:52.4963|TRACE|file|In Main @1.
2016-03-28 11:03:52.5263|TRACE|file|In Library @1

3.a. 以编程方式创建配置

如果NLog.config文件存在,请删除它以验证代码是否创建了新配置但未创建文件。

要使用 F# 以编程方式设置配置,您需要知道:

  1. 此 FileName 字符串是一个布局,其中可能包含布局渲染器的实例。这使您可以使用单个目标写入多个文件。
  2. SimpleLayout - 表示带有嵌入占位符的字符串,可以呈现上下文信息。

到 Log.Library1.fs 添加

let configureNLogPrgramatically () =
  let config = new NLog.Config.LoggingConfiguration()
  let fileTarget = new NLog.Targets.FileTarget()
  let projectPath = __SOURCE_DIRECTORY__
  let soulutionPath = projectPath + "\.."
  let filePath = soulutionPath + @"\log.txt"
  let layout = new NLog.Layouts.SimpleLayout(filePath)
  fileTarget.Name <- "file"
  fileTarget.FileName <- layout
  fileTarget.AutoFlush <- true
  config.AddTarget("file", fileTarget)
  let rule1 = new NLog.Config.LoggingRule("*",NLog.LogLevel.Trace,fileTarget)
  config.LoggingRules.Add(rule1)
  NLog.LogManager.Configuration <- config

3.b。为正在运行的项目创建配置并将消息记录到文件中

在 Main.Program.fs

open Log
open Library1

[<EntryPoint>]

    let main argv = 

        MyLog.configureNLogPrgramatically ()
        MyLog.printNLogConfig ()

        // Add as many of these as needed
        MyLog.evalTracer.Trace("In Main @1.")

        MyFunctions.test001 ()

        0 // return an integer exit code

运行时,日志文件log.txt应包含类似以下内容:

2016-03-28 11:16:07.2901|TRACE|file|In Main @1.
2016-03-28 11:16:07.3181|TRACE|file|In Library @1.

并注意NLog.config创建文件 。

4. 使用 F# Interactive 创建配置并将消息记录到文件中

在 MyLibrary.Script.fsx 中

// print out __SOURCE_DIRECTORY__ to make sure we are not using the Temp directory
printfn __SOURCE_DIRECTORY__

#I __SOURCE_DIRECTORY__

// Inform F# Interactive where to find functions in Log module
#I "../Log/bin/Debug/"
#r "Log.dll"

open Log

// Functions in Log module can now be run.
MyLog.configureNLogPrgramatically ()
MyLog.printNLogConfig ()

// Inform F# Interactive where to find functions in MyLibrary module
#I "../MyLibrary/bin/Debug/"
#r "MyLibrary.dll"

open Library1

// Functions in MyLibrary module can now be run.
MyFunctions.test001 ()

使用 F# Interactive 执行脚本时

Microsoft (R) F# Interactive version 14.0.23413.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> 
<Solution directory>\MyLibrary
val it : unit = ()

--> Added <Solution directory>\MyLibrary' to library include path


--> Added <Solution directory>\MyLibrary\../Log/bin/Debug/' to library include path


--> Referenced <Solution directory>\MyLibrary\../Log/bin/Debug/Log.dll'

File Target[file]
logNamePattern: (:All) levels: [ Trace Debug Info Warn Error Fatal ] appendTo: [ file ]


--> Added <Solution directory>\MyLibrary\../MyLibrary/bin/Debug/' to library include path


--> Referenced <Solution directory>\MyLibrary\../MyLibrary/bin/Debug/MyLibrary.dll'


val it : unit = ()

> 

日志文件log.txt应包含类似以下内容:

2016-03-28 11:42:41.5417|TRACE|file|In Library @1.

此外,当您仍然有一个活动的 F# Interactive 会话时,这将记录下来,因此您可以在执行命令之间查看日志。

于 2013-02-04T01:23:27.530 回答