为了消除人为错误并避免维护谁知道多少App.config
个文件,我决定在运行时设置所有Quartz.NET作业的Log4Net配置,完全在码。不允许App.config
个文件。我已经成功地获得了一个独立的控制台应用程序来执行此操作,如here所示。
然而,在调度程序本身中它是一个不同的故事。由于某种原因,它没有使用我指定的配置:
Dim oProperties As New NameValueCollection
' ... Set Quartz.NET properties here
BasicConfigurator.Configure(New Logger.DbAppender)
With New StdSchedulerFactory(oProperties)
Manager.Scheduler = .GetScheduler
End With
我将它作为TopShelf服务运行,我希望Scheduler
的日志与每个IJob
的目标相同。在这里,Quartz.NET顽固地继续将其输出发送到TopShelf的调试控制台窗口(STDOUT)。
此构造在控制台应用程序中工作(上面链接);为什么不在这里工作?
答案 0 :(得分:1)
好的,明白了。 (这次是真实的。)
澄清:当在TopShelf / Quartz.NET组合下运行时,在.config
中发生在没有Common.Logging
文件的情况下对日志记录的抑制。由于某种原因,它始终拒绝识别运行时加载的Appender
,即使服务中的第一行代码配置日志记录也是如此。仍然是一个谜,但并不重要。 (至少不适合我,这个最新的发现 - YMMV。)
唯一被抑制的日志记录是在Common.Logging
库本身的构建和拆除之后;服务本身发生的所有事情仍然会被记录下来。
我能够使用下面的代码使其工作(当然,结合上面链接的代码)。
正如我所说,YMMV。
[服务]
Public Module Main
Sub Main()
Try
BasicConfigurator.Configure(New Logger.DbAppender("ConnectionString"))
Logger = LogManager.GetLogger(GetType(Main))
Environment.ExitCode = HostFactory.Run(Sub(Configurator)
Configurator.Service(Of Manager)(Sub(Service)
Service.ConstructUsing(Function(Factory) As ServiceControl
Return New Manager
End Function)
Service.WhenStarted(Function(Manager, HostControl) As Boolean
Return Manager.StartService(HostControl)
End Function)
Service.WhenStopped(Function(Manager, HostControl) As Boolean
Return Manager.StopService(HostControl)
End Function)
End Sub)
Configurator.SetDescription(ServiceInfo.Description)
Configurator.SetServiceName(ServiceInfo.Product)
Configurator.SetDisplayName(ServiceInfo.Title)
Configurator.StartAutomatically()
Configurator.RunAsLocalSystem()
End Sub)
Catch ex As Exception
EventLog.WriteEntry(ServiceInfo.Product, ex.Message, EventLogEntryType.Error, 1, 1, ex.ToBytes)
End Try
End Sub
Public Property Logger As ILog
End Module
[DbAppender](更新w / add'l构造函数,接受连接字符串)
Public Class DbAppender
Inherits AdoNetAppender
Public Sub New()
Me.New(String.Empty)
End Sub
Public Sub New(ConnectionString As String)
If Trim(ConnectionString) <> String.Empty Then
MyBase.ConnectionString = ConnectionString
End If
MyBase.CommandText = Me.CommandText
MyBase.BufferSize = 1
Me.Parameters.ForEach(Sub(Parameter As DbParameter)
MyBase.AddParameter(Parameter)
End Sub)
Me.ActivateOptions()
End Sub
Protected Overrides Function CreateConnection(ConnectionType As Type, ConnectionString As String) As IDbConnection
Return MyBase.CreateConnection(GetType(System.Data.SqlClient.SqlConnection), MyBase.ConnectionString)
End Function
Private Overloads ReadOnly Property CommandText As String
Get
Dim _
sColumns,
sValues As String
sColumns = Join(Me.Parameters.Select(Function(P As DbParameter) P.DbColumn).ToArray, ",")
sValues = Join(Me.Parameters.Select(Function(P As DbParameter) P.ParameterName).ToArray, ",")
Return COMMAND_TEXT.ToFormat(sColumns, sValues)
End Get
End Property
Private ReadOnly Property Parameters As List(Of DbParameter)
Get
Parameters = New List(Of DbParameter)
Parameters.Add(Me.Date)
Parameters.Add(Me.Thread)
Parameters.Add(Me.Level)
Parameters.Add(Me.Source)
Parameters.Add(Me.Message)
Parameters.Add(Me.Exception)
End Get
End Property
Private ReadOnly Property [Date] As DbParameter
Get
Return New DbParameter("Date", New DbPatternLayout(PATTERN_DATE), DbType.Date, 0)
End Get
End Property
Private ReadOnly Property Thread As DbParameter
Get
Return New DbParameter("Thread", New DbPatternLayout(PATTERN_THREAD), DbType.String, 255)
End Get
End Property
Private ReadOnly Property Level As DbParameter
Get
Return New DbParameter("Level", New DbPatternLayout(PATTERN_LEVEL), DbType.String, 50)
End Get
End Property
Private ReadOnly Property Source As DbParameter
Get
Return New DbParameter("Source", New DbPatternLayout(PATTERN_SOURCE), DbType.String, 255)
End Get
End Property
Private ReadOnly Property Message As DbParameter
Get
Return New DbParameter("Message", New DbPatternLayout(PATTERN_MESSAGE), DbType.String, 4000)
End Get
End Property
Private ReadOnly Property Exception As DbParameter
Get
Return New DbParameter("Exception", New DbExceptionLayout)
End Get
End Property
Private Const PATTERN_MESSAGE As String = "%message"
Private Const PATTERN_THREAD As String = "%thread"
Private Const PATTERN_SOURCE As String = "%logger.%M()"
Private Const PATTERN_LEVEL As String = "%level"
Private Const PATTERN_DATE As String = "%date{yyyy-MM-dd HH:mm:ss.fff}"
Private Const COMMAND_TEXT As String = "INSERT INTO Log ({0}) VALUES ({1})"
'======================================================================================
' Available patterns:
' http://logging.apache.org/log4net/release/sdk/log4net.Layout.PatternLayout.html
'======================================================================================
End Class
答案 1 :(得分:0)
好的,明白了。 (这没用多久!)
出于某种原因,如果缺少必要的App.config
条目,TopShelf / Quartz.NET组合会坚持抑制日志输出。
在这种情况下,由于它是我们处理的中央调度程序,而不是过多的工作,我会咬紧牙关并继续使用App.config
文件对于这一个。
所以根本问题仍未解决;这只是暂时的解决方法。如果您知道答案,我仍然很高兴收到您的回复。感谢。