Log4Net, come aggiungere un campo personalizzato alla mia registrazione


98

Uso l'appender log4net.Appender.AdoNetAppender.
La mia tabella log4net sono i seguenti campi[Date],[Thread],[Level],[Logger],[Message],[Exception]

Avrei bisogno di aggiungere un altro campo alla tabella log4net (ad esempio SalesId), ma come dovrei specificare nel mio xml e nel codice per registrare il "SalesId" quando registro un messaggio di errore o informazioni?

per esempio log.Info("SomeMessage", SalesId)

Ecco il log4net xml

  <appender name="SalesDBAppender" type="log4net.Appender.AdoNetAppender">
    <bufferSize value="1" />
    <connectionType value ="System.Data.SqlClient.SqlConnection" />
    <connectionString value="Data Source=..." />
    <commandText value="INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" />
    <parameter>
      <parameterName value="@log_date" />
      <dbType value="DateTime" />
      <layout type="log4net.Layout.RawTimeStampLayout" />
    </parameter>
    <parameter>
      <parameterName value="@thread" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%thread" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@log_level" />
      <dbType value="String" />
      <size value="50" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%level" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@logger" />
      <dbType value="String" />
      <size value="255" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%logger" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@message" />
      <dbType value="String" />
      <size value="4000" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%message" />
      </layout>
    </parameter>
    <parameter>
      <parameterName value="@exception" />
      <dbType value="String" />
      <size value="2000" />
      <layout type="log4net.Layout.ExceptionLayout" />
    </parameter>
  </appender>

Risposte:


190

1) Modifica il testo del comando: INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception],[MyColumn]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception, @CustomColumn)

2) Aggiungi la definizione del parametro per la colonna personalizzata:

<parameter>
   <parameterName value="@CustomColumn"/>
   <dbType value="String" />
   <size value="255" />
   <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%property{CustomColumn}" />
  </layout>
</parameter>

3) Quindi utilizzare uno dei contesti di log4net per trasferire i valori al parametro:

// thread properties...
log4net.LogicalThreadContext.Properties["CustomColumn"] = "Custom value";
log.Info("Message"); 

// ...or global properties
log4net.GlobalContext.Properties["CustomColumn"] = "Custom value";

2
Qualcuno può suggerire quale contesto è migliore per la registrazione delle funzionalità del browser.
VivekDev

1
@DumbDev, di solito utilizzerai il contesto Thread. Il GlobalContext è utile per impostare proprietà che non cambiano molto spesso.
Marcelo De Zen

1
Dovresti fare molta attenzione quando usi ThreadContext in un'applicazione Web, poiché questi tendono a saltare i thread e ThreadContext non verrà spostato insieme ad esso.
Robba

4
@theberserker LogicalThreadContextpuò essere utilizzato con Tasks, ma non è corretto ThreadContext, perché è sempre limitato a un thread particolare.
Marcelo De Zen

5
È la mia opinione, ma sembra un po 'strano in questo modo, mi aspettavo un sovraccarico che richiede più argomenti da aggiungere alla nuova istanza LoggingEvent ..
A77

6

Tre tipi di contesto di registrazione disponibili in Log4Net.

  1. Log4Net.GlobalContext: - Questo contesto è condiviso tra tutti i thread e i domini dell'applicazione. Se due thread impostano la stessa proprietà su GlobalContext, un valore sovrascriverà l'altro.

  2. Log4Net.ThreadContext: - Questo ambito di contesto è limitato al thread chiamante. Qui due thread possono impostare la stessa proprietà su valori diversi senza sovrascrivere l'un l'altro.

  3. Log4Net.ThreadLogicalContext: - Questo contesto si comporta in modo simile al ThreadContext. se stai lavorando con un algoritmo di pool di thread personalizzato o ospitando il CLR, potresti trovare qualche utilità per questo.

Aggiungi il codice seguente al tuo file program.cs:

static void Main( string[] args )
{
    log4net.Config.XmlConfigurator.Configure();
    log4net.ThreadContext.Properties[ "myContext" ] = "Logging from Main";
    Log.Info( "this is an info message" );
    Console.ReadLine();
}

2) Aggiungi la definizione del parametro per la colonna personalizzata:

  <log4net>      
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%logger (%property{myContext}) [%level]- %message%newline" />
      </layout>
    </appender> 
  </log4net>

3

Ecco una versione funzionante con alcune preferenze personalizzate. Ho aggiunto una colonna personalizzata per memorizzare un codice di eccezione generato.

1) Aggiungi la tua colonna personalizzata (codice eccezione qui) alla configurazione di Log4net:

<commandText value="INSERT INTO Log([Date],[Thread],[Level],[Logger],[Message],[Exception],[ExceptionCode]) 
VALUES (@log_date, @thread, @log_level, @logger, @message, @exception,@exceptionCode)" />

<parameter>
    <parameterName value="@exceptionCode" />
    <dbType value="String" />
    <size value="11" />
    <layout type="Common.Utils.LogHelper.Log4NetExtentedLoggingPatternLayout">
        <conversionPattern value="%exceptionCode{Code}" />
    </layout>
</parameter>

2) Log4NetExtentedLoggingCustomParameters.cs

namespace Common.Utils.LogHelper
{
    public class Log4NetExtentedLoggingCustomParameters
    {
        public string ExceptionCode { get; set; }

        public string Message { get; set; }

        public override string ToString()
        {
            return Message;
        }
    }
}

3) Log4NetExtentedLoggingPatternConverter.cs

namespace Common.Utils.LogHelper
{
    public class Log4NetExtentedLoggingPatternConverter : PatternConverter
    {
        protected override void Convert(TextWriter writer, object state)
        {
            if (state == null)
            {
                writer.Write(SystemInfo.NullText);
                return;
            }

            var loggingEvent = state as LoggingEvent;
            var messageObj = loggingEvent.MessageObject as Log4NetExtentedLoggingCustomParameters;

            if (messageObj == null)
            {
                writer.Write(SystemInfo.NullText);
            }
            else
            {
                switch (this.Option.ToLower()) //this.Option = "Code"
                {
                    case "code": //config conversionPattern parameter -> %exceptionCode{Code}
                        writer.Write(messageObj.ExceptionCode);
                        break;  
                    default:
                        writer.Write(SystemInfo.NullText);
                        break;
                }
            }
        }
    }
}

4) Log4NetExtentedLoggingPatternLayout.cs

namespace Common.Utils.LogHelper
{
    public class Log4NetExtentedLoggingPatternLayout : PatternLayout
    {
        public Log4NetExtentedLoggingPatternLayout()
        {
            var customConverter = new log4net.Util.ConverterInfo()
            {
                Name = "exceptionCode",
                Type = typeof(Log4NetExtentedLoggingPatternConverter)
            };

            AddConverter(customConverter);
        }
    }
}

5) Logger.cs // Goditi il ​​tuo logger con la nuova colonna! :)

namespace Common.Utils.LogHelper
{
    public class Logger
    {
        static ILog Logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public static string LogError(string message, Exception exception = null)
        {
            var logWithErrCode = GetLogWithErrorCode(message);
            Logger.Error(logWithErrCode, exception);
            return logWithErrCode.ExceptionCode;
        }

        private static Log4NetExtentedLoggingCustomParameters GetLogWithErrorCode(string message)
        {
            var logWithErrCode = new Log4NetExtentedLoggingCustomParameters();
            logWithErrCode.ExceptionCode = GenerateErrorCode(); //this method is absent for simplicity. Use your own implementation
            logWithErrCode.Message = message;
            return logWithErrCode;
        }
    }
}

Riferimenti:

http://blog.stvjam.es/2014/01/logging-custom-objects-and-fields-with

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.