Name Last Update
..
ReadMe.md Loading commit data...

ReadMe.md

Vrh.Logger

Ez a leírás a komponens v2.1.0 kiadásáig bezáróan naprakész. Igényelt minimális framework verzió: 4.0 Teljes funkcionalitás és hatékonyság kihasználásához szükséges legalacsonyabb framework verzió: 4.5

A komponens arra szolgál, hogy egységes és egyszerű megvalósítása legyen a Logolásnak.

Pluginolható, a létező plugin megoldásaink a Vrh.Logger.PLUGINNAME komponens elnevezésekkel kerülnek implementációra.

Használata logoláshoz

A használathoz a Vrh.Logger névtér using-olandó.

VrhLogger static class:

Ez a static osztály adja a logoláshoz szükséges szűk eszközkészletet.

1. Log():

Ezt hívjuk meg, ha bármit logolni akarunk a környezetben.

Definíciója:

/// <summary>
/// Log bejegyzést ad fel (aszinkron!!!) a logoló modul számára
/// </summary>
/// <typeparam name="T">Típus</typeparam>
/// <param name="data">Log adat, meg kell feleljen a generikusan meghatározott típusnak, vagy ennek a típusa határozza meg a generikust, ha nem jelöljük explicit</param>
/// <param name="dataFields">A log bejegyzés adatai. Mezőnév/Mezőérték párok listájaként</param>
/// <param name="exception">Egy exception adható át a Lognak</param>
/// <param name="level">A logolás szintje. Az itt meghatározott szintűnek, vagy az alattinak kell a beállított logolási szintnek lennie, hogy a logolás meg is történjen a tényleges futási környezetben.</param>
/// <param name="source">Logolás forrása. Mindig egy típust (Type) kell átadni. Instance szintű tagoknál a this.GetType() kifejezést használjuk a paraméter értékadásához! 
///                         Static tagoknál a typeof(KonkrétClassNév) kifejezéssel adjuk át a típust.</param>
/// <param name="caller">4.5 Frameworktől automatikusan kap értéket a CallerMemberName attribútumon át, sose adjunk meg értéket ennek a paraméternek! 4.5 alatti verzióknál a hívás helyén kell gondoskodni a kitöltéséről, ha használni  akarjuk a logban ezt az adatot.</param>
/// <param name="line">4.5 Frameworktől  Automatikusan kap értéket a CallerLineNumber attribútumon át, sose adjunk meg kézzel értéket ennek a paraméternek! 4.5 alatti verzióknál a hívás helyén kell gondoskodni a kitöltéséről, ha használni  akarjuk a logban ezt az adatot.</param>
static public void Log<T>(T data, IDictionary<string, string> dataFields, Exception exception, LogLevel level, Type source, [CallerMemberName]string caller = "", [CallerLineNumber]int line = 0)     

Hogy a paraméterekkel a logolás során mi történik a használt logger pluginban, az erősen függ a használt plugin implementációjától. Az erre vonatkozó részleteket az adott Vrh.Logger Plugin dokumentációja írja le. Alább a A Logger komponens fejlesztő támogatására szolgáló DefaultLogger implementációban megvalósuló viselkedést adjuk meg. (Fontos megjegyzés a DefultLogger pluginnal kapcsolatban, hogy az tényleges logolásra nem alkalmas, csak a consolra és a csatlakoztatott debugger outputjára képes elküldeni a bedobott log bejegyzéseket.)

  • A generikusba bármilyen típust bedobhatunk (a konkrét példányt a data paraméterben lehet átadni). A defult logger JSON-ba serializálja a típust, de null is átadható neki.
  • A dataFileds-ben kulcs értékpárral megadott adatok adhatóak át. A Defultlogger ezeket kulcs: érték formában jeleníti meg, null érték is átadható neki.
  • Az exception-ben egy exceptiont dobhatunk be, amit át kívánunk adni logolásra. A DefultLogger a LogHelper.GetExceptionInfo segíytségével jeleníti meg az exception adatait. (Lásd lejebb a Loghelper dokumentációjában.)
  • A level megmondja, hogy a log bejegyzést melyik logszint beállítástól kezdődően kell ténylegesen a logba küldeni. Ha az aktuálisan beállított logolási szint legalább ekkora, akkor történik ténylegesen logolás (a logolásra használt ILogger interfészt implementáló plugin Log metódusának hívása.)
  • A source segítségével adhatjuk meg a logolás forrásának a típusát. Mindig adjuk meg a hívás helyén ezt az értéket, hogy a Logolás releváns információkat tartalmazhasson! Static tagoknál a typeof(MyStaticClass) a helyes átadási mód, míg instance szintű tagoknál a this.GetType()-ot használjuk! A Logger a pluginnak ezt az információt nem adja tovább, hanem kibontja belőle a típust definiáló Assembly nevét, annak definiált verzióját, és a típus teljes nevét (névtérrel együtt). Ezen információk adódnak át a használt Logger pluginnak. A DefaultLogger plugin ezeket megjeleníti.
  • A caller paramétert 4.5-ös Frameworktől kezdődően sose töltsük ki a hívásokban, az automatikusan értéket kap, és a metódus neve kerül bel, ahonnan a Log metódust meghívtuk. 4.5 alatti Fremwork esetén ezt az információt a hívási helyről át kell adni a hívásban, ha kívánunk a Logger pluginnak átadni ilyen információt.
  • A line paramétert 4.5-ös Frameworktől kezdődően sose töltsük ki a hívásokban, az automatikusan értéket kap, és a forrássor száma kerül bel, ahonnan a Log metódust meghívtuk. 4.5 alatti Fremwork esetén ezt az információt a hívási helyről át kell adni a hívásban, ha kívánunk a Logger pluginnak átadni ilyen információt.

Példák a használatára:

catch (Exception ex)
{
    VrhLogger.Log<string>("error", null, ex, LogLevel.Error, this.GetType()));
}
VrhLogger.Log<ApplicationTrust>(AppDomain.CurrentDomain.ApplicationTrust, null, null, LogLevel.Verbose, typeof(Program));
Dictionary<string, string> logData = new Dictionary<string, string>()
{
    { "Vrh.Loger Version ", GetModulVersion(typeof(VrhLogger)) },
    { "Used Logger", _logger != null ? _logger.GetType().FullName : String.Format("Not found!!! {0}", loggerTypeSelector) },
    { "Used Logger version", _logger != null ? GetModulVersion(_logger.GetType()) : "?" },
};
logData.Add("Used Plugin == Defult Logger", (_defaultLogger == null).ToString());
Logger.Log<String>("Vrh.Logger Started", logData, null, _logger != null ? LogLevel.Information : LogLevel.Warning, typeof(VrhLogger));

1.1 String logolása

Hogy ne kelljen a bonyolultabb formát beírni, egyszerű szöveges információ logolására használható az alábbi Log metódus is:

/// <summary>
/// Egyszerű string adat logolása.
/// </summary>
/// <param name="logMessage">Log üzenet</param>
/// <param name="level">Logszint</param>
/// <param name="source">Logolás forrása. Mindig egy típust (Type) kell átadni. Instance szintű tagoknál a this.GetType() kifejezést használjuk a paraméter értékadásához! 
///                         Static tagoknál a typeof(KonkrétClassNév) kifejezéssel adjuk át a típust.</param>
/// <param name="caller">4.5 Frameworktől automatikusan kap értéket a CallerMemberName attribútumon át, sose adjunk meg értéket ennek a paraméternek! 4.5 alatti verzióknál a hívás helyén kell gondoskodni a kitöltéséről, ha használni  akarjuk a logban ezt az adatot.</param>
/// <param name="line">4.5 Frameworktől  Automatikusan kap értéket a CallerLineNumber attribútumon át, sose adjunk meg kézzel értéket ennek a paraméternek! 4.5 alatti verzióknál a hívás helyén kell gondoskodni a kitöltéséről, ha használni  akarjuk a logban ezt az adatot.</param>
static public void Log(string logMessage, LogLevel level, Type source, [CallerMemberName]string caller = "", [CallerLineNumber]int line = 0)

Példák a használatára:

VrhLogger.Log("Simple stringlog", LogLevel.Information, typeof(Program));
1.2. Exception logolása

Hogy ne kelljen a bonyolultabb formát beírni, kivétel logolására használható az alábbi Log metódus is:

/// <summary>
/// Exception egyszerű logolása
/// </summary>
/// <param name="exception">Logolandó kivétel</param>
/// <param name="source">Logolás forrása. Mindig egy típust (Type) kell átadni. Instance szintű tagoknál a this.GetType() kifejezést hazsnáljuk a paraméter értékadásához! 
///                         Static tagoknál a typeof(KonkrétClassNév) kifejezéssel adjuk át a típust.</param>
/// <param name="level">Logszint</param>
/// <param name="caller">4.5 Frameworktől automatikusan kap értéket a CallerMemberName attribútumon át, sose adjunk meg értéket ennek a paraméternek! 4.5 alatti verzióknál a hívás helyén kell gondoskodni a kitöltéséről, ha használni  akarjuk a logban ezt az adatot.</param>
/// <param name="line">4.5 Frameworktől  Automatikusan kap értéket a CallerLineNumber attribútumon át, sose adjunk meg kézzel értéket ennek a paraméternek! 4.5 alatti verzióknál a hívás helyén kell gondoskodni a kitöltéséről, ha használni  akarjuk a logban ezt az adatot.</param>
static public void Log(Exception exception, Type source, LogLevel level = LogLevel.Error, [CallerMemberName]string caller = "", [CallerLineNumber]int line = 0)

Példák a használatára:

catch (Exception ex)
{
    VrhLogger.Log(ex, typeof(Program));
}

2. LoadLoggerPlugin():

Arra használható, hogy anélkül cseréljünk az alkalmazás térben használt Logger plugint, hogy az alkalmazást újraindítanánk. A Vrh.Logger működéséhez nem kell explicit meghívni, mert a Logger static típus static konstruktora is meghívja.

Definiciója:

/// <summary>
/// Betölti a Logger által használt Plugint
///     A static construktor meghívja, azért public, hogy le lehessen programozni egy olyan alkalmazás logikát, ahol app restart nélkül logger plugint cserélünk.
/// </summary>
/// <param name="config">A használt konfigurációt jelöli ki</param>  
static public void LoadLoggerPlugin(string config = null)
  • Egyetlen paramétert lehet neki itt átadni, azt a konfigurációt definiáló stringet, amelyet a plugin a működéséhez használjon. Ha ilyet nem adunk meg, akkor alapértelmezés szerinti konfigurációt használ. (A Vrh.Logger konfigurációjáról, és annak működéséről a dokumentum lejjebb tartalmaz információkat.)

Használata:

VrhLogger.LoadLoggerPlugin(LogConfig.xml/Vrh.Logger);

3. SetNoOfLogEntry():

Segítségével egy olyan szolgáltatást implementálhatunk a felhasználás helyén, amivel egy adott sorszámra állítjuk a Logsorszámot. Az ilyesmi például hibakereséshez jöhet jól.

Definiciója:

/// <summary>
/// Segítségével implementálható a felhasználás helyén egy olyan szolgáltatás, amivel explicit módon beállítható, hogy mennyi legyen a Logsorszám 
/// </summary>
/// <param name="newNoOfLogEntry">Erre az értrékre áll be  asorszám, ha nincs mergadva, akkor 0</param>
public static void SetNoOfLogEntry(ulong newNoOfLogEntry=0)
  • Egyetlen paramétert lehet neki átadni, hogy mennyi legyen a log sorszám aktuális értéke.

Használata:

VrhLogger.SetNoOfLogEntry(9999);

### LogHelper static class: Az olyan hasznos szolgáltatásokat biztosít egyszerű metódusokon keresztül, amelyek a logolással kapcsolatban hasznosak lehetnek. Jelenlegi szolgáltatásai:

  • GetAccurateDateTimeValue: Egy időbélyeg jellegű adatot nagy pontosságot megjelenítő stringként ad vissza, időzóna információval (yyyy.MM.dd HH:mm:ss.fffffff (zzz)).

    /// <summary>
    /// Visszaadja a kapott időpont nagy pontosságú string reprezentánsát 
    /// </summary>
    /// <param name="value">Időbélyeg jellegű adat</param>
    /// <returns>A kapott időbélyeg stringként</returns>
    public static string GetAccurateDateTimeValue(DateTime value)
    
    • GetExceptionInfo: Az átadott exception adatait emberi olvasásra formázott stringként adja vissza. A megadott indentLevel szerinti tab-ot tesz minden egyes sor elejére. csharp /// <summary> /// Kiszedi a kapott kivétel adatait egy szöveges leírássá /// </summary> /// <param name="ex">Exception, amelynek az adatait kigyűjtjük</param> /// <param name="indentLevel">Ennyi tab-bal indentálja az információ minden egyes sorát</param> /// <returns>A kapott Exception adatai stringként</returns> public static string GetExceptionInfo(Exception ex, int indentLevel = 0) >A megjelenített adatok: >* Az Exception konkrét típusa >* A Message field tartalma >* A StackTrace tartalma >* Ha az InnerException nem null, akkor annak tartalma, ugyanígy megformázva, ezzel az adat tartalommal. Tetszőleges mélységig (amíg az InnerException-ök is tartalmaznak InnerExceptiont). Minden egyes InnerExceptiont egyel beljebb indentálva. >* Ha az adott Exceptoion típusa ReflectionTypeLoadException, akkor annak LoaderExceptions gyűjteményén is végigiterál, kigyűjtve azok InnerException-jeit is.
    • GetExceptionData: Segítségével Exception.Data (vagy bármilyen más Idictionary) adatokat rendezhetünk emberi olvasásra szánt szöveggé, úgy, hogy minden kulcs-érték párnak új sort nyit, és előre a kulcsot, majd mögé az adatot írja. csharp /// <summary> /// Visszadja egy IDictionary-ben tárolt kulcs érték párokat (pl.: Exception.Data) /// </summary> /// <param name="data">Idictionary gyűjtemény</param> /// <param name="indentLevel">Ennyivel lesz beindentálva</param> /// <returns></returns> public static string GetExceptionData(IDictionary data, byte indentLevel)
    • MakeIndent: Segítségével egy strin g minden egyes sorát (/n karakterek, mint sorvégek) a megadott szinttel beljebb indentálja, úgy, hogy a sorok elejére /t karaktereket helyez el az indentLevel-nek megfelelő számban. csharp /// <summary> /// Tabokkal indentálja a kapott szöveg minden egyes sorát a paraméterben kapott számnak megfelelő számban /// </summary> /// <param name="input">Az indentálandó szöveg</param> /// <param name="indentLevel">Az indentálás szintje</param> /// <returns>Indentált szöveg</returns> public static string MakeIndent(string input, int indentLevel)
    • GetDictionaryInfo: Segítségével kulcs értékpárok listájaként átadott adatokat rendezhetünk emberi olvasásra szánt szöveggé, úgy, hogy minden kulcs-érték párnak új sort nyit, és előre a kulcsot, majd mögé az adatot írja. csharp /// <summary> /// Visszaadja a kapott Dictonary tartalmát emberi olvasásra formázott kulcs értékpárok listájaként /// </summary> /// <param name="dict">Az adatokat tartalmazó Dictionary</param> /// <param name="IndentLevel">Ennyivel lesz beindentálva</param> /// <returns>Az adatok formázott stringként</returns> public static string GetDictionaryInfo(IDictionary<string, string> dict, byte IndentLevel = 0)
    • HexControlChars: A kapott szövegben esetleg megtalálható nem vizuális karaktereket hexa karakterkód értékre alakítja, és ezeket a megadott jelek közt, mint keretben illeszti be az a szövegben eredetileg is elfoglalt helyükre. csharp /// <summary> /// A megadott sztring kontrolkaraktereit hex formátummá alakítja. /// A kontrol karakterek jelölésére használt keret karaktereket (frameStart, frameEnd), szintén hexa karakterkódra alakítja, ha előfordulnak az eredeti szövegben. /// </summary> /// <param name="str">A vezérlőkaraktereket is tartalmazó szöveg (string)</param> /// <param name="indentLevel">A formázott szöveg indentálásának a mértéke</param> /// <param name="frameStart">A vezérlőkarakterek hexakódjainak keretezésére ezt használja nyitó karakternek</param> /// <param name="frameEnd">A vezérlőkarakterek hexakódjainak keretezésére ezt használja záró karakternek</param> /// <returns>A formázott szöveg</returns> public static string HexControlChars(string str, byte indentLevel = 0, char frameStart = '{', char frameEnd = '}')
    • ArrayToHumanReadableString: Konvertál egy tömböt emberi olvasásra alkalmas stringgé (a tömb értékei a megadott elválasztó karakterrel kerülnek egymástól elválasztásra). A tömbben tárolt típusnak a tárolt adat szöveges vizualizációjára nézve releváns ToString overloaddal kell rendelkeznie, a helyes működéshez.
      csharp /// <summary> /// Konvertál egy tömböt emberi fogyasztásra alkalmas stringgé. /// A T-nek a tárolt értékre nézve releváns ToString overloaddal kell rendelkeznie, a helyes működéshez. /// </summary> /// <typeparam name="T">Típus kijelölő</typeparam> /// <param name="valueArray">Az értékeket tartalmazó tömb</param> /// <param name="indentLevel">A formázott szöveg indentálásának a mértéke</param> /// <param name="valueSeparator">Az értékeket egymástól elválasztó karakter a formázott szövegben.</param> /// <returns>a formázott szöveg</returns> public static string ArrayToHumanReadableString<T>(T[] valueArray, byte indentLevel = 0, char valueSeparator = ';')
    • BytesToHumanReadableString: A megadott bájt tömböt ascii encodolással szöveggé alakítja, az esetleges vezérlőkaraktereket hexa értékre cserélve. Tipikus felhasználási területe alacsony szintű kommunikációs pufferek tartalmának logolása. csharp /// <summary> /// A megadott bájt tömböt Ascii encodolással szöveggé alakítja, az esetleges vezérlőkaraktereket hexa értékre cserélve /// Tipikus felhasználási területe alacsony szintű kommunikációs pufferek tartalmának logolása /// </summary> /// <param name="bytearray">A konvertálandó bytok sorozata</param> /// <param name="indentLevel">A formázott szöveg indentálásának a mértéke</param> /// <returns>A formázott szöveg</returns> public static string BytesToHumanReadableString(byte[] bytearray, byte indentLevel = 0)
    • BytesToHexBlock: byte sorozatot HexBlock formázású, emberi olvasásra szánt stringgé alakít. csharp /// <summary> /// Egy byte sorozatot HexBlock formázású, emberi olvasásra szánt stringgé alakít /// </summary> /// <param name="data">a bemenő bájtsorozat</param> /// <param name="header">megadja, hogy az első sor egy header legyen, amely magyarázza az adattartalmat</param> /// <param name="footer">megadja, hogy legyen e egy hexablock véget értét hangsúlyozó lezárás a block végén</param> /// <param name="encoding">Beállítható vele, a használt karakter encoding, alapértelmezésben ASCII-t fog használni</param> /// <param name="indentLevel">Annyivel indentálja a hexa blockot</param> /// <returns>a formázott szöveg</returns> public static string BytesToHexBlock(byte[] data, bool header = true, bool footer = false, Encoding encoding = null, byte indentLevel = 0)
    • ExtractPropertyValuesToDataFields: Visszadja a paraméterben kapott objektum propertijeinek értékeit név-érték párok litsájaként, amit közvetlenül odalehet adni a VrhLogger.Log hívásoknak, hogy kiírja az értékekeket. A property-ken a ToString-et hívja az értékhez, így az érték string reprezentánsa az adott típus ToString megvalósításának megfelelő lesz. csharp /// <summary> /// Visszadja a paraméterben kapott objektum propertijeinek értékeit név-érték párok litsájaként (a property-n a ToString-et hívja az értékhez) /// </summary> /// <typeparam name="TClass">Ezzel az objektum típussal dolgozik</typeparam> /// <param name="instance">Ezzel a példánnyal</param> /// <returns>név-érték párok litáájaként a property-k neve és értéke</returns> public static Dictionary<string, string> ExtractPropertyValuesToDataFields<TClass>(TClass instance) ### Konfiguráció: A Vrh.Logger konfigurációjának megadásához kétféle módszert támogat:
    • Vagy egy az alkalmazástér konfigurációjából vesz fel appSettings kulcsokat.
    • Vagy egy XML struktúrából olvassa ki a működési paramétereket.

Config XML használata:

Az alábbi XML-t érti meg, mint konfigurációt:

<Vrh.Logger>
  <LogLevel>Warning</LogLevel>
  <EnableConsoleLogging>True</EnableConsoleLogging>
  <EnableDebuggerLogging>True</EnableDebuggerLogging>
  <EnableFileLogging LogDirectory="Log" LogFile="Vrh.Logger.TxtLog.log">True</EnableFileLogging>
  <UsedLogger>DefaultLogger</UsedLogger>
  <UsedLoggerConfig>tetszőleges xml szabványos tartalom</UsedLoggerConfig>
  <LoggerErrorLogDirectory>Log</LoggerErrorLogDirectory>
  <LoggerErrorLogFile>Vrh.Logger.Errors.log</LoggerErrorLogFile>
</Vrh.Logger>

Az XML struktúrát az XmlProcessing modulon keresztül kapja meg. Alapértelmezett XmlParser connection string: file=~LogConfig.xml, azaz az alapértelmezett xml struktúrát az alkalmazás könyvtárában levő LogConfig.xml file tartalmazza.

Ha ettől el akarunk térni, akkor erre két lehetőségünk van:

  1. Meghívjuk a felhasználás helyén, még az első Log hívás előtt, a Logger class LoadLoggerPlugin() metódusát, paraméternek pedig átadjuk a használandó XmlParser connectionstring-et.
  2. Az alklamazás standard (App.config, Web.config) konfigurációjában definiálunk egy Vrh.Logger:Config kulcsú appSettings kulcsot és az értékének a használandó XmlParser connectionstring-et adjuk. xml <appSettings> <add key="Vrh.Logger:Config" value="file=~LogConfig.xml;element=Vrh.Logger;"/> </appSettings> A fenti példában az xml struktúrát az alkalmazás könyvtárában levő LogConfig.xml file gyökér eleme alatt található Vrh.Logger xml elem tartalmazza.

A következő legyen az alkalmazás könyvtárában levő AppCfg.xml file szerkezete, amelyben a struktúra belsejében található LoggerConfiguration elem tartalmazza a Vrh.Logger paramétereit. Ennek a következő XmlParser connectionstring felel meg: file=~Config.xml;element=ComponentConfiguration\LoggerConfiguration;

<ApplicationConfiguration>
    <ComponentConfiguration>
        <LoggerConfiguration>
            <LogLevel>Warning</LogLevel>
            <EnableConsoleLogging>True</EnableConsoleLogging>
            <EnableDebuggerLogging>True</EnableDebuggerLogging>
            <EnableFileLogging LogDirectory="Log" LogFile="Vrh.Logger.TxtLog.log">True</EnableFileLogging>
            <UsedLogger>DefaultLogger</UsedLogger>
            <LoggerErrorLogDirectory>Log</LoggerErrorLogDirectory>
            <LoggerErrorLogFile>Vrh.Logger.Errors.log</LoggerErrorLogFile>
        </LoggerConfiguration>
    </ComponentConfiguration>
</ApplicationConfiguration>

Ha a file csak a Vrh.Logger paramétereit tartalmazza, akkor pedig: file=~Config.xml;

<LoggerConfiguration>
    <LogLevel>Warning</LogLevel>
    <EnableConsoleLogging>True</EnableConsoleLogging>
    <EnableDebuggerLogging>True</EnableDebuggerLogging>
    <EnableFileLogging LogDirectory="Log" LogFile="Vrh.Logger.TxtLog.log">True</EnableFileLogging>
    <UsedLogger>DefaultLogger</UsedLogger>
    <LoggerErrorLogDirectory>Log</LoggerErrorLogDirectory>
    <LoggerErrorLogFile>Vrh.Logger.Errors.log</LoggerErrorLogFile>
</LoggerConfiguration>
  • Megfigyelhetőek az alábbiak: >* Az element tagban a struktúrán belüli kijelölésben a Root elemet nem definiáljuk, csak az azon belüli útvonalat. >* Ha nem adunk meg element tagot, akkor a beállítások tagjeit a root elem alatt keresi. >* A root elem elnevezése tetszőleges lehet a configurációt tartalmazó XML-ben.

Szabvány app settings kulcsok használata:

Ekkor a szabványos config állomáynban szabványos appSettings kulcsok megadásával specifikáljuk a fenti négy beállítást:

    <appSettings>      
      <add key="Vrh.Logger:Config" value="@D:\Temp\_t\LogConfig.xml/Vrh.Logger"/>
      <add key="Vrh.Logger:LogLevel" value="debug"/>
      <add key="Vrh.Logger:EnableConsoleLogging" value="True"/>
      <add key="Vrh.Logger:EnableDebuggerLogging" value="True"/>
      <add key="Vrh.Logger:UsedLogger" value="DefaultLogger"/>
      <add key="Vrh.Logger:LoggerErrorLogDirectory" value="@D:\Temp\_t\Log"/>
      <add key="Vrh.Logger:LoggerErrorLogFile" value="Vrh.Logger.Errors.log"/>      
      <add key="Vrh.Logger:EnableFileLogging" value="True"/>
      <add key="Vrh.Logger:LogDirectory" value="Log"/>
      <add key="Vrh.Logger:LogFile" value="Vrh.Logger.TxtLog.log"/>
    </appSettings>

Mi mit jelent fentiekből?

A két beállítási mód közül az AppSettings kulcsok használata kap prioritást. Tehát amit megtalál az AppSettingsek közt, azt a beállítást innen kiolvassa, és nem számít, hogy az XML konfigurációban is van-e rá definíció, és mi az ottani értéke. Ez így arra is lehetőséget nyújt, hogy bizonyos beállításokat megadjunk az XML konfiguráció szintjén, míg másokat csak az .config-ban definiáljunk. A fenti beállítások konkrét értelmezése:

  • LogLevel: A logolás szintje. A Vrh.Logger koncepciója szerint a logszint kezelése nem a Pluginok hatásköre. A beállításban megadott logszint, vagy az annál magasabbak kerülnek logolásra. Az alapértelmezett érték, ha a beállítás nincs jelen az Error. A használható értékek, magassági sorrendben, és a szándékolt jelentéssel: >* Debug: Azon log bejegyzések, amelyek olyan részletes, a program belső működésével, állapotával kapcsolatos információkat jelentenek, melyek fejlesztői szintű információnak tekinthetőek, értelmezésükhöz a program belső ismerete vagy/és fejlesztői szaktudás szükséges. >* Verbose: Részletes információk a program működéséről és az e-közbeni állapotokról, de tartalmuk a program belső ismerete nélkül is értelmezhető. >* Information: Olyan részletességű információk, amelyek részleteiben tájékoztatnak a program működéséről, de csak a funkciók szempontjából, ezért az üzleti/funkcionális ismeretekkel rendelkezőknek is értelmezhető információkat tartalmaznak csak. >* Warning: Olyan log üzenetek, amelyek a program működésével kapcsolatos figyelmeztetések, fontos információk. Általában valamilyen veszélyre, a működést legalábbis főfunkció szintjén nem befolyásoló hibára, inkonzisztenciára, konfigurációs ellentmondásra ilyesmire figyelmeztetnek. Jellemzően ez az a szint, amivel az üzemeltető rá jöhet, hogy mi az oka annak, hogy nem azt a működést tapasztalja, amit elvárna. >* Error: A program működése során fellépő nem kritikus mértékű hibák. >* Fatal: Olyan kritikus hiba, amely a program működésének leállását okozza, vagy egy főfunkció működésének ellátását akadályozza. >* None: Ez nem egy valódi log szint. Segítségével teljesen kikapcsolható a logolás.
  • EnableConsoleLogging: Segítségével azt lehet előírni a Vrh.Logger-nek, hogy a benne található DefultLogger implementációt is üzemeltesse és az alkalmazás Console-ra is jelenítse meg a log bejegyzéseket. Egy logikai érték. Az igaz (True) értéket a true, yes, 1 értékek jelentik (a kis és nagybetűk közt nem tesz különbséget). Minden ezektől eltérő érték hamis értéket (False) jelent. Az alapértelmezett érték a False, ha a beállítás nincs jelen.
  • EnableDebuggerLogging: Segítségével azt lehet előítrni a Vrh.Logger-nek, hogy a benne található DefultLogger implementációt is üzemeltesse és az alkalmazáshoz csatlakoztatott Debugger outputján is jelenítse meg a log bejegyzéseket. Egy logikai érték. Az igaz (True) értéket a true, yes, 1 értékek jelentik (a kis és nagybetük közt nem tesz különbséget). Minden ezektől eltérő érték hamis értéket (False) jelenet. Az alapértelmezett érték a False, ha a beállítás nincs jelen.
  • EnablEFileLogging: Segítségével azt lehet előítrni a Vrh.Logger-nek, hogy a benne található DefultLogger implementációt is üzemeltesse és egy txt log fájlba írja ki a log bejegyzéseket. Egy logikai érték. Az igaz (True) értéket a true, yes, 1 értékek jelentik (a kis és nagybetük közt nem tesz különbséget). Minden ezektől eltérő érték hamis értéket (False) jelenet. Az alapértelmezett érték a False, ha a beállítás nincs jelen.
  • LogDirectory: Ha a txt log file írás engedélyezve van, akkor az itt megadott könyvtárat használja a Log file célkönyvtáraként. Ha a könyvtár nem létezik, akkor létrehozza. Ha nincs megadva, akkor az alkalmazás futási könyvtárában keletkezik a fájl.
  • LogFile: Segítségével lehet definiálni, hogy a fent leírt text log fájlt milyen néven hozza létre a Vrh.Logger. Ha nincs megadva, akkor a fájl Vrh.Logger.TxtLog.log néven jön létre.
  • UsedLogger: Ha a Vrh.Logger működési környezetében több Logger plugin is található. Akkor ennek segítségével írhatjuk elő, hogy ezek közül melyiket használja a konfiguráció logolásra. Ha ez a beállítás nincs jelen, akkor mindig azt a plugint használja maleiket először megtalál a működési környezetben. Így egyetlen plugin jelenléte esetén a beállítást nem szükséges megadni. Az értéknek a használandó plugin pontos osztály nevét, vagy teljes (névterekkel együtt) osztálynevét kell megadni, ezt mindig az adott Plugin dokumentációjából derül ki.
  • UsedLoggerConfig: A UsedLogger elemben megadott plugin publikus "Init" metódusának XElement típusú paraméterében átadott xml elem, aminek beltartalmát teljes egészében a betöltött plugin dolgozza fel. Ezt a paramétert nem lehet az appSettings elemeken keresztül átadni!

  • LoggerErrorLogDirectory: Ha a Vrh.Logger működésében valami hiba lép fel, amely meggátolja a logolást, akkor egy saját text fájlba írja a hiba tényét, és az üzenet segítségével a hiba oka kideríthető. Magasabb logolási szinteken bejegyzéseket készít egyéb információkról is ide, a Logger indulásáról, leállásáról, a használt plugin betöltéséről. Ez a beállítás mondja, meg, hogy melyik könyvtárba kerüljön ez a txt Log. Ha nincs megadva, akkor az alkalmazás futási könyvtárában keletkezik a fájl.

  • LoggerErrorLogFile: Segítségével lehet definiálni, hogy a fent leírt saját hiba text fájlt milyen néven hozza létre a Vrh.Logger. Ha nincs megadva, akkor a fájl Vrh.Logger.Errors.log néven jön létre.

    Információk Plugin fejlesztéshez

    Minden Vrh.Logger egyetlen Log metódust valósít meg az Vrh.Logger.Ilogger intefész implementációjával. Az interfész használathoz a Vrh.Logger névtér using-olandó. Az ILogger interfész teljes definíciója:

    /// <summary>
    /// Logger interfész, amelyet a Vrh.Logger használ
    ///  A konkrét logger megoldásnak, vagy annak  a wraperének ezt kell implementálnia.
    ///  Az implementzáló típust meg kell jelőlni Export attribútummal!
    /// </summary>
    public interface ILogger : IDisposable
    {
        /// <summary>
        /// Azt fogja hívni a Vrh.Logger a logok átadásához.
        ///     A koncepció szerint a LogLevel-t a Vrh.Logger kezeli a konkrét logger plugin felett!
        /// </summary>
        /// <typeparam name="T">Típuskijelölő</typeparam>
        /// <param name="noOfLogEntry">Log sorszáma a Logger létrejötte óta az adott alkalmazástérben</param>
        /// <param name="data">A kijelölt típusú adat</param>
        /// <param name="dataFields">Kulcs érték párok listájaként átadott adatok</param>
        /// <param name="exception">Egy exceptiont lehet ide bedobni, hogy a Logger az alapján logolja az exception fontos részleteit</param>
        /// <param name="level">A log szintje ennek a bejegyzésnek</param>
        /// <param name="sourceModul">Forrásmodul a Logger static Log hívásnak átadott típust deklaráló assembly neve kerül bele</param>
        /// <param name="sourceModulVersion">Forrásmodul verziója. Az assemblyben definiált AssemblyInformationalVersion, annak hiányában a definiált AssemblyVersion</param>
        /// <param name="sourceClass">Az osztály teljes neve, ahonnan a Log bejegyzést bedobták</param>
        /// <param name="sourceMethode">A metódus, neve, ahonnan a log bejegyzés érkezett (4.5 Framework-tól automatikus, az alatt  a hívási helyen kell gondoskodni az átadásáról)</param>
        /// <param name="line">A forrás sor száma, ahonnan a Log hívás származik (4.5 Framework felett automatikus, az alatt a hívási helyen kell gondoskodni az átadásáról)</param>
        /// <param name="callTimeStamp">A hívás időbéjege</param>
        void Log<T>(UInt64 noOfLogEntry, T data, IDictionary<string, string> dataFields, Exception exception, LogLevel level, string sourceModul, string sourceModulVersion, string sourceClass, string sourceMethode, int line, DateTime callTimeStamp);
    
        /// <summary>
        /// Esemény,a melyen keresztül a plugin visszajelzést tud küldeni a működésében bekövetkező kritikus hibákról.
        ///     Minden esetben Dispose hívást, és recreatet eredményez a Pluginra nézve a Vrh.Logger keret szintjén!!!     
        /// </summary>
        event FatalErrorInPluginEventHandler FatalErrorInPlugin;
    

    Az alábbi szabályok és elvek elvárások a Pluginnal szemben:

  • Implementáció:

    • A Plugin megvalósítás implementálja az ILoggert, amely egyetlen Log metódus megvalósítását jelenti.
    • De az ILogger egy IDispose leszármazott, ezért a plugin disposolható. És kötelezően Dispose mintát implementál.
    • A Pluginnak kötelessége megvalósítani tényleges teljes erőforrás felszabadítást a Dispose ágon. A Vrh.Logger keret bizonyos esetekben a publikus Dispose metodusát hívja. Ekkor minden a logoláshoz használt erőforrást el kell engednie, és az objektumnak meg kell semmisülnie a Dispose visszatérésére. Tehát maradéktalanul működnie kell egy ilyen teszt kódnak rá (ahol iterationCount egy tetszőleges számú ismétlést definiál): csharp for (int i = 0; i < iterationCount; i++) { ILogger logger = new MyLoggerPlugin(); logger.Log<string>((ulong)i, "test", null, null, LogLevel.Debug, "TEST", "V1.0.0", "TestClass", "TestMethode", 1, DateTime.Now); }
  • Hibavédettség:

    • A plugin implementációnak le kell kezelnie, hogy a Log hívás során bármilyen paraméter értéket is kapjon bármelyik paraméterben, beleértve a null értékeket is a nullozható típusok esetén. Megengedett, hogy a Logolás ne sikerüljön (ne keletkezzen log bejegyzés), de hogy a Plugin működése leálljon az nem.
    • Fenti paraméterek közül az alábbiak Null értéktől különböző kitöltöttségét mindig biztosítja a Vrh.Logger keret a nullozható típusok esetén is: >* dataFields (üres Dictonary formájában)
      >* sourceModul >* sourceModulVersion >* sourceClass
  • További részletek:

    • Mivel a Vrh.Logger keret a Plugint a MEF keretrendszerrel tölti be, ezért meg kell jelölni Export attribútummal, a plugin Vrh.Logger.ILogger interfészt implementáló típusát, mégpedig az Ilogger contract típussal: csharp [Export(typeof(ILogger))] public class DefaultLogger : ILogger { ...
    • Az Export attribútum a System.ComponentModel.Composition névtérben található.
    • Mivel a Vrh.Logger keret a plugint egy egyszerű MEF Import-ként injektálja, így minden működéséhez szükséges inicializációt el kell végezni az alapértelmezett (paraméter nélküli) konstruktorában. Sem konstruktor paraméter átadására, sem inicializáló függvény meghívására nincs lehetőség az automatikus Plugin töltés folyamatában.
    • Mivel a Vrh Logger keret a Plugin Log implementációját aszinkron, egy külön háttérszálra dobva hívja (és nem vár a visszatérésére), ezért ez további követelményeket és sajátosságokat jelent: >* A Log metódusnak, illetve a Plugin ennek a hívásnak a kezelésével összefüggő működésének szálvédettnek kell lennie! Hiszen a Logger keret változó számú, párhuzamos konkurens hívást fog intézni a plugin felé a Log híváson keresztül. >* Ennek megfelelően a Log hívással semmilyen mód nem biztosított futási eredmények, vagy hibák visszadobására a logolásból. A Le nem kezelt kivételek annyit eredményeznek, hogy a végrehajtására indított tread nem normál státusszal terminál. Ennek ellenére kívánatos a Plugin Log metódusra hibavédelmet implementálni, és a logolásban fellépő kritikus hibák okáról a lentebb leírt módon értesíteni a Vrh.Logger komponenst.
    • Amennyiben a Plugin működését akadályozandó hiba áll fenn, vagy ilyen keletkezik, a Plugin felelőssége, hogy erről értesítse a Vrh.Logger plugint. Ennek a módja, a Vrh.Logger.ILogger interfészben definiált FatalErrorInPlugin esemény implementálása: csharp /// <summary> /// Esemény,a melyen keresztül a plugin visszajelzést tud küldeni a működésében bekövetkező kritikus hibákról. /// Minden esetben Dispose hívást, és recreatet eredményez a Pluginra nézve a Vrh.Logger keret szintjén!!! /// </summary> event FatalErrorInPluginEventHandler FatalErrorInPlugin;
    • Az eseményt a FatalErrorInPluginEventHandler delegate-nek megfelelő signaturával iratkozik fel a Vrh.Logger keret, amely teljes definíciója az alábbi: csharp /// <summary> /// Delegeta definició, a FatalErrorInPlugin event kezeléséhez /// </summary> /// <param name="pluginType">A plugin típusa, mindig adjuk át, hogy a Vrh.Logger keret releváns információt menthessen a hiba fellépésének helyéről</param> /// <param name="e">Az esemény argumentumai, egy szöveges üzenetet, és egy tetszőleges szabványos Exception átadását támogatja</param> public delegate void FatalErrorInPluginEventHandler(Type pluginType, PluginFatalErrorEventArgs e);
    • A használt PluginFatalErrorEventArgs typus teljes definiciója az alábbi: ```csharp /// /// EventArgs a FatalErrorInPlugin eseméynhez /// public class PluginFatalErrorEventArgs : EventArgs { /// /// Szöveges információ a fellépett hibáról /// public string Message { get; set; }
    /// <summary>
    /// Itt adhatjuk át a feléppő, vagy a kiváltott Exception-t
    /// </summary>
    public Exception Exception { get; set; }
    
    /// <summary>
    /// Jelzi a logger keretnek, hogy indítsa újra a plugint 
    /// </summary>
    public bool RestartMe { get; set; }
    

    } >```

    • Fentiek alapján a Pluginban az alábbi minta alapján kell helyesen implementálni az esemény visszajelzést:

         /// <summary>
         /// FatalErrorInPlugin esemény (ILogger interfész member)
         /// </summary>
         public event FatalErrorInPluginEventHandler FatalErrorInPlugin;
      
         /// <summary>
         /// Metódus a FatalErrorInPlugin esemény elsütésére
         /// </summary>
         /// <param name="exception">Menteni kívánt kivétel</param>
         /// <param name="message">Szabadon beállítható üzenet a hibával kapcsolatban</param>
         private void OnFatalErrorInPlugin(Exception exception = null, string message = "")
         {
             var ea = new PluginFatalErrorEventArgs()
             {
                 Message = message,
                 Exception = exception,
       RestartMe = true,
             };
             FatalErrorInPlugin?.Invoke(this.GetType(), ea);
         }
      
    • A hiba esemény kiváltásához egyszerűen az OnFatalErrorInPlugin metódust hívjuk a plugin implementációjában azon a helyen, ahonnan a hiba fellépéséről értesítést akarunk küldeni a keretnek.

    • Cészerű kihasználni, hogy konkrét Exception típust tudunk átadni. Az emellé mellékelt szöveges üzenet inkább egy opcionális lehetőség.

    • Az esemény kritikus hibák jelzésére szolgál. A Vrh.Logger keret a saját logjába mindig errorként menti az ezen át érkezett információkat. Ne használjuk a plugin működésével kapcsolatos ionformációk átadására, csak ténylegesen olyan súlyos hibák jelzésére, amely megakadályozzák az adott Logger plugin helyes működését. A RestartMe tag segítségével utasíthatjuk a keretet, hogy töltse be újra a Plugint. Célszerű olyan implementáció megvalósítása, amely biztosítja, hogy a Log hívások csak a hiba fellépésekor jelentsenek Error-t, és ne minden egyes Log híváskor, ezzel biztosítani lehet, hogy a Logolás infrastrukturális ellehetetlenítése ne legyen befolyással a program eredeti működésére.

  • Logszintek:

    • A koncepció szerint a logolási szintek kezelése nem a Plugin, hanem a Vrh.Logger keret hatásköre. Ezért a Vrh.Logger keret a saját beállításának megfelelően, nem is intéz Log hívást a plugin felé, ha a logolandó információ nem éri le az aktuálisan beállított logolási szintet. Ennek ellenére a Pluginban szükség lehet a Logolási szint szerepeltetésére, például, hogy mentsük a log bejegyzéssel ezt információt. Lehetőleg ne végezzünk szemantikai tranzformációt a logszintekkel kapcsolatban, és törekedjünk rá, hogy konkrétan a Vrh.Logger által definiált LogLevel enumeratort használjuk. Az itt definiált None érték nem egy valós logszint, a logolás teljes kikapcsolására használja a keret. Ennek megfelelően, ilyen log szint megjelöléssel sose fog a Vrh.Logger keret hívást intézni a Plugin felé.
    • A logszintek teljes definíciója az alábbi a LogLevel enumban: csharp /// <summary> /// A logolás lehetséges szintjei /// </summary> public enum LogLevel { /// <summary> /// Debug részletességet célzó logbejegyzések a működés részletes követésére, hibakeresésre /// </summary> Debug = 1, /// <summary> /// Részletes, bőbeszédű információk szintje /// </summary> Verbose = 2, /// <summary> /// Információk a rendszer működéséről /// </summary> Information = 3, /// <summary> /// Figyelmeztetések szintje /// </summary> Warning = 4, /// <summary> /// A hibák szintje /// </summary> Error = 5, /// <summary> /// A kritikus hibák szintje /// </summary> Fatal = 6, /// <summary> /// None segítségével kikapcsolható a teljes logolás, sose használjuk logbejegyzés szintjeként, mert a VRH.Logger az ilyen bejegyzéseket mindig elutasítja! /// </summary> None = 7, }

Version History:

2.1.0 (2019.11.14)

Compatibility API changes:

  1. A betöltendő logger modulnak a LogConfig xml struktúra UsedLoggerConfig xml elemét átadja paraméterként; ennek tartalmát csak a betöltött logger elemzi és használja;
  2. A fenti xml struktúrát a logger betöltése után annak "Init" nevű publikus metódusán keresztül adja át, amelynek egyetlen paramétere egy XElement típus.;
  3. Az "Init" metódus nem kötelező, ha nem létezik, akkor nem okoz hibát.
  4. Az iLoggerLogger kliens kiegészítésre került az "Init" metódussal, amelyben megkapja a WcfCliens xml struktúrát, ami alapján az XmlProcessing.WCF osztály eszközeivel inicializálja az iLogger szervizhez csatlakozó kliensét, így megadható a connectionstringstore-on keresztül az iLogger szerviz címe.
  5. Ha nincs UsedLoggerConfig vagy benne WCFClient elem, vagy abban nincsenek megadva adatok, akkor a működés a korábbiak szerinti.

2.0.3 (2019.11.06)

Patches:

  1. Webes környezetben való működésképtelenség (path felvételek miatt) hibamentessé tétele
  2. None a defult loglevel, ha config error van
  3. Nem ír Fatal logot sem, ha none a loglevel ## v2.0.2 (2019.11.04) ### Patches:
  4. Load error információk megjelenésének javítása (Error log txt-ben) ## v2.0.1 (2019.10.25) ### Patches:
  5. A nuget csomag telepítéskor elkészíti azt a minimális konfigurációt, ami a telepítés helyén való instant működőképességhez szükséges. (Minden Nuget csomagnak ez lenne a célja a belézárt komponenst illetően: A telepítés teljes automatizálása, ami azonnali használatbavételt tesz lehetővé a telepítés helyén a komponens mélyebb ismerete (pl. konfigurálás módja) nélkül!)
  6. Főverzió emeléskor az Obsolete-nek jelölt elemeket ki kell dobni a kódból, ezt most pótoltam
  7. Instanmt kipróbálhatóság futatahatóság a repoba felrakott állapotban (konfig fájlok tartalma, stb.)

v1.5.7 (2019.06.04)

Patch:

  1. Windows Service-ben a Log bejegyzések előállítása túl időköltséges volt (már a task oldalon) a PID lekérdezések miatt. Állandó lekérdezés helyett áttéve egy Lazy fieldbe. ## v1.5.6 (2019.05.27) ### Patch:
  2. DefualtLogger Txt log implementáció: Logbejegyzések kiegészítése TimeStamp-pel
  3. DefualtLogger Txt log implementáció: A létrehozott logfájl nevébe bekerül prefxként a dátumbélyeg (YYYYMMDD_), így naponta új txt fájl keletkezik, és nem lesznek használhatatlanul nagyok a log fájlok. ## v1.5.5 (2019.05.23) ### Patch:
  4. compatible_Lear branch!!! Nugetek Learhez igazítása ## v1.5.4 (2019.05.21) ### Patch:
  5. To upgrade all Nugets to latest ## V1.5.2 (2018.12.11) ### Patch:
  6. Service név lekérdezésében hiba javítása ## V1.5.1 (2018.12.11) ### Patch:
  7. CallSignature osztály láthatósága .public ## V1.5.0 (2018.12.11) ### Compatibility API changes:
  8. CallSignature osztály bevezetése. ## V1.4.0 (2017.12.06) ### Compatibility API changes:
  9. Logger class funkciója áttéve a VrhLogger-class alá. Ott csak annak a public (API) funkcionalitása maradt, oly módon, hogy áthív a VrhLogger-be. (Hogy ne legyen incompatibility a change.)
  10. A Logger class Obsolote-tal jelölve --> Depcreated! ### Patches:
  11. LogHelper.ExtractPropertyValuesToDataFields null védelme ## V1.3.0 (2017.12.05) ### Compatibility API changes:
  12. LogHelper kiegészítése az ExtractPropertyValuesToDataFields metódussal ## V1.2.0 (2017.08.10) ### Compatibility API changes:
  13. DefaultLogger kiegészítése TXT log file írási kéápességgel
  14. Lehetséges app settings kulcsok kezelésének beépítése a default plugin txt file logolás képesség konfigurációjához (Kulcsok: "Vrh.Logger:EnableFileLogging", "Vrh.Logger:LogDirectory" "Vrh.Logger:LogFile")
  15. LogConfig.xml (config xml) feldolgozó kiegészítése a default plugin txt file logolás képesség kapcsán szükésge súj beállítások kezelésével (Tag: EnableFileLogging (Extended boolean: true|yes|1/false|no|0) lehetséges attríbutumai: LogDirectory="Log" LogFile="Vrh.Logger.TxtLog.log) ### Patches:
  16. LoggerErrorLogFile beállítást valóban figyelembe vegye a belső error log file elnevezésében
  17. A Default logger valóban figyelembe veszi a három leheteséges log target-re engedélyezés van-e konfigurálva, és csak arra ír, amelyikre igen ## V1.1.0 (2017.03.21)
    ### Compatibility API changes:
  18. LogHelper.GetExceptionData bevezetése ### Patches:
  19. Newtonsoft.Json nuget dependency növelése 10.0.1-re
  20. LogHelper.GetExceptionInfo kiegészítése az Exception.Data tartalmának kibontásával ## V1.0.1 (2017.03.21) ### Patches:
  21. Új Vrh.LinqXmlProcesser.Base beépítés
  22. Nuspec fájl javításaok ## V1.0.0 (2017.02.21) Initial version