วิธีกำหนดค่า log4net โดยทางโปรแกรมตั้งแต่เริ่มต้น (ไม่มีการกำหนดค่า)


87

นี่เป็นความคิดที่ไม่ดีฉันรู้ แต่ ... ฉันต้องการกำหนดค่า log4net แบบเป็นโปรแกรมตั้งแต่เริ่มต้นโดยไม่มีไฟล์กำหนดค่า ฉันกำลังทำงานเกี่ยวกับแอปพลิเคชันการบันทึกอย่างง่ายสำหรับฉันและทีมของฉันเพื่อใช้สำหรับแอปพลิเคชันแผนกขนาดเล็กจำนวนมากที่เรารับผิดชอบ ฉันต้องการให้ทุกคนเข้าสู่ระบบฐานข้อมูลเดียวกัน แอปพลิเคชันการบันทึกเป็นเพียงเครื่องห่อหุ้มรอบ ๆ log4net ที่มีการกำหนดค่าล่วงหน้าของ AdoNetAppender

แอปพลิเคชันทั้งหมดถูกปรับใช้ 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 (สตรีม)

ด้วยวิธีนี้ฉันสามารถใช้ไวยากรณ์การกำหนดค่าที่ฉันคุ้นเคยและไม่ต้องกังวลกับการปรับใช้ไฟล์


2
ชื่อเมธอดที่สมบูรณ์คือ log4net.Config.XmlConfigurator.Configure (ตามลิงค์)
olorin

122

นี่คือคลาสตัวอย่างที่สร้าง log4net config โดยสมบูรณ์ในโค้ด ฉันควรพูดถึงว่าการสร้างคนตัดไม้ด้วยวิธีการคงที่มักถูกมองว่าไม่ดี แต่ในบริบทของฉันนี่คือสิ่งที่ฉันต้องการ ไม่ว่าคุณจะแกะรหัสตามความต้องการของคุณได้

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 จากฉันดูเหมือนว่าคุณจะได้รับคำตอบว่าจะทำอย่างไรโดยใช้โปรแกรมโดยไม่ใช้ไฟล์ config
Wil P

ยังใช้งานไม่ได้มีการสร้างไฟล์ข้อความว่าง แต่ไม่มีอะไรเขียนลงไป :(
Ivan G.

8
+1 hierarchy.Configured = true;ซึ่งเป็นเคล็ดลับสำหรับฉัน
Firo

1
เคล็ดลับสำหรับฉันคือ Roller.ActivateOptions () ... วูดูมืด
Asaf

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 การกำหนดค่า (IAppender) เกินพิกัดจะช่วยประหยัดความวุ่นวายได้มากไชโย
ฌอน

1
+1 สำหรับสิ่งนั้น การโทรActivateOptions()ขาดหายไปอย่างแน่นอนหรืออย่างน้อยก็ชี้ให้เห็นในเอกสารไม่เพียงพอ
fbmd

5

ดังที่โจนาธานกล่าวว่าการใช้ทรัพยากรเป็นทางออกที่ดี

มีข้อ จำกัด เล็กน้อยที่เนื้อหาทรัพยากรที่ฝังไว้จะได้รับการแก้ไขในเวลาคอมไพล์ ฉันมีส่วนประกอบการบันทึกที่สร้าง XmlDocument ด้วยการกำหนดค่า Log4Net พื้นฐานโดยใช้ตัวแปรที่กำหนดเป็น appSettings (เช่นชื่อไฟล์สำหรับ RollingFileAppender ระดับการบันทึกเริ่มต้นอาจเป็นชื่อสตริงการเชื่อมต่อหากคุณต้องการใช้ AdoNetAppender) จากนั้นฉันเรียกlog4net.Config.XmlConfigurator.Configureให้กำหนดค่า Log4Net โดยใช้องค์ประกอบรากของ XmlDocument ที่สร้างขึ้น

จากนั้นผู้ดูแลระบบสามารถปรับแต่งการกำหนดค่า "มาตรฐาน" ได้โดยแก้ไข appSettings สองสามอย่าง (โดยทั่วไปคือระดับชื่อไฟล์ ... ) หรือสามารถระบุไฟล์การกำหนดค่าภายนอกเพื่อให้สามารถควบคุมได้มากขึ้น


3

ฉันไม่สามารถบอกข้อมูลโค้ดของคำถามในข้อมูลโค้ดของคำถามได้หาก "" และอื่น ๆ ... "รวมถึง apndr.ActivateOptions () ที่สำคัญมากซึ่งระบุไว้ในคำตอบของ Todd Stout หากไม่มี 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
เกือบจะได้ผล แต่ฉันต้องเรียก. ActiveOptions บน PatternLayout และ Appender ก่อนที่จะทำงานได้อย่างสมบูรณ์
cjb110

ไม่แน่ใจว่าทำไม มันได้ผลสำหรับฉันเหมือนเดิมบางทีเราอาจใช้เวอร์ชันอื่น
oleksii

2

Netjesมีสิ่งนี้สำหรับการตั้งค่า connectionstring โดยทางโปรแกรม:

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