From 2352c68dd004f3d7fe07db68d7cddfc2c0bbd0cd Mon Sep 17 00:00:00 2001 From: Schwirg László Date: Thu, 27 Apr 2023 18:50:36 +0200 Subject: [PATCH] - Hangfire beillesztése folyamatban --- Vrh.Web.Reporting/Global.asax.cs | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------- Vrh.Web.Reporting/LogConfig.xml | 17 +++++++++++++++++ Vrh.Web.Reporting/Vrh.NugetModuls.Documentations/Vrh.Logger/ReadMe.md | 607 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Vrh.Web.Reporting/Vrh.Web.Reporting.csproj | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- Vrh.Web.Reporting/Web.config | 7 ++++++- Vrh.Web.Reporting/packages.config | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- Vrh.Web.iScheduler.Lib/Vrh.Web.iScheduler.Lib.csproj | 7 ------- Vrh.Web.iScheduler.Lib/iSchedulerHangfire.cs | 32 -------------------------------- Vrh.Web.iScheduler.Lib/packages.config | 3 --- Vrh.iScheduler/App.config | 31 +++++++++++++++++-------------- Vrh.iScheduler/Monitor .cs | 38 ++++++++++++++++++++++++++++++++------ Vrh.iScheduler/Vrh.iScheduler.csproj | 19 +++++++++++++++++-- Vrh.iScheduler/packages.config | 8 +++++++- iSchedulerMonitor/App.config | 44 ++++++++++++++++++++++---------------------- iSchedulerMonitor/iSchedulerMonitor.ACPlugin.csproj | 8 ++++---- iSchedulerMonitor/packages.config | 2 +- 16 files changed, 1104 insertions(+), 155 deletions(-) create mode 100644 Vrh.Web.Reporting/LogConfig.xml create mode 100644 Vrh.Web.Reporting/Vrh.NugetModuls.Documentations/Vrh.Logger/ReadMe.md delete mode 100644 Vrh.Web.iScheduler.Lib/iSchedulerHangfire.cs diff --git a/Vrh.Web.Reporting/Global.asax.cs b/Vrh.Web.Reporting/Global.asax.cs index 53fd9bd..b4c66cf 100644 --- a/Vrh.Web.Reporting/Global.asax.cs +++ b/Vrh.Web.Reporting/Global.asax.cs @@ -1,47 +1,69 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Linq; +using System.Net; +using System.Threading; using System.Web; using System.Web.Hosting; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; +using System.Xml.Linq; using Hangfire; -using Vrh.Web.iScheduler; +using Microsoft.Web.Administration; +using Vrh.iScheduler; +using Vrh.Logger; namespace Vrh.Web.Reporting { public class MvcApplication : System.Web.HttpApplication { - const string HANGFIRESQLDBCONNECTIONSTRINGNAME = "MAINDBLOG4PRO"; protected void Application_Start() { + (new DCLogEntry(LogLevel.Information, "Vrh.Web.Reporting.MvcApplication.Application_Start")).Write(); AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); - HangfireBootstrapper.Instance.SqlDBconnectionstring= Vrh.XmlProcessing.ConnectionStringStore.GetSQL(HANGFIRESQLDBCONNECTIONSTRINGNAME); - HangfireBootstrapper.Instance.Start(); - new iSchedulerHangfire(HangfireBootstrapper.Instance._backgroundJobServer); + ////////////////////////////////////////////////////////////////////////////////////// + ///Enable webApp pool autostart, preload and alwaysrun + ////////////////////////////////////////////////////////////////////////////////////// + /// For web applications running on servers under your control, either physical or virtual, you can use the auto-start feature of IIS ≥ 7.5 shipped with + /// Windows Server ≥ 2008 R2. Full setup requires the following steps to be done. Enable automatic start and AlwaysRunning mode for Application pool + /// and configure Auto - start feature as written below. + /// Edit the following file: C:\Windows\System32\inetsrv\config\applicationHost.config. + /// All edits should be made below the section. + /// In the section find the tag of the application pool to be autostarted. + /// Add autoStart="true" and startMode="AlwaysRunning" attributes to this tag. + /// In the section find the tag of the web application + /// running on the application pool with name "YourApplicationPoolName". + /// Add serviceAutoStartEnabled="true" and serviceAutoStartProvider="AnyNameForYourAutoStartProvider" attributes to this tag. + /// Here YourWebsiteName is the name of the website where the web application, using the application pool belongs to. + /// In the section create the following element: + /// + /// Here AnyNameForYourAutoStartProvider can be any name, that is suitable for the xml standard. + /// Here FullTypeNameOfTheAutostartProviderClass is the full type name (with namespace and class name) of the class that matches the IProcessHostPreloadClient interface; + /// this class should not be within the root class of the mvc application, but for example another class on the same level! For what is in this code the tag is the following: + /// + /// Here NameOfTheAssemblyContainingTheAutostartProviderClass is the name of (for example the dll), but without the extension. + ////////////////////////////////////////////////////////////////////////////////////// + + (new ApplicationPreload())._Preload(); //Vrh.Web.Menu inicializáló beállításai Vrh.Web.Menu.Global.CustomerLogo = "~/Content/Images/Menu_LearLogo.jpg"; // ! ha azt szeretnénk, hogy a menükezelő kezelje a hitelesítést is, // ! akkor ezt itt igaz értékre kell állítani Vrh.Web.Menu.Global.IsUseAuthentication = true; -} - - public class ApplicationPreload : System.Web.Hosting.IProcessHostPreloadClient - { - public void Preload(string[] parameters) - { - HangfireBootstrapper.Instance.SqlDBconnectionstring= Vrh.XmlProcessing.ConnectionStringStore.GetSQL(HANGFIRESQLDBCONNECTIONSTRINGNAME); - HangfireBootstrapper.Instance.Start(); - } } + + protected void Application_End(object sender, EventArgs e) { + (new DCLogEntry(LogLevel.Information, "Vrh.Web.Reporting.MvcApplication.Application_End")).Write(); HangfireBootstrapper.Instance.Stop(); } /// @@ -54,54 +76,200 @@ namespace Vrh.Web.Reporting { //int i = 1; } - public class HangfireBootstrapper : IRegisteredObject + } + public class ApplicationPreload : System.Web.Hosting.IProcessHostPreloadClient + { + public void Preload(string[] parameters) { - public static readonly HangfireBootstrapper Instance = new HangfireBootstrapper(); - public BackgroundJobServer _backgroundJobServer { get; set; } - public string SqlDBconnectionstring { get; set; } = null; - private readonly object _lockObject = new object(); - private bool _started; + (new DCLogEntry(LogLevel.Information, "Vrh.Web.Reporting.ApplicationPreload")).Write(); + _Preload(); + } + public void _Preload() + { + SetupAutoStart(typeof(ApplicationPreload)); + HangfireBootstrapper.Instance.SqlDBconnectionstring = Vrh.XmlProcessing.ConnectionStringStore.GetSQL(HANGFIRESQLDBCONNECTIONSTRINGNAME); + HangfireBootstrapper.Instance.Start(); + Vrh.iScheduler.Monitor.InitHangfire(HangfireBootstrapper.Instance._backgroundJobServer); + } + public const string HANGFIRESQLDBCONNECTIONSTRINGNAME = "MAINDBLOG4PRO"; + public const string CONFIGFILEDIRECTORY = @"inetsrv\config"; + public const string CONFIGFILENAME = @"applicationHost.config"; + //public const string FILEPATH = @"C:\temp\applicationHost.config"; + public const string POOLNAME = "Log4ProIS_REPORTING"; + public const string WEBAPPNAME = "/Log4ProIS-REPORTING"; + public const string WEBSITENAME = "Default Web Site"; + public const string AUTOSTARTPROVIDERNAME = "ApplicationPreload"; + public const string AUTOSTARTPROVIDERTYPENAME = "Vrh.Web.Reporting.ApplicationPreload"; + public const string AUTOSTARTPROVIDERASSEMBLYNAME = "Vrh.Web.Reporting"; - private HangfireBootstrapper() - { - } + public static bool SetupAutoStart(Type serviceAutoStartProviderType) + { + const string SYSTEMAPPLICATIONHOST_ELEMENT = "system.applicationHost"; + const string APPLICATIONPOOLS_ELEMENT = "applicationPools"; + const string SITES_ELEMENT = "sites"; + const string SERVICEAUTOSTARTPROVIDERS_ELEMENT = "serviceAutoStartProviders"; + const string SITE_ELEMENT = "site"; + const string APPLICATION_ELEMENT = "application"; + const string ADD_ELEMENT = "add"; + const string NAME_ATTRIBUTE = "name"; + const string TYPE_ATTRIBUTE = "type"; + const string SERVICEAUTOSTARTENABLED_ATTRIBUTE = "serviceAutoStartEnabled"; + const string SERVICEAUTOSTARTPROVIDER_ATTRIBUTE = "serviceAutoStartProvider"; + const string APPLICATIONPOOL_ATTRIBUTE = "applicationPool"; + const string PATH_ATTRIBUTE = "path"; + const string AUTOSTART_ATTRIBUTE = "autoStart"; + const string STARTMODE_ATTRIBUTE = "startMode"; - public void Start() + string applicationpoolname = GetCurrentApplicationPoolName(); + string websitename = System.Web.Hosting.HostingEnvironment.SiteName; + string webapplicationname = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath; + string autostartprovidername = (websitename + "____" + applicationpoolname + "____" + webapplicationname).Replace(" ", "_").Replace("-", "_").Replace("/", "_"); + string serviceAutoStartProviderTypeFullName = serviceAutoStartProviderType.FullName; + string serviceAutoStartProviderAssassemblyName = serviceAutoStartProviderType.Assembly.GetName().Name; + var le = new DCLogEntry(LogLevel.Information, "Vrh.Web.Reporting.MvcApplication.SetupAutoStart"); + try { - lock (_lockObject) - { - if (_started) return; - _started = true; + string configfilepath = Path.Combine(NativeSystemPath, CONFIGFILEDIRECTORY, CONFIGFILENAME); + le.AddDataField("configfilepath", configfilepath); + le.AddDataField("applicationpoolname", applicationpoolname); + le.AddDataField("websitename", websitename); + le.AddDataField("webapplicationname", webapplicationname); + le.AddDataField("serviceAutoStartProviderTypeFullName", serviceAutoStartProviderTypeFullName); + le.AddDataField("serviceAutoStartProviderAssassemblyName", serviceAutoStartProviderAssassemblyName); + + + var filecontent = System.IO.File.ReadAllText(configfilepath); + XElement configxml = XElement.Parse(filecontent, LoadOptions.PreserveWhitespace); //XElement.Load(configfilepath); + + XElement myconfigrootxml = configxml.Element(XName.Get(SYSTEMAPPLICATIONHOST_ELEMENT)); + XElement myapplicationpooladdelement = myconfigrootxml?.Element(XName.Get(APPLICATIONPOOLS_ELEMENT))? + .Elements(XName.Get(ADD_ELEMENT))?.FirstOrDefault(e => e.Attribute(XName.Get(NAME_ATTRIBUTE)).Value == applicationpoolname); + XElement mysiteapplicationelement = myconfigrootxml?.Element(XName.Get(SITES_ELEMENT))? + .Elements(XName.Get(SITE_ELEMENT))?.FirstOrDefault(e => e.Attribute(XName.Get(NAME_ATTRIBUTE)).Value == websitename) + .Elements(XName.Get(APPLICATION_ELEMENT))?.FirstOrDefault(e => e.Attribute(XName.Get(PATH_ATTRIBUTE)).Value == webapplicationname && e.Attribute(XName.Get(APPLICATIONPOOL_ATTRIBUTE)).Value == applicationpoolname); + if (myapplicationpooladdelement == null) return false; + if (mysiteapplicationelement == null) return false; - HostingEnvironment.RegisterObject(this); + bool configchanged = false; + configchanged = SetOrAddAttribute(AUTOSTART_ATTRIBUTE, myapplicationpooladdelement, "true") || configchanged; + configchanged = SetOrAddAttribute(STARTMODE_ATTRIBUTE, myapplicationpooladdelement, "AlwaysRunning") || configchanged; + configchanged = SetOrAddAttribute(SERVICEAUTOSTARTENABLED_ATTRIBUTE, mysiteapplicationelement, "true") || configchanged; + configchanged = SetOrAddAttribute(SERVICEAUTOSTARTPROVIDER_ATTRIBUTE, mysiteapplicationelement, autostartprovidername) || configchanged; - GlobalConfiguration.Configuration - .UseSqlServerStorage(SqlDBconnectionstring) - // Specify other options here - ; + XElement myautostartproviderselement = null; + XElement myautostartprovideraddelement = null; + configchanged = SetOrAddElement(SERVICEAUTOSTARTPROVIDERS_ELEMENT, myconfigrootxml, "", out myautostartproviderselement) || configchanged; + configchanged = SetOrAddElementWithSelectorAttribute(ADD_ELEMENT, myautostartproviderselement, NAME_ATTRIBUTE, autostartprovidername, "", out myautostartprovideraddelement) || configchanged; + configchanged = SetOrAddAttribute(TYPE_ATTRIBUTE, myautostartprovideraddelement, $"{serviceAutoStartProviderTypeFullName},{serviceAutoStartProviderAssassemblyName }") || configchanged; - _backgroundJobServer = new BackgroundJobServer(); + if (configchanged) + { + //configxml.Save(configfilepath); + System.IO.File.WriteAllText(configfilepath, configxml.ToString()); } + le.AddDataField("configchanged", configchanged); + //le.AddDataField("myconfigrootxml", myconfigrootxml); + le.AddSuccessResult("SUCCESS"); + return true; } - - public void Stop() + catch (Exception ex) { le.AddExceptionResult(ex); le.SetLogLevel(LogLevel.Error); return false; } + finally { le.Write(); } + } + private static bool SetOrAddElement(string elementname, XElement elementcontainer, string elementvalue, out XElement myelement) + { + bool configchanged = false; + myelement = elementcontainer?.Element(XName.Get(elementname)); + if (myelement == null) { myelement = new XElement(XName.Get(elementname), ""); elementcontainer.Add(myelement); configchanged = true; } + if (myelement.Value != elementvalue) { myelement.Value = elementvalue; configchanged = true; } + return configchanged; + } + private static bool SetOrAddElementWithSelectorAttribute(string elementname, XElement elementcontainer, string selectorattributename, string selectorattributevalue, string elementvalue, out XElement myelement) + { + bool configchanged = false; + myelement = elementcontainer?.Elements(XName.Get(elementname))?.FirstOrDefault(e => e.Attribute(XName.Get(selectorattributename)).Value == selectorattributevalue); + if (myelement == null) { - lock (_lockObject) + myelement = new XElement(XName.Get(elementname), ""); + elementcontainer.Add(myelement); + SetOrAddAttribute(selectorattributename, myelement, selectorattributevalue); + configchanged = true; + } + if (myelement.Value != elementvalue) { myelement.Value = elementvalue; configchanged = true; } + return configchanged; + } + private static bool SetOrAddAttribute(string attrname, XElement attrcontainer, string attrvalue) + { + bool configchanged = false; + XAttribute attr = attrcontainer.Attribute(XName.Get(attrname)); + if (attr == null) { attr = new XAttribute(XName.Get(attrname), ""); attrcontainer.Add(attr); configchanged = true; } + if (attr.Value != attrvalue) { attr.Value = attrvalue; configchanged = true; } + return configchanged; + } + public static string NativeSystemPath + { + get + { + if (Environment.Is64BitOperatingSystem) { - if (_backgroundJobServer != null) - { - _backgroundJobServer.Dispose(); - } - - HostingEnvironment.UnregisterObject(this); + return System.IO.Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.Windows), + "Sysnative"); } + return Environment.GetFolderPath(Environment.SpecialFolder.System); + } + } + + public static string GetCurrentApplicationPoolName() + { + string appPoolName = string.Empty; + foreach (Application app in (new ServerManager()).Sites[System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName()].Applications) + { + if (app.Path == HttpRuntime.AppDomainAppVirtualPath) { appPoolName = app.ApplicationPoolName; } + } + return appPoolName; + } + } + public class HangfireBootstrapper : IRegisteredObject + { + public static readonly HangfireBootstrapper Instance = new HangfireBootstrapper(); + public BackgroundJobServer _backgroundJobServer { get; set; } + public string SqlDBconnectionstring { get; set; } = null; + private readonly object _lockObject = new object(); + private bool _started; + + + private HangfireBootstrapper() + { + } + + public void Start() + { + lock (_lockObject) + { + if (_started) return; + _started = true; + + HostingEnvironment.RegisterObject(this); + + GlobalConfiguration.Configuration + .UseSqlServerStorage(SqlDBconnectionstring) + // Specify other options here + ; + + _backgroundJobServer = new BackgroundJobServer(); } + } - void IRegisteredObject.Stop(bool immediate) + public void Stop() + { + lock (_lockObject) { - Stop(); + if (_backgroundJobServer != null) { _backgroundJobServer.Dispose(); } + HostingEnvironment.UnregisterObject(this); } } + + void IRegisteredObject.Stop(bool immediate) { Stop(); } } } diff --git a/Vrh.Web.Reporting/LogConfig.xml b/Vrh.Web.Reporting/LogConfig.xml new file mode 100644 index 0000000..427b24e --- /dev/null +++ b/Vrh.Web.Reporting/LogConfig.xml @@ -0,0 +1,17 @@ + + + + Debug + + True + + True + + True + + DefaultLogger + + Log + + Vrh.Logger.Errors.log + \ No newline at end of file diff --git a/Vrh.Web.Reporting/Vrh.NugetModuls.Documentations/Vrh.Logger/ReadMe.md b/Vrh.Web.Reporting/Vrh.NugetModuls.Documentations/Vrh.Logger/ReadMe.md new file mode 100644 index 0000000..2be12e3 --- /dev/null +++ b/Vrh.Web.Reporting/Vrh.NugetModuls.Documentations/Vrh.Logger/ReadMe.md @@ -0,0 +1,607 @@ +# 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 diff --git a/Vrh.Web.Reporting/Vrh.Web.Reporting.csproj b/Vrh.Web.Reporting/Vrh.Web.Reporting.csproj index 6bbccf6..73ce1b4 100644 --- a/Vrh.Web.Reporting/Vrh.Web.Reporting.csproj +++ b/Vrh.Web.Reporting/Vrh.Web.Reporting.csproj @@ -15,8 +15,8 @@ {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} Library Properties - Vrh.Web.iScheduler - Vrh.Web.iScheduler + Vrh.Web.Reporting + Vrh.Web.Reporting v4.6.2 false true @@ -78,11 +78,11 @@ ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll - - ..\packages\Hangfire.Core.1.7.34\lib\net46\Hangfire.Core.dll + + ..\packages\Hangfire.Core.1.8.0-rc4\lib\net46\Hangfire.Core.dll - - ..\packages\Hangfire.SqlServer.1.7.34\lib\net45\Hangfire.SqlServer.dll + + ..\packages\Hangfire.SqlServer.1.8.0-rc4\lib\net451\Hangfire.SqlServer.dll ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.3.6.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll @@ -106,21 +106,27 @@ ..\packages\Microsoft.SqlServer.Types.11.0.0\lib\net20\Microsoft.SqlServer.Types.dll + + ..\packages\Microsoft.Web.Administration.11.1.0\lib\netstandard1.5\Microsoft.Web.Administration.dll + ..\packages\Microsoft.Web.Infrastructure.2.0.1\lib\net40\Microsoft.Web.Infrastructure.dll ..\packages\Microsoft.AspNet.Mvc.Futures.5.0.0\lib\net40\Microsoft.Web.Mvc.dll + + ..\packages\Microsoft.Win32.Primitives.4.0.1\lib\net46\Microsoft.Win32.Primitives.dll + + + ..\packages\Microsoft.Win32.Registry.4.0.0\lib\net46\Microsoft.Win32.Registry.dll + ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll ..\packages\Owin.1.0\lib\net40\Owin.dll - - ..\packages\Owin.1.0\lib\net40\Owin.dll - ..\packages\PagedList.1.17.0.0\lib\net40\PagedList.dll @@ -128,13 +134,92 @@ ..\packages\PagedList.Mvc.4.5.0.0\lib\net40\PagedList.Mvc.dll + + ..\packages\System.AppContext.4.1.0\lib\net46\System.AppContext.dll + + + + ..\packages\System.Console.4.0.0\lib\net46\System.Console.dll + + + ..\packages\System.Diagnostics.DiagnosticSource.4.0.0\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.Diagnostics.TraceSource.4.0.0\lib\net46\System.Diagnostics.TraceSource.dll + + + ..\packages\System.Diagnostics.Tracing.4.1.0\lib\net462\System.Diagnostics.Tracing.dll + + + ..\packages\System.Globalization.Calendars.4.0.1\lib\net46\System.Globalization.Calendars.dll + + + ..\packages\System.IO.4.1.0\lib\net462\System.IO.dll + + + ..\packages\System.IO.Compression.4.1.0\lib\net46\System.IO.Compression.dll + + + + ..\packages\System.IO.Compression.ZipFile.4.0.1\lib\net46\System.IO.Compression.ZipFile.dll + + + ..\packages\System.IO.FileSystem.4.0.1\lib\net46\System.IO.FileSystem.dll + + + ..\packages\System.IO.FileSystem.Primitives.4.0.1\lib\net46\System.IO.FileSystem.Primitives.dll + - - - + + ..\packages\System.Net.Http.4.1.0\lib\net46\System.Net.Http.dll + + + ..\packages\System.Net.Sockets.4.1.0\lib\net46\System.Net.Sockets.dll + + + + ..\packages\System.Reflection.4.1.0\lib\net462\System.Reflection.dll + + + ..\packages\System.Reflection.TypeExtensions.4.4.0\lib\net461\System.Reflection.TypeExtensions.dll + + + ..\packages\System.Runtime.4.1.0\lib\net462\System.Runtime.dll + + + ..\packages\System.Runtime.Extensions.4.1.0\lib\net462\System.Runtime.Extensions.dll + + + ..\packages\System.Runtime.InteropServices.4.1.0\lib\net462\System.Runtime.InteropServices.dll + + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + + + ..\packages\System.Security.Claims.4.0.1\lib\net46\System.Security.Claims.dll + + + ..\packages\System.Security.Cryptography.Algorithms.4.2.0\lib\net461\System.Security.Cryptography.Algorithms.dll + + + ..\packages\System.Security.Cryptography.Encoding.4.0.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\packages\System.Security.Cryptography.Primitives.4.0.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.1.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + + + ..\packages\System.Security.Principal.Windows.4.0.0\lib\net46\System.Security.Principal.Windows.dll + + + + ..\packages\System.ServiceProcess.ServiceController.4.1.0\lib\net461\System.ServiceProcess.ServiceController.dll + @@ -172,8 +257,6 @@ - - @@ -192,6 +275,9 @@ ..\packages\VRH.Log4Pro.WebTools.1.11.1\lib\net451\VRH.Log4Pro.WebTools.dll + + ..\packages\Vrh.Logger.2.9.4\lib\net451\Vrh.Logger.dll + ..\packages\Vrh.Membership.4.11.0\lib\net451\Vrh.Membership.dll @@ -566,6 +652,9 @@ + + Always + @@ -813,6 +902,7 @@ + diff --git a/Vrh.Web.Reporting/Web.config b/Vrh.Web.Reporting/Web.config index 8b81949..de9ab1e 100644 --- a/Vrh.Web.Reporting/Web.config +++ b/Vrh.Web.Reporting/Web.config @@ -11,6 +11,7 @@ + @@ -107,7 +108,7 @@ - + @@ -157,6 +158,10 @@ + + + + diff --git a/Vrh.Web.Reporting/packages.config b/Vrh.Web.Reporting/packages.config index 9a548b7..fe38514 100644 --- a/Vrh.Web.Reporting/packages.config +++ b/Vrh.Web.Reporting/packages.config @@ -7,9 +7,9 @@ - - - + + + @@ -30,24 +30,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Vrh.Web.iScheduler.Lib/Vrh.Web.iScheduler.Lib.csproj b/Vrh.Web.iScheduler.Lib/Vrh.Web.iScheduler.Lib.csproj index ad41d2f..bc03260 100644 --- a/Vrh.Web.iScheduler.Lib/Vrh.Web.iScheduler.Lib.csproj +++ b/Vrh.Web.iScheduler.Lib/Vrh.Web.iScheduler.Lib.csproj @@ -46,12 +46,6 @@ ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll - - ..\packages\Hangfire.Core.1.7.34\lib\net46\Hangfire.Core.dll - - - ..\packages\Hangfire.SqlServer.1.7.34\lib\net45\Hangfire.SqlServer.dll - ..\packages\Microsoft.AspNetCore.Hosting.2.2.7\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.dll @@ -316,7 +310,6 @@ - diff --git a/Vrh.Web.iScheduler.Lib/iSchedulerHangfire.cs b/Vrh.Web.iScheduler.Lib/iSchedulerHangfire.cs deleted file mode 100644 index 8c0d9f3..0000000 --- a/Vrh.Web.iScheduler.Lib/iSchedulerHangfire.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Hangfire; -using Vrh.iScheduler; - -namespace Vrh.Web.iScheduler -{ - public class iSchedulerHangfire - { - public iSchedulerHangfire(BackgroundJobServer backgroundserver) - { - string ischedulerMonitorXml = "config=ALMiSchedulerMonitor";//TODO:hogy lehet ezt paraméterben átadni?????? - string ischedulerXml = ""; // vagy "config=ALMiScheduler;"; - var m_xmlp = new iSchedulerXMLProcessor(ischedulerMonitorXml, ischedulerXml); - if (m_xmlp.EnableWebAppExecution && m_xmlp.CheckInterval > 0) - { - string intervalcron = Cron.MinuteInterval((int)(m_xmlp.CheckInterval / 60));//"*/1 * * * *" - - //C:\Windows\system32>%windir%\system32\inetsrv\appcmd set config /section:applicationPools /[name='Log4ProIS'].autoStart:true - - _backgroundJobServer = backgroundserver ?? (new BackgroundJobServer()); - BackgroundJob.Enqueue(() => new Monitor(m_xmlp).Examination(null)); - //RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor(m_xmlp).Examination(null), intervalcron); //minutes interval - //RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor(m_xmlp).Examination(null), $"{(int)(m_xmlp.CheckInterval / 60)} * * * *"); // cron expression - } - } - private BackgroundJobServer _backgroundJobServer; - } -} diff --git a/Vrh.Web.iScheduler.Lib/packages.config b/Vrh.Web.iScheduler.Lib/packages.config index f8e12e2..c0b5b8f 100644 --- a/Vrh.Web.iScheduler.Lib/packages.config +++ b/Vrh.Web.iScheduler.Lib/packages.config @@ -2,9 +2,6 @@ - - - diff --git a/Vrh.iScheduler/App.config b/Vrh.iScheduler/App.config index 7b26c26..dc9adf5 100644 --- a/Vrh.iScheduler/App.config +++ b/Vrh.iScheduler/App.config @@ -1,36 +1,39 @@ - + -
+
- + - - + + - - + + - - + + - - + + - - + + - + + + + \ No newline at end of file diff --git a/Vrh.iScheduler/Monitor .cs b/Vrh.iScheduler/Monitor .cs index 81c4ec3..8875527 100644 --- a/Vrh.iScheduler/Monitor .cs +++ b/Vrh.iScheduler/Monitor .cs @@ -14,11 +14,29 @@ using System.Timers; using Vrh.Logger; using System.Data.SqlClient; using System.Xml.Linq; - +using Hangfire; +using Hangfire.Storage; namespace Vrh.iScheduler { + public class Monitor : IDisposable { + public static void InitHangfire(BackgroundJobServer backgroundserver) + { + string ischedulerMonitorXml = "config=ALMiSchedulerMonitor";//TODO:hogy lehet ezt paraméterben átadni?????? + string ischedulerXml = ""; // vagy "config=ALMiScheduler;"; + var m_xmlp = new iSchedulerXMLProcessor(ischedulerMonitorXml, ischedulerXml); + Monitor.SetiSchedulerCommonXMLProcessor(m_xmlp); + if (m_xmlp.EnableWebAppExecution && m_xmlp.CheckInterval > 0) + { + string intervalcron = Cron.MinuteInterval((int)(m_xmlp.CheckInterval / 60));//"*/1 * * * *" + //RecurringJob.RemoveIfExists("ischedulermonitorcycle"); + RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor().Examination(null), intervalcron); + //var HanfireJobId = BackgroundJob.Enqueue(() => new Monitor().Examination(null)); + //RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor(m_xmlp).Examination(null), intervalcron); //minutes interval + //RecurringJob.AddOrUpdate("ischedulermonitorcycle", () => new Monitor(m_xmlp).Examination(null), $"{(int)(m_xmlp.CheckInterval / 60)} * * * *"); // cron expression + } + } #region Enums /// /// Ütemezések lehetséges állapotai. @@ -46,7 +64,11 @@ namespace Vrh.iScheduler private Timer m_timer; private iSchedulerXMLProcessor m_xmlp; - + private static iSchedulerXMLProcessor CommonM_xmlp; + public static void SetiSchedulerCommonXMLProcessor(iSchedulerXMLProcessor m_xmlp) + { + CommonM_xmlp = m_xmlp; + } #endregion Privates #region Constructor @@ -60,19 +82,22 @@ namespace Vrh.iScheduler /// a távoli gépen. Ha egy gépen fut, akkor nem kötelező. public Monitor(string scheduleMonitorXmlPath, string scheduleXmlPath) { - m_xmlp = new iSchedulerXMLProcessor(scheduleMonitorXmlPath, scheduleXmlPath); - Init(m_xmlp); + Init(new iSchedulerXMLProcessor(scheduleMonitorXmlPath, scheduleXmlPath)); } public Monitor(iSchedulerXMLProcessor m_xmlp) { Init(m_xmlp); } + public Monitor() + { + Init(CommonM_xmlp); + } private void Init(iSchedulerXMLProcessor m_xmlp) { + this.m_xmlp = m_xmlp; //try //{ - m_timer = new Timer(m_xmlp.CheckInterval * 1000); // !!! Ez itt a jó sor !!! - // m_timer = new Timer(20000); // !!! Ez meg itt a debug !!! + m_timer = new Timer(m_xmlp.CheckInterval * 1000); // !!! Ez itt a jó sor !!! m_timer = new Timer(20000); meg a debug !!! m_timer.Elapsed += OnExamination; var le = new DCLogEntry(LogLevel.Debug, nameof(Monitor) + " constructor. Preparation ready."); @@ -118,6 +143,7 @@ namespace Vrh.iScheduler /// Időzített események megkeresése, és végrehajtása. /// /// + [DisableConcurrentExecution(1000)] public void Examination(DateTime? signalTime) { var le = new DCLogEntry(LogLevel.Debug,nameof(Examination)); diff --git a/Vrh.iScheduler/Vrh.iScheduler.csproj b/Vrh.iScheduler/Vrh.iScheduler.csproj index 55d1957..5ffcc5e 100644 --- a/Vrh.iScheduler/Vrh.iScheduler.csproj +++ b/Vrh.iScheduler/Vrh.iScheduler.csproj @@ -41,6 +41,18 @@ ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll + + ..\packages\Hangfire.Core.1.8.0-rc4\lib\net46\Hangfire.Core.dll + + + ..\packages\Hangfire.SqlServer.1.8.0-rc4\lib\net451\Hangfire.SqlServer.dll + + + ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + ..\packages\Microsoft.Report.Viewer.11.0.0.0\lib\net\Microsoft.ReportViewer.Common.dll @@ -59,6 +71,9 @@ ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + ..\packages\Owin.1.0\lib\net40\Owin.dll + ..\packages\PagedList.1.17.0.0\lib\net40\PagedList.dll @@ -109,8 +124,8 @@ ..\packages\VRH.Log4Pro.MultiLanguageManager.3.21.3\lib\net45\VRH.Log4Pro.MultiLanguageManager.dll - - ..\packages\Vrh.Logger.2.9.3\lib\net451\Vrh.Logger.dll + + ..\packages\Vrh.Logger.2.9.4\lib\net451\Vrh.Logger.dll ..\packages\Vrh.Membership.4.11.0\lib\net451\Vrh.Membership.dll diff --git a/Vrh.iScheduler/packages.config b/Vrh.iScheduler/packages.config index 8647ae2..e131713 100644 --- a/Vrh.iScheduler/packages.config +++ b/Vrh.iScheduler/packages.config @@ -1,20 +1,26 @@  + + + + + + - + diff --git a/iSchedulerMonitor/App.config b/iSchedulerMonitor/App.config index 774eb8b..18d7d4f 100644 --- a/iSchedulerMonitor/App.config +++ b/iSchedulerMonitor/App.config @@ -1,50 +1,50 @@ - + -
+
- + - + - - + + - - + + - - + + - - + + - - + + - - + + - + - - - - + + + + - + \ No newline at end of file diff --git a/iSchedulerMonitor/iSchedulerMonitor.ACPlugin.csproj b/iSchedulerMonitor/iSchedulerMonitor.ACPlugin.csproj index 0c0b8cd..afd852a 100644 --- a/iSchedulerMonitor/iSchedulerMonitor.ACPlugin.csproj +++ b/iSchedulerMonitor/iSchedulerMonitor.ACPlugin.csproj @@ -118,8 +118,8 @@ ..\packages\VRH.Log4Pro.MultiLanguageManager.3.21.3\lib\net45\VRH.Log4Pro.MultiLanguageManager.dll - - ..\packages\Vrh.Logger.2.9.3\lib\net451\Vrh.Logger.dll + + ..\packages\Vrh.Logger.2.9.4\lib\net451\Vrh.Logger.dll ..\packages\Vrh.Membership.4.11.0\lib\net451\Vrh.Membership.dll @@ -159,10 +159,10 @@ Always - + Always - + Always diff --git a/iSchedulerMonitor/packages.config b/iSchedulerMonitor/packages.config index 64dda2f..c68b8c7 100644 --- a/iSchedulerMonitor/packages.config +++ b/iSchedulerMonitor/packages.config @@ -16,7 +16,7 @@ - + -- libgit2 0.21.2