À quoi ressemblerait une classe Log4Net Wrapper?

j'ai cherché un cadre de journalisation pour .net (c#) et j'ai décidé de donner à log4net le feu vert après avoir lu quelques fils de questions/réponses ici sur stackoverflow. Je vois des gens dire et redire qu'ils utilisent une classe d'emballage pour log4net et je me demande à quoi cela ressemblerait.

j'ai mon code divisé en différents projets (data access/business/webservice/..). Comment un log4net classe wrapper? Serait la classe wrapper doivent être inclus dans tous les projets? Dois-je le construire comme un projet distinct tout ensemble?

L'emballage doit-il être une classe singleton?

55
demandé sur Zaid Masud 2008-10-03 15:39:24

9 réponses

essentiellement vous créez une interface et ensuite une implémentation concrète de cette interface qui enveloppe directement les classes et les méthodes de Log4net. D'autres systèmes de diagraphie peuvent être enveloppés en créant plus de classes de béton qui enveloppent d'autres classes et méthodes de ces systèmes. Enfin, utilisez une usine pour créer des instances de vos wrappers en fonction d'un paramètre de configuration ou d'une ligne de changement de code. (Note: vous pouvez obtenir plus flexible - et complexe-en utilisant une Inversion de Contrôle conteneur tel que StructureMap .)

public interface ILogger
{
    void Debug(object message);
    bool IsDebugEnabled { get; }

    // continue for all methods like Error, Fatal ...
}

public class Log4NetWrapper : ILogger
{
    private readonly log4net.ILog _logger;

    public Log4NetWrapper(Type type)
    {
        _logger = log4net.LogManager.GetLogger(type);
    }

    public void Debug(object message)
    {
        _logger.Debug(message);
    }

    public bool IsDebugEnabled
    {
        get { return _logger.IsDebugEnabled; }
    }

    // complete ILogger interface implementation
}

public static class LogManager
{
    public static ILogger GetLogger(Type type)
    {
        // if configuration file says log4net...
        return new Log4NetWrapper(type);
        // if it says Joe's Logger...
        // return new JoesLoggerWrapper(type);
    }
}

et un exemple d'utilisation de ce code dans vos classes (déclaré comme champ statique en lecture seule):

private static readonly ILogger _logger =
    LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

vous pouvez obtenir le même effet légèrement plus favorable à la performance en utilisant:

private static readonly ILogger _logger = 
    LogManager.GetLogger(typeof(YourTypeName));

le premier exemple est considéré comme pouvant être maintenu.

vous ne voudriez pas créer un Singleton pour gérer tous journalisation parce que Log4Net journalise pour le type d'invocation; son beaucoup plus propre et utile pour avoir chaque type utiliser son propre logger plutôt que de voir un seul type dans le fichier journal rapportant tous les messages.

parce que votre mise en œuvre devrait être assez réutilisable (d'autres projets dans votre organisation) vous pourriez en faire son propre assemblage ou idéalement l'inclure avec votre propre cadre personnel/organisation/assemblage utilitaire. Ne déclarez pas les cours séparément dans chacun de vos entreprise/data/UI assemblées, ce n'est pas facile à gérer.

49
répondu cfeduke 2008-10-03 12:06:23

en supposant que vous alliez avec quelque chose comme la réponse de cfeduke au-dessus de , vous pourriez aussi ajouter une surcharge à votre LogManager comme ceci:

public static ILogger GetLogger()
{
    var stack = new StackTrace();
    var frame = stack.GetFrame(1);
    return new Log4NetWrapper(frame.GetMethod().DeclaringType);
}

de cette façon dans votre code vous pouvez maintenant utiliser:

private static readonly ILogger _logger = LogManager.GetLogger();

au lieu de:

private static readonly ILogger _logger =
    LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly ILogger _logger = 
    LogManager.GetLogger(typeof(YourTypeName));

, qui est en fait l'équivalent de la première variante (c'est-à-dire celle qui utilise MethodBase.GetCurrentMethod().DeclaringType ), un peu plus simple.

24
répondu Alconja 2017-05-23 11:53:44

Quels sont les avantages que vous prévoyez de retirer de l'écriture d'un wrapper pour log4net. Je recommande de se familiariser avec les cours de log4net avant d'écrire un papier d'emballage autour d'eux. cfeduke a raison dans sa réponse sur la façon d'écrire ledit wrapper, mais à moins que vous ayez besoin d'ajouter une fonctionnalité réelle à son exemple, un wrapper ne réussirait qu'à ralentir le processus de journalisation et à ajouter de la complexité pour les futurs responsables. Cela est particulièrement vrai lorsque les outils de recadrage disponibles dans. Net de tels changements super facile.

5
répondu 2008-10-03 12:30:30

j'ai réussi à isoler la dépendance à log4net en un seul projet. Si vous avez l'intention de faire la même chose, voici à quoi ressemble ma classe d'emballage:

using System;

namespace Framework.Logging
{
    public class Logger
    {
        private readonly log4net.ILog _log;

        public Logger()
        {
            _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        }

        public Logger(string name)
        {
            _log = log4net.LogManager.GetLogger(name);
        }

        public Logger(Type type)
        {
            _log = log4net.LogManager.GetLogger(type);
        }

        public void Debug(object message, Exception ex = null)
        {
            if (_log.IsDebugEnabled)
            {
                if (ex == null)
                {
                    _log.Debug(message);
                }
                else
                {
                    _log.Debug(message, ex);
                }
            }
        }

        public void Info(object message, Exception ex = null)
        {
            if (_log.IsInfoEnabled)
            {
                if (ex == null)
                {
                    _log.Info(message);
                }
                else
                {
                    _log.Info(message, ex);
                }
            }
        }

        public void Warn(object message, Exception ex = null)
        {
            if (_log.IsWarnEnabled)
            {
                if (ex == null)
                {
                    _log.Warn(message);
                }
                else
                {
                    _log.Warn(message, ex);
                }
            }
        }

        public void Error(object message, Exception ex = null)
        {
            if (_log.IsErrorEnabled)
            {
                if (ex == null)
                {
                    _log.Error(message);
                }
                else
                {
                    _log.Error(message, ex);
                }
            }
        }

        public void Fatal(object message, Exception ex = null)
        {
            if (_log.IsFatalEnabled)
            {
                if (ex == null)
                {
                    _log.Fatal(message);
                }
                else
                {
                    _log.Fatal(message, ex);
                }
            }
        }
    }
}

et n'oubliez pas d'ajouter ceci dans le AssemblyInfo.cs du projet d'interfaçage (ça m'a pris quelques heures pour le trouver)

[assembly: log4net.Config.XmlConfigurator(Watch = true, ConfigFile = "log4net.config")]

et mettez votre configuration log4net xml dans le fichier log4net.config , définissez-le comme Content , Copy Always

1
répondu Jeson Martajaya 2016-02-02 22:23:00

Ma compréhension est qu'une classe wrapper pour log4net serait une classe statique qui prend soin de l'initialisation de l'objet connexion à partir de l'app.config / web.configuration ou par code (par exemple intégration avec NUnit).

0
répondu devio 2008-10-03 11:45:47

une utilisation possible pour un wrapper log4net pourrait être une classe qui obtient la classe d'appel et la méthode via la réflexion pour avoir une idée de l'endroit où votre entrée de journalisation s'est produite. au moins je l'utiliser fréquemment.

0
répondu Joachim Kerschbaumer 2008-10-03 11:45:49

Alconja, j'aime votre idée d'utiliser le stacktrace pour revenir à la méthode d'appel. Je pensais à encapsuler davantage les appels, non seulement pour récupérer l'objet logger, mais pour effectuer réellement la journalisation. Ce que je veux, c'est une classe statique qui gère la journalisation, en faisant des abstractions à partir de l'implémentation spécifique utilisée. C'est-à-dire:

LoggingService.LogError("my error message");

de cette façon je n'ai besoin de changer les internes de la classe statique, si je décide plus tard d'utiliser un autre système de journalisation.

donc j'ai utilisé votre idée pour obtenir l'objet appelant en utilisant la trace de la pile:

public static class LoggingService
{
    private static ILog GetLogger()
    {    
        var stack = new StackTrace();    
        var frame = stack.GetFrame(2);    
        return log4net.LogManager.GetLogger(frame.GetMethod().DeclaringType);
    }

    public static void LogError(string message)
    {
        ILog logger = GetLogger();
        if (logger.IsErrorEnabled)
            logger.Error(message);
    }
    ...
}

quelqu'un voit un problème avec cette approche?

0
répondu Tim S. Van Haren 2010-01-15 14:43:02

il y a des cadres comme le Prism Library pour WPF qui promeuvent l'utilisation d'un façade pour le cadre de journalisation de votre choix.

il s'agit d'un exemple qui utilise log4net :

using System;
using log4net;
using log4net.Core;
using Prism.Logging;

public class Log4NetLoggerFacade : ILoggerFacade
{
    private static readonly ILog Log4NetLog = LogManager.GetLogger(typeof (Log4NetLoggerFacade));

    public void Log(string message, Category category, Priority priority)
    {
        switch (category)
        {
            case Category.Debug:
                Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade), Level.Debug, message, null);
                break;
            case Category.Exception:
                Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade), Level.Error, message, null);
                break;
            case Category.Info:
                Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade), Level.Info, message, null);
                break;
            case Category.Warn:
                Log4NetLog.Logger.Log(typeof(Log4NetLoggerFacade), Level.Warn, message, null);
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(category), category, null);
        }
    }
}

notez qu'en spécifiant le callerStackBoundaryDeclaringType vous pouvez toujours obtenir le nom de classe de l'appelant émettant la demande de journalisation. Tout ce que vous devez faire est de inclure %C %M dans votre modèle de conversion:

<layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %C.%M - %message%newline" />
</layout>

cependant, comme la documentation avertit, la génération de l'information de la classe de l'appelant est lente, donc il doit être utilisé avec sagesse.

0
répondu Leonardo 2016-07-15 15:50:18

je sais que cette réponse est tardive, mais elle peut aider quelqu'un dans le futur.

il semble que vous vouliez une API programmatique que XQuiSoft Logging vous donne. Vous n'avez pas à spécifier quel logger vous voulez avec XQuiSoft. c'est aussi simple que cela:

du Journal.Écrire(De Niveau.Verbeux, "source", "catégorie", "votre message ici");

ensuite, via la configuration, vous dirigez les messages par source, catégorie, niveau, ou tout autre filtre personnalisé vers différents emplacements (fichiers, e-mails, etc...).

voir cet article pour une introduction.

-3
répondu Michael 2012-12-15 20:59:22