我使用异步工作流在 F# 中编写了一个应用程序。 现在我想做的是添加一些跟踪!
基本上有一个可以多次实例化的 A 类。每个实例都独立异步(本身)和并行(与其他实例)工作。 我现在的基本想法是为 A 的每个实例添加一个 TraceSource 实例,这很可能是我想要做的。我设法通过 https://github.com/matthid/fsharpasynctrace 解决了使用 Async 对象分发 TraceSource 的问题
但是,如果每个 TraceSource 实例都指定相同的名称,则其中一些实例将写入同一个文件 (log.txt),而其他实例将写入 {guid}log.txt。
如果我为每个实例指定一个其他名称,则用户必须编辑 app.config 文件才能正确记录日志。 A 的每个实例都有一个由用户指定的逻辑名称,因此理想情况下我会将实例的日志保存在 name_log.txt 中。 (这是因为用户基本上是在运行时创建 A 的实例)
所以我的问题是:有没有更好的方法来做到这一点,即无需用户交互,仍然可以获得所需的输出和灵活性(通过 app.config)?
注意:因为基本上所有内容都在线程池中,并且因为同时跨实例可能有很多操作,所以跟踪类或线程根本不是一个选项。
注2:我可以考虑以某种方式扩展app.config并自己完成,这是我唯一的选择吗?
编辑: 为了使问题更清楚:
想象一下下面的类:
module OtherModule =
let doSomethingAsync m = async{return()}
[<AbstractClass>]
type A (name:string) as x =
let processor =
MailboxProcessor.Start(
fun inbox -> async {
while true do
let! msg = inbox.Receive()
do! x.B(msg)
do! OtherModule.doSomethingAsync(msg)})
abstract member B : string -> Async<unit>
member x.Do(t:string) = processor.Post(t)
您有很多此类的实例,并且每个实例的生命周期都很长。您现在遇到了上述情况。 (您还想跟踪抽象成员,这可以通过 protected 跟踪源来完成...这在 F# 中不可用。并且您想跟踪一些模块函数。这就是我选择上述分发模型的原因。如果您这样做任何其他方式你都将很难浏览日志。)
最佳答案
我还没有测试过这个,但看起来它会起作用。 TraceSource
上的 TraceXXX
方法接受 id
参数。将其用作“实例标识符”怎么样?然后,您可以编写一个自定义跟踪监听器来根据该 ID 重定向输出。也许这将作为一个起点:
type MultiOutputTraceListener(directory) =
inherit TraceListener()
let mutable output : TextWriter = null
let writers = Dictionary()
let setOutput (id: int) =
lock writers <| fun () ->
match writers.TryGetValue(id) with
| true, w -> output <- w
| _ ->
let w = new StreamWriter(Path.Combine(directory, id.ToString() + ".log"))
writers.Add(id, w)
output <- w
override x.Write(msg: string) = output.Write(msg)
override x.WriteLine(msg: string) = output.WriteLine(msg)
override x.TraceData(eventCache, source, eventType, id, data: obj) =
setOutput id
base.TraceData(eventCache, source, eventType, id, data)
override x.TraceData(eventCache, source, eventType, id, data) =
setOutput id
base.TraceData(eventCache, source, eventType, id, data)
override x.TraceEvent(eventCache, source, eventType, id, message) =
setOutput id
base.TraceEvent(eventCache, source, eventType, id, message)
override x.TraceEvent(eventCache, source, eventType, id, format, args) =
setOutput id
base.TraceEvent(eventCache, source, eventType, id, format, args)
override x.Dispose(disposing) =
if disposing then
for w in writers.Values do
w.Dispose()
使用
module Tracing =
let Source = TraceSource("MyTraceSource")
type A(id) =
member x.M() =
Tracing.Source.TraceEvent(TraceEventType.Verbose, id, "Entering method M()")
...
let a1 = A(1)
let a2 = A(2)
关于.net - 在多线程环境中使用TraceSource,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11397654/