log4net을 처음부터 프로그래밍 방식으로 구성하는 방법 (구성 없음)


87

이것은 나쁜 생각이지만, 구성 파일없이 처음부터 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을 구성하는 방법에 대한 좋은 참조가 있습니까?


답변:


37

이전에이 작업을 수행 한 한 가지 방법은 구성 파일을 포함 된 리소스로 포함하고 방금 log4net.Config.Configure (Stream)을 사용하는 것 입니다.

이렇게하면 익숙한 구성 구문을 사용할 수 있고 파일 배포에 대해 걱정할 필요가 없습니다.


2
전체 메서드 이름은 log4net.Config.XmlConfigurator.Configure입니다 (링크 참조)
olorin

122

다음은 코드에서 완전히 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");
    }
}

}


6
+1, 구성 파일없이 순전히 프로그래밍 방식으로 수행하는 방법에 대한 답을 얻은 것 같습니다.
Wil P

물론, 여전히 그러나 아무것도 :( 여기에 기록되지 않습니다, 빈 텍스트 파일이 생성되고, 작동하지 않았다
이반 G.

8
일을 위해 hierarchy.Configured = true;하는 나를 위해 트릭을 수행
FIRO

1
나를위한 트릭은 roller.ActivateOptions () ... 약간의 어두운 부두입니다.
Asaf 2015 년

1
@Legends "dnsservices.txt"는 로그 파일의 상대 이름입니다. 현재 작업 디렉토리에 상대적인 것 같습니다. 로그가 항상 알려진 디렉토리로 이동하도록 사용자 시스템의 절대 경로로 변경했습니다.
Colm Bhandal

32

더 간결한 솔루션 :

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가 호출 될 때까지이 개체는 정의되지 않은 상태에 있으며 사용해서는 안됩니다.


BasicConfigurator.Configure (IAppender) 오버로드를 사용하면 많은 혼란을 덜 수 있습니다.
Shaun

1
그 하나에 +1. 전화 ActivateOptions()가 확실히 누락되었거나 적어도 문서에서 충분히 지적되지 않았습니다.
fbmd

5

조나단은 말한다, 자원을 사용하는 것은 좋은 솔루션입니다.

포함 된 리소스 내용이 컴파일 타임에 고정된다는 점에서 약간 제한적입니다. appSettings로 정의 된 변수를 사용하여 기본 Log4Net 구성으로 XmlDocument를 생성하는 로깅 구성 요소가 있습니다 (예 : RollingFileAppender의 파일 이름, 기본 로깅 수준, AdoNetAppender를 사용하려는 경우 연결 문자열 이름). 그런 다음 log4net.Config.XmlConfigurator.Configure생성 된 XmlDocument의 루트 요소를 사용하여 Log4Net을 구성하도록 호출 합니다.

그런 다음 관리자는 몇 가지 appSettings (일반적으로 수준, 파일 이름 등)를 수정하여 "표준"구성을 사용자 지정하거나 더 많은 제어를 위해 외부 구성 파일을 지정할 수 있습니다.


3

Todd Stout의 대답에 표시된 매우 중요한 apndr.ActivateOptions ()가 " '등등 ..."에 포함되어 있는지 질문의 코드 조각에서 말할 수 없습니다. ActivateOptions ()없이 Appender는 비활성 상태이며 실패 이유를 설명 할 수있는 작업을 수행하지 않습니다.


나는 거기에 그것을 가지고 있다고 생각하지 않습니다. 그게 문제 였을 수 있습니다. 감사.
John M Gant

3

파티에 좀 늦었어요. 그러나 여기 저에게 일한 최소한의 구성이 있습니다.

샘플 클래스

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

2
거의 작동하지만 완전히 작동하기 전에 PatternLayout 및 Appender에서 .ActiveOptions를 호출해야했습니다.
cjb110

이유가 확실하지 않습니다. 그것은 나를 위해 일했습니다. 아마도 다른 버전을 사용했을 것입니다.
oleksii 2013-06-20

2

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
  }
}

1

// 세 개의 구성 파일을 포함 리소스로 포함하고 다음과 같이 액세스합니다.

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);
      }

    }
  }
}

0

BasicConfigurator.Configure(apndr)작동하지 않은 것이 이상합니다 . 제 경우에는 그 일을했습니다 ... 그러나 어쨌든 여기에 대답이 있습니다 hier.Configured = true;. 모든 설정을 마친 후에 (C # 코드)를 작성해야합니다 .



0

다음은 파일 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

0

'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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.