Log4net'i programlı olarak sıfırdan yapılandırma (yapılandırma yok)


87

Bu Kötü bir Fikir, biliyorum, ama ... log4net'i hiçbir yapılandırma dosyası olmadan programlı olarak sıfırdan yapılandırmak istiyorum. Sorumlu olduğumuz bir grup nispeten küçük departman uygulamasında kullanmak üzere kendim ve ekibim için basit bir günlük kaydı uygulaması üzerinde çalışıyorum. Hepsinin aynı veritabanında oturum açmasını istiyorum. Günlük uygulaması, önceden yapılandırılmış AdoNetAppender ile log4net etrafındaki bir sarmalayıcıdır.

Tüm uygulamalar ClickOnce dağıtılmıştır, bu da yapılandırma dosyasının dağıtımında küçük bir sorun oluşturur. Yapılandırma dosyası çekirdek projenin parçasıysa, özelliklerini derleme ile dağıtılacak şekilde ayarlayabilirdim. Ancak bu bağlantılı bir uygulamanın parçası, bu yüzden onu ana uygulamayla dağıtma seçeneğim yok. (Bu doğru değilse lütfen birisi bana haber versin).

Muhtemelen kötü bir fikir olduğu için, log4net'i sıfırdan programlı olarak yapılandırmak için çok fazla örnek kod yok gibi görünüyor. İşte şimdiye kadar sahip olduğum şeyler.

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

İçin tüm parametreleri yapılandırdıktan sonra apndr, ilk başta bunu denedim ...

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

İşe yaramadı. Sonra karanlıkta bir atış olarak bunu denedim.

BasicConfigurator.Configure(apndr)

Bu da işe yaramadı. Log4net'i hiçbir yapılandırma dosyası olmadan programlı olarak sıfırdan nasıl yapılandıracağına dair iyi referansları olan var mı?


Yanıtlar:


37

Bunu geçmişte yaptığım bir yol, yapılandırma dosyasını gömülü bir kaynak olarak dahil etmek ve sadece log4net.Config.Configure (Stream) kullanmaktı .

Bu şekilde, aşina olduğum yapılandırma sözdizimini kullanabilirim ve bir dosyanın dağıtılması konusunda endişelenmem gerekmiyordu.


2
Tam yöntem adı log4net.Config.XmlConfigurator.Configure şeklindedir (bağlantıdaki gibi)
olorin

122

İşte log4net yapılandırmasını tamamen kodda oluşturan örnek bir sınıf. Statik yöntemle kaydedici oluşturmanın genellikle kötü olarak görüldüğünü belirtmeliyim, ancak benim bağlamımda istediğim buydu. Ne olursa olsun, ihtiyaçlarınızı karşılamak için kodu düzenleyebilirsiniz.

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
Benden +1, görünen o ki, bunu yapılandırma dosyası olmadan tamamen programlı olarak nasıl yapacağınıza dair cevabı burada almışsınız gibi görünüyor.
Wil P

yine de çalışmadı, boş metin dosyası oluşturuldu, ancak üzerine hiçbir şey yazılmadı :(
Ivan G.

8
+1 hierarchy.Configured = true;hangisi benim için hile yapıyor
Firo

1
Benim için numara roller.ActivateOptions () ... Biraz karanlık Vudu.
Asaf

1
@Legends "dnsservices.txt", günlük dosyanız için göreli bir addır. Geçerli çalışma dizinine göre görünüyor. Günlüklerin her zaman bilinen bir dizine gitmesi için bunu kullanıcının sisteminde mutlak bir yola değiştirdim.
Colm Bhandal

32

Daha özlü çözüm:

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 yöntemini çağırmayı unutmayın :

ActivateOptions yöntemi, yapılandırma özellikleri ayarlandıktan sonra bu nesnede çağrılmalıdır. ActivateOptions çağrılana kadar bu nesne tanımlanmamış bir durumdadır ve kullanılmamalıdır.


BasicConfigurator.Configure (IAppender) aşırı yüklemesini kullanmak, çok fazla karışıklıktan kurtarır.
Shaun

1
Bunun için +1. Arama ActivateOptions()kesinlikle eksik veya en azından belgelerde yeterince belirtilmemiş.
fbmd

5

As Jonathan diyor, bir kaynağın kullanılarak iyi bir çözümdür.

Gömülü kaynak içeriklerinin derleme zamanında sabitleneceği için biraz kısıtlayıcıdır. AppSettings olarak tanımlanan değişkenleri kullanarak temel Log4Net yapılandırmasıyla bir XmlDocument oluşturan bir günlük kaydı bileşenim var (örneğin, RollingFileAppender için dosya adı, varsayılan günlük seviyesi, belki bir AdoNetAppender kullanmak istiyorsanız bağlantı dizesi adı). Ve sonra log4net.Config.XmlConfigurator.Configureoluşturulan XmlDocument'ın kök öğesini kullanarak Log4Net'i yapılandırmak için çağırıyorum .

Daha sonra yöneticiler, birkaç appSettings'i (tipik olarak seviye, dosya adı, ...) değiştirerek "standart" yapılandırmayı özelleştirebilir veya daha fazla kontrol elde etmek için harici bir yapılandırma dosyası belirleyebilir.


3

Sorunun kod pasajında ​​"'Ve diğerleri ..." nin Todd Stout'un cevabında belirtilen çok önemli apndr.ActivateOptions () öğesini içerip içermediğini anlayamıyorum. ActivateOptions () olmadan Appender inaktiftir ve neden başarısız olduğunu açıklayacak hiçbir şey yapmayacaktır.


Orada olduğunu sanmıyorum. Sorun bu olabilir. Teşekkürler.
John M Gant

3

Parti için biraz geç. Ama işte benim için işe yarayan minimal bir yapılandırma.

Örnek sınıf

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

Minimal log4net izleme yapılandırması (NUnit testi içinde)

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

İzleme dinleyicisine yazdırır

Namespace+Bar: Logged

2
Bu neredeyse işe yarıyor, ancak tam olarak çalışmadan önce PatternLayout ve Appender'da .ActiveOptions'ı aramam gerekiyordu.
cjb110

Emin değilim neden. Benim için olduğu gibi çalıştı, belki farklı versiyonlar kullandık.
oleksii

2

Dr. Netjes , bağlantı dizesini programlı olarak ayarlamak için buna sahiptir:

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

// Gömülü Kaynak olarak üç yapılandırma dosyası yerleştirdim ve bunlara şu şekilde eriştim:

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

İşe yaramaması garip BasicConfigurator.Configure(apndr). Benim durumumda işini yaptı ... Ama her neyse, işte cevap - hier.Configured = true;tüm kurulumu tamamladıktan sonra (c # kodu) yazmalıydın.



0

Burada AdoNetAdapter, tamamen herhangi bir App.configdosyanın yokluğunda (için bile değil Common.Logging) tamamen kod içinde nasıl oluşturup kullanabileceğinizi gösteren bir çorbadan fındığa örnek var . Devam edin, silin!

Bu, derleme adının artık sürümü yansıttığı yeni adlandırma kurallarına göre güncellemelere karşı dayanıklı olma avantajına sahiptir . ( Common.Logging.Log4Net1213vb.)

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

[Ana]

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 için Çözüm

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.