动态设置web服务日志中的log4net文件名

本文关键字:log4net 文件名 日志 设置 web 服务 动态 | 更新日期: 2023-09-27 18:16:31

我在web服务中使用log4net,我想根据请求本身发送的用户参数设置每个请求的日志文件名。

我在配置

中定义了一个属性
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    <appender name="ClaimLog" type="log4net.Appender.RollingFileAppender">
      <file type="log4net.Util.PatternString" value="C:'projects'reports'ClaimRpt'Log'ClaimLog_%property{UserNameWCF}.txt" />

并将其设置在我的web方法

的开头
type ClaimServiceF() = 

    let log = LogManager.GetLogger("ClaimServiceF")

member this.BeginReport(sel: Model.Selection) : Model.RptResponse =
    GlobalContext.Properties.Item("UserNameWCF") <- sel.User
    let rptResp = new Model.RptResponse()
    log.Info("Started")
    match sel with
    | null -> 

我将f#库(SrvImplF.dll)包装在c# WCF项目中(为什么?)并使用Visual Studio的WCF测试客户端进行测试。

但是日志文件名仍然保持其初始值ClaimLog_(null).txt,即使我可以设置一个断点并看到sel.User被正确填充

我也尝试了从AppSettings

的AppSettings类型提供程序
  <appSettings>
    <add key="my_service_log" value="C:'projects'reports'ClaimRpt'Log'ClaimLog_{UserNameWCF}.txt" />
  </appSettings>
由编码

open FSharp.Configuration
type Settings = AppSettings<"app.config">

let appender = LogManager.GetRepository().GetAppenders() |> Seq.find(fun x -> x.Name.Equals("ClaimLog") ) :?> log4net.Appender.RollingFileAppender

appender.File <- Settings.MyServiceLog.Replace("{UserNameWCF}",sel.User)

但是-除了我需要在dll下创建一个虚构的app.config并在那里复制app键的事实之外,因为类型提供程序没有看到包装项目的app.config -它抛出异常

抛出异常:'System. '在SrvImplF.dll中的TypeInitializationException类型为"System"的异常。TypeInitializationException'发生在SrvImplF.dll,但未在用户代码中处理。的类型初始化项"FSharp.Configuration。AppSettingsTypeProvider'抛出异常。

我认为最后这只是我的类型提供程序配置中的一个小错误,无论如何也直接输入值

        let configFile = "C:'reports'ClaimRpt'Log'ClaimLog_{UserNameWCF}.txt" //Settings.MyServiceLog
        appender.File <- configFile.Replace("{UserNameWCF}",sel.User)

没有例外,但日志文件名保持不变ClaimLog_(null).txt

动态设置web服务日志中的log4net文件名

必须在设置属性后调用LogManager.GetLogger("ClaimServiceF")

请注意,您的方法容易出现竞争条件。如果多个客户机同时访问您的应用程序,您可能最终会记录到错误的文件。例如,假设两个并行请求的执行顺序如下:

// incoming request A
GlobalContext.Properties.Item("UserNameWCF") <- sel.User
// incoming request B
GlobalContext.Properties.Item("UserNameWCF") <- sel.User
// request A
var logger = LogManager.GetLogger("ClaimServiceF")
// logger has 'UserNameWCF' set to 'sel.User' of request B

要解决这个问题,可以考虑使用ThreadContext,它将属性"附加"或"作用域"到一个请求,因为每个请求都由一个单独的(池化的,重用的)线程处理。如果您使用async/await来设置属性并在同一线程中获取记录器,则要格外注意。