log4net을 처음부터 프로그래밍 방식으로 구성하는 방법 (구성 없음)
이것은 나쁜 생각이지만, 구성 파일없이 처음부터 log4net을 프로그래밍 방식으로 구성하고 싶습니다. 저는 저와 제 팀이 우리가 담당하는 비교적 작은 부서별 애플리케이션에 사용할 간단한 로깅 애플리케이션을 개발 중입니다. 모두 동일한 데이터베이스에 기록하기를 원합니다. 로깅 애플리케이션은 AdoNetAppender가 미리 구성된 log4net을 둘러싼 래퍼입니다.
모든 응용 프로그램은 ClickOnce가 배포되어 구성 파일 배포에 약간의 문제가 있습니다. 구성 파일이 핵심 프로젝트의 일부인 경우 어셈블리와 함께 배포 할 속성을 설정할 수 있습니다. 하지만 링크 된 애플리케이션의 일부이므로 기본 애플리케이션과 함께 배포 할 수있는 옵션이 없습니다. (그게 사실이 아니라면 누군가 알려주세요).
아마도 그것은 나쁜 생각이기 때문에 프로그래밍 방식으로 log4net을 처음부터 구성하는 데 사용할 수있는 샘플 코드가 많지 않은 것 같습니다. 지금까지 내가 가진 것입니다.
Dim apndr As New AdoNetAppender()
apndr.CommandText = "INSERT INTO LOG_ENTRY (LOG_DTM, LOG_LEVEL, LOGGER, MESSAGE, PROGRAM, USER_ID, MACHINE, EXCEPTION) VALUES (@log_date, @log_level, @logger, @message, @program, @user, @machine, @exception)"
apndr.ConnectionString = connectionString
apndr.ConnectionType = "System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
apndr.CommandType = CommandType.Text
Dim logDate As New AdoNetAppenderParameter()
logDate.ParameterName = "@log_date"
logDate.DbType = DbType.DateTime
logDate.Layout = New RawTimeStampLayout()
apndr.AddParameter(logDate)
Dim logLevel As New AdoNetAppenderParameter()
logLevel.ParameterName = "@log_level"
'And so forth...
에 대한 모든 매개 변수를 구성한 후 apndr
처음에는 이것을 시도했습니다.
Dim hier As Hierarchy = DirectCast(LogManager.GetRepository(), Hierarchy)
hier.Root.AddAppender(apndr)
작동하지 않았습니다. 그런 다음 어둠 속에서 촬영하기 위해 대신 이것을 시도했습니다.
BasicConfigurator.Configure(apndr)
그것도 작동하지 않았습니다. 누구든지 구성 파일없이 처음부터 프로그래밍 방식으로 log4net을 구성하는 방법에 대한 좋은 참조가 있습니까?
이전에이 작업을 수행 한 한 가지 방법은 구성 파일을 포함 된 리소스로 포함하고 방금 log4net.Config.Configure (Stream)을 사용하는 것 입니다.
이렇게하면 익숙한 구성 구문을 사용할 수 있고 파일 배포에 대해 걱정할 필요가 없습니다.
다음은 코드에서 완전히 log4net 구성을 생성하는 예제 클래스입니다. 정적 메서드를 통해 로거를 만드는 것은 일반적으로 나쁜 것으로 보이지만 내 맥락에서는 이것이 내가 원했던 것임을 언급해야합니다. 어쨌든 필요에 맞게 코드를 조각 할 수 있습니다.
using log4net;
using log4net.Repository.Hierarchy;
using log4net.Core;
using log4net.Appender;
using log4net.Layout;
namespace dnservices.logging
{
public class Logger
{
private PatternLayout _layout = new PatternLayout();
private const string LOG_PATTERN = "%d [%t] %-5p %m%n";
public string DefaultPattern
{
get { return LOG_PATTERN; }
}
public Logger()
{
_layout.ConversionPattern = DefaultPattern;
_layout.ActivateOptions();
}
public PatternLayout DefaultLayout
{
get { return _layout; }
}
public void AddAppender(IAppender appender)
{
Hierarchy hierarchy =
(Hierarchy)LogManager.GetRepository();
hierarchy.Root.AddAppender(appender);
}
static Logger()
{
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
TraceAppender tracer = new TraceAppender();
PatternLayout patternLayout = new PatternLayout();
patternLayout.ConversionPattern = LOG_PATTERN;
patternLayout.ActivateOptions();
tracer.Layout = patternLayout;
tracer.ActivateOptions();
hierarchy.Root.AddAppender(tracer);
RollingFileAppender roller = new RollingFileAppender();
roller.Layout = patternLayout;
roller.AppendToFile = true;
roller.RollingStyle = RollingFileAppender.RollingMode.Size;
roller.MaxSizeRollBackups = 4;
roller.MaximumFileSize = "100KB";
roller.StaticLogFileName = true;
roller.File = "dnservices.txt";
roller.ActivateOptions();
hierarchy.Root.AddAppender(roller);
hierarchy.Root.Level = Level.All;
hierarchy.Configured = true;
}
public static ILog Create()
{
return LogManager.GetLogger("dnservices");
}
}
}
더 간결한 솔루션 :
var layout = new PatternLayout("%-4timestamp [%thread] %-5level %logger %ndc - %message%newline");
var appender = new RollingFileAppender {
File = "my.log",
Layout = layout
};
layout.ActivateOptions();
appender.ActivateOptions();
BasicConfigurator.Configure(appender);
ActivateOptions 메서드 를 호출하는 것을 잊지 마십시오 .
구성 속성을 설정 한 후이 개체에서 ActivateOptions 메서드를 호출해야합니다. ActivateOptions가 호출 될 때까지이 개체는 정의되지 않은 상태에 있으며 사용해서는 안됩니다.
로 조나단은 말한다, 자원을 사용하는 것은 좋은 솔루션입니다.
포함 된 리소스 내용이 컴파일 타임에 고정된다는 점에서 약간 제한적입니다. appSettings로 정의 된 변수를 사용하여 기본 Log4Net 구성으로 XmlDocument를 생성하는 로깅 구성 요소가 있습니다 (예 : RollingFileAppender의 파일 이름, 기본 로깅 수준, AdoNetAppender를 사용하려는 경우 연결 문자열 이름). 그런 다음 log4net.Config.XmlConfigurator.Configure
생성 된 XmlDocument의 루트 요소를 사용하여 Log4Net을 구성하도록 호출 합니다.
그런 다음 관리자는 몇 가지 appSettings (일반적으로 수준, 파일 이름 등)를 수정하여 "표준"구성을 사용자 지정하거나 더 많은 제어를 얻기 위해 외부 구성 파일을 지정할 수 있습니다.
Todd Stout의 대답에 표시된 매우 중요한 apndr.ActivateOptions ()가 " '등등 ..."에 포함되어 있는지 질문의 코드 조각에서 말할 수 없습니다. ActivateOptions ()없이 Appender는 비활성 상태이며 실패 이유를 설명 할 수있는 작업을 수행하지 않습니다.
파티에 좀 늦었어요. 그러나 여기에 저에게 일한 최소한의 구성이 있습니다.
샘플 클래스
public class Bar
{
private readonly ILog log = LogManager.GetLogger(typeof(Bar));
public void DoBar() { log.Info("Logged"); }
}
최소 log4net 추적 구성 (NUnit 테스트 내부)
[Test]
public void Foo()
{
var tracer = new TraceAppender();
var hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.AddAppender(tracer);
var patternLayout = new PatternLayout {ConversionPattern = "%m%n"};
tracer.Layout = patternLayout;
hierarchy.Configured = true;
var bar = new Bar();
bar.DoBar();
}
추적 수신기에 인쇄합니다.
Namespace+Bar: Logged
Netjes 박사 는 다음과 같이 연결 문자열 을 프로그래밍 방식으로 설정합니다.
// Get the Hierarchy object that organizes the loggers
log4net.Repository.Hierarchy.Hierarchy hier =
log4net.LogManager.GetLoggerRepository() as log4net.Repository.Hierarchy.Hierarchy;
if (hier != null)
{
//get ADONetAppender
log4net.Appender.ADONetAppender adoAppender =
(log4net.Appender.ADONetAppender)hier.GetLogger("MyProject",
hier.LoggerFactory).GetAppender("ADONetAppender");
if (adoAppender != null)
{
adoAppender.ConnectionString =
System.Configuration.ConfigurationSettings.AppSettings["MyConnectionString"];
adoAppender.ActivateOptions(); //refresh settings of appender
}
}
// 세 개의 구성 파일을 포함 리소스로 포함하고 다음과 같이 액세스합니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Resources;
using System.IO;
namespace Loader
{
class Program
{
private static log4net.ILog CustomerLog = log4net.LogManager.GetLogger("CustomerLogging");
private static log4net.ILog OrderLog = log4net.LogManager.GetLogger("OrderLogging");
private static log4net.ILog DetailsLog = log4net.LogManager.GetLogger("OrderDetailLogging");
static void Main(string[] args)
{
// array of embedded log4net config files
string[] configs = { "Customer.config", "Order.config", "Detail.config"};
foreach (var config in configs)
{
// build path to assembly config
StringBuilder sb = new StringBuilder();
sb.Append(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
sb.Append(".");
sb.Append(config);
// convert to a stream
Stream configStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(sb.ToString());
// configure logger with ocnfig stream
log4net.Config.XmlConfigurator.Configure(configStream);
// test logging
CustomerLog.Info("Begin logging with: " + config);
OrderLog.Info("Begin logging with: " + config);
DetailsLog.Info("Begin logging with: " + config);
for (int iX = 0; iX < 10; iX++)
{
CustomerLog.Info("iX=" + iX);
OrderLog.Info("iX=" + iX);
DetailsLog.Info("iX=" + iX);
}
CustomerLog.Info("Ending logging with: " + config);
OrderLog.Info("Ending logging with: " + config);
DetailsLog.Info("Ending logging with: " + config);
}
}
}
}
BasicConfigurator.Configure(apndr)
작동하지 않은 것이 이상합니다 . 제 경우에는 그 일을했습니다 ... 그러나 어쨌든, 여기에 대답이 있습니다 hier.Configured = true;
. 모든 설정을 마친 후에 (C # 코드)를 작성해야합니다 .
나는 이것을 사용하여 결국 :
http://www.mikebevers.be/blog/2010/09/log4net-custom-adonetappender/
4 시간이 지나면 구성을 조작하고 점점 더 좌절감을 느낍니다.
누군가에게 도움이되기를 바랍니다.
다음은 파일 AdoNetAdapter
이없는 상태에서도 완전히 코드에서을 (를) 만들고 사용할 수있는 방법에 대한 수프-투-넛 예제입니다 . 어서 삭제하세요!App.config
Common.Logging
이렇게 하면 어셈블리 이름이 이제 버전을 반영하는 새로운 명명 규칙 하에서 업데이트에 대해 탄력적이라는 추가 이점이 있습니다 . ( Common.Logging.Log4Net1213
등)
[SQL]
CREATE TABLE [Log](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Date] [datetime] NOT NULL,
[Thread] [varchar](255) NOT NULL,
[Level] [varchar](20) NOT NULL,
[Source] [varchar](255) NOT NULL,
[Message] [varchar](max) NOT NULL,
[Exception] [varchar](max) NOT NULL
)
[본관]
Imports log4net
Imports log4net.Core
Imports log4net.Layout
Imports log4net.Config
Imports log4net.Appender
Module Main
Sub Main()
Dim oLogger As ILog
Dim sInput As String
Dim iOops As Integer
BasicConfigurator.Configure(New DbAppender)
oLogger = LogManager.GetLogger(GetType(Main))
Console.Write("Command: ")
Do
Try
sInput = Console.ReadLine.Trim
Select Case sInput.ToUpper
Case "QUIT" : Exit Do
Case "OOPS" : iOops = String.Empty
Case Else : oLogger.Info(sInput)
End Select
Catch ex As Exception
oLogger.Error(ex.Message, ex)
End Try
Console.Clear()
Console.Write("Command: ")
Loop
End Sub
End Module
[DbAppender]
Imports log4net
Imports log4net.Core
Imports log4net.Layout
Imports log4net.Appender
Imports log4net.Repository.Hierarchy
Public Class DbAppender
Inherits AdoNetAppender
Public Sub New()
MyBase.BufferSize = 1
MyBase.CommandText = Me.CommandText
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), "Data Source=(local);Initial Catalog=Logger;Persist Security Info=True;User ID=username;Password=password")
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 String.Format(COMMAND_TEXT, sColumns, sValues)
End Get
End Property
Private ReadOnly Property Parameters As List(Of DbParameter)
Get
Parameters = New List(Of DbParameter)
Parameters.Add(Me.LogDate)
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 LogDate As DbParameter
Get
Return New DbParameter("Date", DbType.Date, 0, New DbPatternLayout("%date{yyyy-MM-dd HH:mm:ss.fff}"))
End Get
End Property
Private ReadOnly Property Thread As DbParameter
Get
Return New DbParameter("Thread", DbType.String, 255, New DbPatternLayout("%thread"))
End Get
End Property
Private ReadOnly Property Level As DbParameter
Get
Return New DbParameter("Level", DbType.String, 50, New DbPatternLayout("%level"))
End Get
End Property
Private ReadOnly Property Source As DbParameter
Get
Return New DbParameter("Source", DbType.String, 255, New DbPatternLayout("%logger.%M()"))
End Get
End Property
Private ReadOnly Property Message As DbParameter
Get
Return New DbParameter("Message", DbType.String, 4000, New DbPatternLayout("%message"))
End Get
End Property
Private ReadOnly Property Exception As DbParameter
Get
Return New DbParameter("Exception", DbType.String, 2000, New DbExceptionLayout)
End Get
End Property
Private Const COMMAND_TEXT As String = "INSERT INTO Log ({0}) VALUES ({1})"
End Class
[DbParameter]
Imports log4net
Imports log4net.Core
Imports log4net.Layout
Imports log4net.Appender
Imports log4net.Repository.Hierarchy
Public Class DbParameter
Inherits AdoNetAppenderParameter
Private ReadOnly Name As String
Public Sub New(Name As String, Type As DbType, Size As Integer, Layout As ILayout)
With New RawLayoutConverter
Me.Layout = .ConvertFrom(Layout)
End With
Me.Name = Name.Replace("@", String.Empty)
Me.ParameterName = String.Format("@{0}", Me.Name)
Me.DbType = Type
Me.Size = Size
End Sub
Public ReadOnly Property DbColumn As String
Get
Return String.Format("[{0}]", Me.Name)
End Get
End Property
End Class
[DbPatternLayout]
Imports log4net
Imports log4net.Core
Imports log4net.Layout
Imports log4net.Appender
Imports log4net.Repository.Hierarchy
Public Class DbPatternLayout
Inherits PatternLayout
Public Sub New(Pattern As String)
Me.ConversionPattern = Pattern
Me.ActivateOptions()
End Sub
End Class
[DbExceptionLayout]
Imports log4net
Imports log4net.Core
Imports log4net.Layout
Imports log4net.Appender
Imports log4net.Repository.Hierarchy
Public Class DbExceptionLayout
Inherits ExceptionLayout
Public Sub New()
Me.ActivateOptions()
End Sub
End Class
'Vb.Net 용 솔루션
Private Shared EscanerLog As log4net.ILog = log4net.LogManager.GetLogger("Log4Net.Config")
Public Sub New(ByVal sIDSesion As String)
Dim sStream As Stream
Dim JsText As String
Using reader As New StreamReader((GetType(ClsGestorLogsTraza).Assembly).GetManifestResourceStream("Comun.Log4Net.Config"))
JsText = reader.ReadToEnd()
sStream = GenerateStreamFromString(JsText)
log4net.Config.XmlConfigurator.Configure(sStream)
End Using
End Sub
Public Function GenerateStreamFromString(ByVal s As String) As Stream
Dim stream = New MemoryStream()
Dim writer = New StreamWriter(stream)
writer.Write(s)
writer.Flush()
stream.Position = 0
Return stream
End Function
Public Function StreamFromResource(ByVal sFilename As String) As Stream
Dim nAssembly As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly()
Dim s As Stream = nAssembly.GetManifestResourceStream(System.Reflection.MethodBase.GetCurrentMethod.DeclaringType, sFilename)
Return s
End Function
'code' 카테고리의 다른 글
iOS 장치 만 대상으로하는 CSS 미디어 쿼리 (0) | 2020.09.18 |
---|---|
iOS 배포 서명 ID 누락 (0) | 2020.09.18 |
NIB 파일의 객체를 앞 / 뒤로 보내는 방법은 무엇입니까? (0) | 2020.09.18 |
REST API에 대한 온라인 문서 구조화 (0) | 2020.09.17 |
성과 시스템을 코딩하는 가장 좋은 방법 (0) | 2020.09.17 |