Cách định cấu hình log4net lập trình từ đầu (không có cấu hình)


87

Đây là một Ý tưởng Xấu, tôi biết, nhưng ... tôi muốn định cấu hình log4net theo lập trình từ đầu mà không có tệp cấu hình. Tôi đang làm việc trên một ứng dụng ghi nhật ký đơn giản để tôi và nhóm của tôi sử dụng cho một loạt các ứng dụng phòng ban tương đối nhỏ mà chúng tôi chịu trách nhiệm. Tôi muốn tất cả họ đăng nhập vào cùng một cơ sở dữ liệu. Ứng dụng ghi nhật ký chỉ là một trình bao bọc xung quanh log4net với AdoNetAppender được cấu hình sẵn.

Tất cả các ứng dụng đều được triển khai ClickOnce, điều này gây ra một vấn đề nhỏ khi triển khai tệp cấu hình. Nếu tệp cấu hình là một phần của dự án cốt lõi, tôi có thể đặt các thuộc tính của nó để triển khai cùng với assembly. Nhưng nó là một phần của ứng dụng được liên kết, vì vậy tôi không có tùy chọn triển khai nó với ứng dụng chính. (Nếu điều đó không đúng, ai đó vui lòng cho tôi biết).

Có thể vì đó là một Ý tưởng Xấu, dường như không có nhiều mã mẫu để định cấu hình log4net theo chương trình từ đầu. Đây là những gì tôi có cho đến nay.

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

Sau khi định cấu hình tất cả các tham số cho apndr, lần đầu tiên tôi đã thử điều này ...

Dim hier As Hierarchy = DirectCast(LogManager.GetRepository(), Hierarchy)
hier.Root.AddAppender(apndr)

Nó không hoạt động. Sau đó, như một cảnh quay trong bóng tối, tôi đã thử điều này thay thế.

BasicConfigurator.Configure(apndr)

Điều đó cũng không hoạt động. Có ai có bất kỳ tài liệu tham khảo tốt nào về cách định cấu hình log4net lập trình từ đầu mà không có tệp cấu hình không?


Câu trả lời:


37

Một cách tôi đã làm trước đây là bao gồm tệp cấu hình dưới dạng tài nguyên nhúng và chỉ sử dụng log4net.Config.Configure (Luồng) .

Bằng cách đó, tôi có thể sử dụng cú pháp cấu hình mà tôi đã quen thuộc và không phải lo lắng về việc triển khai tệp.


2
Tên phương pháp hoàn toàn là log4net.Config.XmlConfigurator.Configure (như trong link)
olorin

122

Đây là một lớp ví dụ tạo cấu hình log4net hoàn toàn bằng mã. Tôi nên đề cập rằng việc tạo một trình ghi nhật ký thông qua một phương pháp tĩnh thường được xem là không tốt, nhưng trong bối cảnh của tôi, đây là điều tôi muốn. Bất kể, bạn có thể khắc mã để đáp ứng nhu cầu của mình.

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 từ tôi, có vẻ như bạn đã có câu trả lời ở đây về cách thực hiện điều này hoàn toàn theo chương trình mà không cần tệp cấu hình.
Wil P

tốt, nó vẫn không làm việc, tập tin văn bản trống được tạo ra, tuy nhiên không có gì được ghi vào nó :(
Ivan G.

8
+1 cho hierarchy.Configured = true;cái nào thực hiện thủ thuật cho tôi
Firo

1
Bí quyết đối với tôi là con lăn.ActivateOptions () ... Một số Voodoo đen tối.
Asaf

1
@Leosystem "dnsservices.txt" chỉ là tên tương đối cho tệp nhật ký của bạn. Có vẻ là tương đối với dir làm việc hiện tại. Tôi đã thay đổi nó thành một đường dẫn tuyệt đối trên hệ thống của người dùng để các bản ghi sẽ luôn chuyển đến một dir đã biết.
Colm Bhandal

32

Giải pháp ngắn gọn hơn:

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

Đừng quên gọi phương thức ActivateOptions :

Phương thức ActivateOptions phải được gọi trên đối tượng này sau khi các thuộc tính cấu hình đã được thiết lập. Cho đến khi ActivateOptions được gọi, đối tượng này ở trạng thái không xác định và không được sử dụng.


Sử dụng quá tải BasicConfigurator.Configure (IAppender) sẽ tiết kiệm được rất nhiều sự cố, chúc mừng.
Shaun

1
+1 cho cái đó. Cuộc gọi ActivateOptions()chắc chắn bị thiếu hoặc ít nhất là không được chỉ ra đủ trong tài liệu.
fbmd

5

Như Jonathan nói, sử dụng một nguồn lực là một giải pháp tốt.

Có một chút hạn chế là nội dung tài nguyên nhúng sẽ được sửa tại thời điểm biên dịch. Tôi có một thành phần ghi nhật ký tạo XmlDocument với cấu hình Log4Net cơ bản, sử dụng các biến được định nghĩa là appSettings (ví dụ: tên tệp cho RollingFileAppender, mức ghi nhật ký mặc định, có thể là tên chuỗi kết nối nếu bạn muốn sử dụng AdoNetAppender). Và sau đó tôi gọi log4net.Config.XmlConfigurator.Configuređể định cấu hình Log4Net bằng cách sử dụng phần tử gốc của XmlDocument đã tạo.

Sau đó, quản trị viên có thể tùy chỉnh cấu hình "tiêu chuẩn" bằng cách sửa đổi một vài appSettings (thường là cấp, tên tệp, ...) hoặc có thể chỉ định tệp cấu hình bên ngoài để kiểm soát nhiều hơn.


3

Tôi không thể biết trong đoạn mã của câu hỏi liệu "'Và v.v." có bao gồm apndr.ActivateOptions () rất quan trọng được chỉ ra trong câu trả lời của Todd Stout hay không. Nếu không có ActivateOptions (), Appender không hoạt động và sẽ không làm bất cứ điều gì có thể giải thích tại sao nó không thành công.


Tôi không nghĩ rằng tôi đã có điều đó trong đó. Đó có thể là vấn đề. Cảm ơn.
John M Gant

3

Hơi muộn cho bữa tiệc. Nhưng đây là một cấu hình tối thiểu phù hợp với tôi.

Lớp mẫu

public class Bar
{
    private readonly ILog log = LogManager.GetLogger(typeof(Bar));
    public void DoBar() { log.Info("Logged"); }
}

Cấu hình theo dõi log4net tối thiểu (bên trong thử nghiệm 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();
}

In cho trình nghe theo dõi

Namespace+Bar: Logged

2
Điều đó gần như hoạt động, nhưng tôi cần phải gọi .ActiveOptions trên PatternLayout và Appender trước khi nó hoạt động hoàn toàn.
cjb110

Không chắc chắn lý do tại sao. Nó hoạt động với tôi như nó vốn có, có lẽ chúng tôi đã sử dụng các phiên bản khác nhau.
oleksii

2

Tiến sĩ Netjes có điều này để thiết lập các kết nối theo chương trình:

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

// Tôi đã nhúng ba tệp cấu hình dưới dạng Tài nguyên được nhúng và truy cập chúng như sau:

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

Nó là lạ mà BasicConfigurator.Configure(apndr)không hoạt động. Trong trường hợp của tôi, nó đã thực hiện công việc của nó ... Nhưng, dù sao, đây là câu trả lời - bạn nên viết hier.Configured = true;(mã c #) sau khi bạn đã hoàn thành tất cả các thiết lập.



0

Đây là một ví dụ về cách bạn có thể tạo và sử dụng một AdoNetAdaptermã hoàn toàn bằng mã, hoàn toàn không có bất kỳ App.configtệp nào (thậm chí không cho Common.Logging). Hãy tiếp tục, xóa nó!

Điều này có thêm lợi ích là có khả năng chống lại các bản cập nhật theo quy ước đặt tên mới , trong đó tên hợp ngữ hiện phản ánh phiên bản. ( Common.Logging.Log4Net1213, v.v.)

[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
)

[Chủ yếu]

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

'Giải pháp cho 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.