# 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:** ```csharp /// /// Log bejegyzést ad fel (aszinkron!!!) a logoló modul számára /// /// Típus /// 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 /// A log bejegyzés adatai. Mezőnév/Mezőérték párok listájaként /// Egy exception adható át a Lognak /// 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. /// 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. /// 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. /// 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. static public void Log(T data, IDictionary 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**: ```csharp catch (Exception ex) { VrhLogger.Log("error", null, ex, LogLevel.Error, this.GetType())); } ``` ```csharp VrhLogger.Log(AppDomain.CurrentDomain.ApplicationTrust, null, null, LogLevel.Verbose, typeof(Program)); ``` ```csharp Dictionary logData = new Dictionary() { { "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("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: ```csharp /// /// Egyszerű string adat logolása. /// /// Log üzenet /// Logszint /// 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. /// 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. /// 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. static public void Log(string logMessage, LogLevel level, Type source, [CallerMemberName]string caller = "", [CallerLineNumber]int line = 0) ``` **Példák a használatára**: ```csharp 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: ```csharp /// /// Exception egyszerű logolása /// /// Logolandó kivétel /// 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. /// Logszint /// 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. /// 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. 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**: ```csharp 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:** ```csharp /// /// 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. /// /// A használt konfigurációt jelöli ki 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:** ```csharp 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:** ```csharp /// /// 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 /// /// Erre az értrékre áll be asorszám, ha nincs mergadva, akkor 0 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:** ```csharp 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)*). ```csharp /// /// Visszaadja a kapott időpont nagy pontosságú string reprezentánsát /// /// Időbélyeg jellegű adat /// A kapott időbélyeg stringként 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 /// /// Kiszedi a kapott kivétel adatait egy szöveges leírássá /// /// Exception, amelynek az adatait kigyűjtjük /// Ennyi tab-bal indentálja az információ minden egyes sorát /// A kapott Exception adatai stringként 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 /// /// Visszadja egy IDictionary-ben tárolt kulcs érték párokat (pl.: Exception.Data) /// /// Idictionary gyűjtemény /// Ennyivel lesz beindentálva /// 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 /// /// Tabokkal indentálja a kapott szöveg minden egyes sorát a paraméterben kapott számnak megfelelő számban /// /// Az indentálandó szöveg /// Az indentálás szintje /// Indentált szöveg 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 /// /// Visszaadja a kapott Dictonary tartalmát emberi olvasásra formázott kulcs értékpárok listájaként /// /// Az adatokat tartalmazó Dictionary /// Ennyivel lesz beindentálva /// Az adatok formázott stringként public static string GetDictionaryInfo(IDictionary 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 /// /// 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. /// /// A vezérlőkaraktereket is tartalmazó szöveg (string) /// A formázott szöveg indentálásának a mértéke /// A vezérlőkarakterek hexakódjainak keretezésére ezt használja nyitó karakternek /// A vezérlőkarakterek hexakódjainak keretezésére ezt használja záró karakternek /// A formázott szöveg 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 /// /// 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. /// /// Típus kijelölő /// Az értékeket tartalmazó tömb /// A formázott szöveg indentálásának a mértéke /// Az értékeket egymástól elválasztó karakter a formázott szövegben. /// a formázott szöveg public static string ArrayToHumanReadableString(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 /// /// 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 /// /// A konvertálandó bytok sorozata /// A formázott szöveg indentálásának a mértéke /// A formázott szöveg 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 /// /// Egy byte sorozatot HexBlock formázású, emberi olvasásra szánt stringgé alakít /// /// a bemenő bájtsorozat /// megadja, hogy az első sor egy header legyen, amely magyarázza az adattartalmat /// megadja, hogy legyen e egy hexablock véget értét hangsúlyozó lezárás a block végén /// Beállítható vele, a használt karakter encoding, alapértelmezésben ASCII-t fog használni /// Annyivel indentálja a hexa blockot /// a formázott szöveg 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 /// /// 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) /// /// Ezzel az objektum típussal dolgozik /// Ezzel a példánnyal /// név-érték párok litáájaként a property-k neve és értéke public static Dictionary ExtractPropertyValuesToDataFields(TClass instance) ``` ### Konfiguráció: A Vrh.Logger konfigurációjának megadásához kétféle módszert támogat: 1. Vagy egy az alkalmazástér konfigurációjából vesz fel appSettings kulcsokat. 2. 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: ```xml Warning True True True DefaultLogger tetszőleges xml szabványos tartalom Log Vrh.Logger.Errors.log ``` 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 ``` 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;** ```xml Warning True True True DefaultLogger Log Vrh.Logger.Errors.log ``` Ha a file csak a Vrh.Logger paramétereit tartalmazza, akkor pedig: **file=~Config.xml;** ```xml Warning True True True DefaultLogger Log Vrh.Logger.Errors.log ``` * 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: ```xml ``` #### 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: ```csharp /// /// 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! /// public interface ILogger : IDisposable { /// /// 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! /// /// Típuskijelölő /// Log sorszáma a Logger létrejötte óta az adott alkalmazástérben /// A kijelölt típusú adat /// Kulcs érték párok listájaként átadott adatok /// Egy exceptiont lehet ide bedobni, hogy a Logger az alapján logolja az exception fontos részleteit /// A log szintje ennek a bejegyzésnek /// Forrásmodul a Logger static Log hívásnak átadott típust deklaráló assembly neve kerül bele /// Forrásmodul verziója. Az assemblyben definiált AssemblyInformationalVersion, annak hiányában a definiált AssemblyVersion /// Az osztály teljes neve, ahonnan a Log bejegyzést bedobták /// 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) /// 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) /// A hívás időbéjege void Log(UInt64 noOfLogEntry, T data, IDictionary dataFields, Exception exception, LogLevel level, string sourceModul, string sourceModulVersion, string sourceClass, string sourceMethode, int line, DateTime callTimeStamp); /// /// 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!!! /// 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((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 > /// > /// 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!!! > /// > 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 > /// > /// Delegeta definició, a FatalErrorInPlugin event kezeléséhez > /// > /// 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 > /// Az esemény argumentumai, egy szöveges üzenetet, és egy tetszőleges szabványos Exception átadását támogatja > 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; } /// /// Itt adhatjuk át a feléppő, vagy a kiváltott Exception-t /// public Exception Exception { get; set; } /// /// Jelzi a logger keretnek, hogy indítsa újra a plugint /// 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: >```csharp > /// > /// FatalErrorInPlugin esemény (ILogger interfész member) > /// > public event FatalErrorInPluginEventHandler FatalErrorInPlugin; > > /// > /// Metódus a FatalErrorInPlugin esemény elsütésére > /// > /// Menteni kívánt kivétel > /// Szabadon beállítható üzenet a hibával kapcsolatban > 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 > /// > /// A logolás lehetséges szintjei > /// > public enum LogLevel > { > /// > /// Debug részletességet célzó logbejegyzések a működés részletes követésére, hibakeresésre > /// > Debug = 1, > /// > /// Részletes, bőbeszédű információk szintje > /// > Verbose = 2, > /// > /// Információk a rendszer működéséről > /// > Information = 3, > /// > /// Figyelmeztetések szintje > /// > Warning = 4, > /// > /// A hibák szintje > /// > Error = 5, > /// > /// A kritikus hibák szintje > /// > Fatal = 6, > /// > /// 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! > /// > 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: 1. Load error információk megjelenésének javítása (Error log txt-ben) ## v2.0.1 (2019.10.25) ### Patches: 1. 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!**) 2. Főverzió emeléskor az Obsolete-nek jelölt elemeket ki kell dobni a kódból, ezt most pótoltam 3. 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: 1. DefualtLogger Txt log implementáció: Logbejegyzések kiegészítése TimeStamp-pel 2. 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: 1. compatible_Lear branch!!! Nugetek Learhez igazítása ## v1.5.4 (2019.05.21) ### Patch: 1. To upgrade all Nugets to latest ## V1.5.2 (2018.12.11) ### Patch: 1. Service név lekérdezésében hiba javítása ## V1.5.1 (2018.12.11) ### Patch: 1. CallSignature osztály láthatósága .public ## V1.5.0 (2018.12.11) ### Compatibility API changes: 1. CallSignature osztály bevezetése. ## V1.4.0 (2017.12.06) ### Compatibility API changes: 1. 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.) 2. A Logger class Obsolote-tal jelölve --> Depcreated! ### Patches: 1. LogHelper.ExtractPropertyValuesToDataFields null védelme ## V1.3.0 (2017.12.05) ### Compatibility API changes: 1. LogHelper kiegészítése az ExtractPropertyValuesToDataFields metódussal ## V1.2.0 (2017.08.10) ### Compatibility API changes: 1. DefaultLogger kiegészítése TXT log file írási kéápességgel 2. 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") 3. 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: 1. LoggerErrorLogFile beállítást valóban figyelembe vegye a belső error log file elnevezésében 2. 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: 1. LogHelper.GetExceptionData bevezetése ### Patches: 1. Newtonsoft.Json nuget dependency növelése 10.0.1-re 2. LogHelper.GetExceptionInfo kiegészítése az Exception.Data tartalmának kibontásával ## V1.0.1 (2017.03.21) ### Patches: 1. Új Vrh.LinqXmlProcesser.Base beépítés 2. Nuspec fájl javításaok ## V1.0.0 (2017.02.21) Initial version