From bc2804d0b9f5f277eec345b5151af11e1f723c8a Mon Sep 17 00:00:00 2001 From: Milan Hanajik Date: Tue, 5 May 2020 15:42:15 +0200 Subject: [PATCH] iPerl head failure rate is monitored by Various.StatisticsMonitoring component, ver. 2.26.1458 --- TBF/BenchControl/Events.cs | 4 +- .../GenericDevices/IStatisticsMonitoring.cs | 21 ++ .../EventTriggers/Statistics/Factory.cs | 27 --- .../EventTriggers/Statistics/Trigger.cs | 106 --------- .../EventTriggers/Statistics/TriggerCfg.cs | 170 --------------- TBF/BenchControl/Sequences/MainSeq.cs | 26 ++- TBF/BenchControl/Sequences/ProcessData.cs | 1 + TBF/BenchControl/StateMachine.cs | 2 + TBF/BenchControl/TbfComponents.cs | 4 +- .../Various/StatisticsMonitoring/Factory.cs | 27 +++ .../StatisticsMonitoring/ProcessStatistics.cs | 204 ++++++++++++++++++ .../StatisticsMonitoring/StatisticsCfg.cs | 127 +++++++++++ TBF/Properties/AssemblyInfo.cs | 4 +- TBF/TBF.csproj | 7 +- 14 files changed, 414 insertions(+), 316 deletions(-) create mode 100644 TBF/BenchControl/GenericDevices/IStatisticsMonitoring.cs delete mode 100644 TBF/BenchControl/Output/EventTriggers/Statistics/Factory.cs delete mode 100644 TBF/BenchControl/Output/EventTriggers/Statistics/Trigger.cs delete mode 100644 TBF/BenchControl/Output/EventTriggers/Statistics/TriggerCfg.cs create mode 100644 TBF/BenchControl/Various/StatisticsMonitoring/Factory.cs create mode 100644 TBF/BenchControl/Various/StatisticsMonitoring/ProcessStatistics.cs create mode 100644 TBF/BenchControl/Various/StatisticsMonitoring/StatisticsCfg.cs diff --git a/TBF/BenchControl/Events.cs b/TBF/BenchControl/Events.cs index d7422cfbe..6b7afba8a 100644 --- a/TBF/BenchControl/Events.cs +++ b/TBF/BenchControl/Events.cs @@ -1,5 +1,5 @@ /// -/// Copyright (c) 2013-2018 Sensus Slovensko a.s. +/// Copyright (c) 2013-2020 Sensus Slovensko a.s. /// namespace TBF.BenchControl { @@ -155,6 +155,8 @@ namespace TBF.BenchControl ResultsProcessed, /// Event triggers ErrorProcessingResults, + StatisticsProcessed, /// Statistics monitoring (Event triggers) + /// Timer events TimerExpired, diff --git a/TBF/BenchControl/GenericDevices/IStatisticsMonitoring.cs b/TBF/BenchControl/GenericDevices/IStatisticsMonitoring.cs new file mode 100644 index 000000000..57c235620 --- /dev/null +++ b/TBF/BenchControl/GenericDevices/IStatisticsMonitoring.cs @@ -0,0 +1,21 @@ +/// +/// Copyright (c) 2020 Sensus Slovensko a.s. +/// +using System; +using System.Collections.Generic; +using TBF.BenchControl.Generic; +using Results.Entities; + +namespace TBF.BenchControl.GenericDevices +{ + public interface IStatisticsMonitoring : IComponent + { + /// + /// Process recent results and monitor obtained statistics + /// (failure rates of hardware components, etc.) + /// + /// Number of the last saved batch + /// Reference to the operation + IOperation ProcessStatisticsOp(int lastBatchNr); + } +} diff --git a/TBF/BenchControl/Output/EventTriggers/Statistics/Factory.cs b/TBF/BenchControl/Output/EventTriggers/Statistics/Factory.cs deleted file mode 100644 index 7f3123d15..000000000 --- a/TBF/BenchControl/Output/EventTriggers/Statistics/Factory.cs +++ /dev/null @@ -1,27 +0,0 @@ -/// -/// Copyright (c) 2020 Sensus Slovensko a.s. -/// -using System; -using System.Collections.Generic; -using TBF.BenchControl.Generic; - -namespace TBF.BenchControl.Output.EventTriggers.Statistics -{ - public class Factory : IComponentFactory - { - public string ClassName { get { return this.GetType().Namespace.Substring(17); } } - - public void ResetStaticProperties() { Trigger.ResetStaticProperties(); } - - public IComponent DummyComponent() { return new Trigger(); } - - public IComponent GetComponent(IComponentCfg cfg, IList components) { return new Trigger(cfg); } - - public IComponentCfg DefaultConfig() { return new TriggerCfg(this.GetType().Namespace.Substring(24), this); } - - public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component) - { - return ComponentCfgBase.CreateFromDbEntity(TriggerCfg.Serializer, component, this);; - } - } -} diff --git a/TBF/BenchControl/Output/EventTriggers/Statistics/Trigger.cs b/TBF/BenchControl/Output/EventTriggers/Statistics/Trigger.cs deleted file mode 100644 index 1bfbbb4f4..000000000 --- a/TBF/BenchControl/Output/EventTriggers/Statistics/Trigger.cs +++ /dev/null @@ -1,106 +0,0 @@ -/// -/// Copyright (c) 2020 Sensus Slovensko a.s. -/// -using System; -using log4net; - -namespace TBF.BenchControl.Output.EventTriggers.Statistics -{ - public class Trigger : ComponentBase, IOperation, GenericDevices.IEventTrigger - { - private static readonly ILog log = LogManager.GetLogger(typeof(Trigger)); - public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(1)); } - - readonly TriggerCfg triggerCfg; - - Results.Entities.Batch batch; - - - public Trigger() {} - - public Trigger(Generic.IComponentCfg cfg) - : base(cfg) - { - triggerCfg = cfg as TriggerCfg; - ApplyConfig(); - log.Debug(this.ToString()); - } - - - void ApplyConfig() - { - } - - #region Configuration Change Handling - - public static void OnCfgChange(object sender, CfgChangeArgs args) - { - if (CfgChangeHandler == null) return; - try { CfgChangeHandler(sender, args); } - catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); } - } - - public static event EventHandler CfgChangeHandler; - - public override void StartChangeHandler() - { - CfgChangeHandler += delegate(object sender, CfgChangeArgs args) - { - TriggerCfg newCfg = args.Cfg as TriggerCfg; - if (newCfg != null && newCfg.Name.Equals(Name)) - { - if (args.Command == CfgChangeCmd.CfgChange) - { - triggerCfg.EventSource = newCfg.EventSource; - triggerCfg.Culture = newCfg.Culture; - triggerCfg.EliminateSpaces = newCfg.EliminateSpaces; - triggerCfg.PrintCaption = newCfg.PrintCaption; - - ApplyConfig(); - } - } - }; - } - - #endregion Configuration Change Handling - - - /// - /// Writes the test cycle results into a file - /// Events: - /// Event.ResultsWritten - /// Event.Busy - /// - /// Results to write into a file - /// Reference to the operation - public IOperation ProcessResultsOp(Results.Entities.Batch batch) - { - this.batch = batch; - return this; - } - - /// Start this operation - public void Start() - { - Process(batch); - } - - /// Run this operation - /// Event.ResultsProcessed - public Event Run() - { - return Event.ResultsProcessed; - } - - /// Stop this operation - public void Stop() - { - } - - - void Process(Results.Entities.Batch batch) - { - return; - } - } -} diff --git a/TBF/BenchControl/Output/EventTriggers/Statistics/TriggerCfg.cs b/TBF/BenchControl/Output/EventTriggers/Statistics/TriggerCfg.cs deleted file mode 100644 index 0dd938d85..000000000 --- a/TBF/BenchControl/Output/EventTriggers/Statistics/TriggerCfg.cs +++ /dev/null @@ -1,170 +0,0 @@ -/// -/// Copyright (c) 2020 Sensus Slovensko a.s. -/// -using System; -using System.Xml.Serialization; -using Config.Entities; -using TBF.BenchControl.Generic; -using TBF.Resources; -using System.Collections.Generic; - -namespace TBF.BenchControl.Output.EventTriggers.Statistics -{ - /// - /// Serializable configuration of Output.EventTriggers.Standard component. - /// - public class TriggerCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider - { - public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TriggerCfg) })[0]; - public override XmlSerializer GetSerializer() { return Serializer; } - - public IComponentCfgCtrl GetControl() { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); } - - /// - /// Serialized parameters - /// - public string EventSource; - public Culture Culture; - public bool EliminateSpaces; - public bool PrintCaption; - - /// Private parameterless constructor invoked by all other (public) constructors - TriggerCfg() {} - - public TriggerCfg(string name, IComponentFactory factory) - : this() - { - Name = name; - Factory = factory; - ParentName = string.Empty; - InitializeAll(); - } - - public string ComponentName { get { return Name; } } - - public void InitializeAll() - { - EventSource = "Štatistiky výsledkov"; - Culture = Culture.EN; - EliminateSpaces = false; - PrintCaption = false; - } - - string[] paramNames = new string[] - { - "Event source", - "Culture", - "Eliminate spaces", - "Print caption", - }; - public string ParamName(int i) { return paramNames[i]; } - public int ParamsCount() { return paramNames.Length; } - - public IList ParamValues(int i) - { - IList listOfValues = new List(); - if (i == 1) - { - for (Culture cu = 0; cu < Culture.Count; cu++) listOfValues.Add(cu.ToString()); - return listOfValues; - } - else if (i == 2) - { - listOfValues.Add(Strings.yes); - listOfValues.Add(Strings.no); - return listOfValues; - } - else - { - return null; - } - } - - public string ToString(int i) - { - switch (i) - { - case -1: return string.Format("Name={0}, FNameFmt={1}, NoSpaces={2}", Name, EventSource, EliminateSpaces); - case 0: return EventSource; - case 1: return Culture.ToString(); - case 2: return EliminateSpaces ? Strings.yes : Strings.no; - case 3: return PrintCaption ? Strings.yes : Strings.no; - default: return string.Empty; - } - } - - public CfgUpdateFlags UpdateParam(int i, string strValue) - { - switch (i) - { - case 0: EventSource = strValue; return CfgUpdateFlags.RestartRqrd; - case 1: - for (Culture cu = 0; cu < Culture.Count; cu++) - { - if (strValue == cu.ToString()) - { - if (Culture != cu) - { - Culture = cu; - return CfgUpdateFlags.RestartRqrd; - } - else - { - return CfgUpdateFlags.None; - } - } - } - return CfgUpdateFlags.Error; - case 2: EliminateSpaces = (strValue == Strings.yes); return CfgUpdateFlags.RestartRqrd; - case 3: PrintCaption = (strValue == Strings.yes); return CfgUpdateFlags.RestartRqrd; - default: return CfgUpdateFlags.None; - } - } - - public bool ValidateParam(int i, string strValue, out string message) - { - message = string.Empty; - - switch (i) - { - case 0: return true; - case 1: - for (Culture cu = 0; cu < Culture.Count; cu++) - { - if (strValue == cu.ToString()) return true; - } - break; - case 2: - case 3: - if (strValue == Strings.yes || strValue == Strings.no) return true; - break; - default: - message = "Invalid index"; - return false; - } - - message = ParamName(i) + " is invalid"; - return false; - } - - void CopyContentTo(TriggerCfg prms) - { - prms.EventSource = this.EventSource; - prms.Culture = this.Culture; - prms.EliminateSpaces = this.EliminateSpaces; - prms.PrintCaption = this.PrintCaption; - } - - public Config.Entities.IParamsProvider Clone() - { - TriggerCfg pars = new TriggerCfg(); - CopyContentTo(pars); - return pars; - } - - public bool UpdateEmbeddedDbEntity() - { - return true; /// =OK, do nothing - } - } -} diff --git a/TBF/BenchControl/Sequences/MainSeq.cs b/TBF/BenchControl/Sequences/MainSeq.cs index 339837d68..cbdf8e9be 100644 --- a/TBF/BenchControl/Sequences/MainSeq.cs +++ b/TBF/BenchControl/Sequences/MainSeq.cs @@ -1233,6 +1233,7 @@ namespace TBF.BenchControl.Sequences string[] writers = (StateMachine.Procedure.ResultsWriter != null) ? StateMachine.Procedure.ResultsWriter.Split(new char[] { '~' }) : new string[0]; string[] printers = (StateMachine.Procedure.ResultsPrinter != null) ? StateMachine.Procedure.ResultsPrinter.Split(new char[] { '~' }) : new string[0]; string[] eventTriggers = (StateMachine.Procedure.EventTriggers != null) ? StateMachine.Procedure.EventTriggers.Split(new char[] { '~' }) : new string[0]; + /// string[] rsltProcessors = new string[writers.Length + printers.Length + eventTriggers.Length]; writers.CopyTo(rsltProcessors, 0); printers.CopyTo(rsltProcessors, writers.Length); @@ -1294,14 +1295,29 @@ namespace TBF.BenchControl.Sequences ProcessData.BatchRslts.Batch.ProcedureName, Program.LocalSettings.BatchNr); - evacuation: - - /// Evacuation is similar to 'Abort session' (no results are saved), but the evacuation is done as well. - StateMachine.ControlBoard.ManualUIAllowed = true; Event evacRetv = DoEvacuation(purgeEnd); - Bridge.OnProcedureCompleted(this, new ProcedureCompletedEventArgs(StateMachine.Procedure)); + /// + /// Process statistics (in each regular cycle after evacuation when ProcessData.StatisticsMonitoringComp is defined) + /// + if (ProcessData.StatisticsMonitoringComp is IStatisticsMonitoring) + { + State.Create("MainSeq : Processing statistics") + .AddOperation((ProcessData.StatisticsMonitoringComp as IStatisticsMonitoring).ProcessStatisticsOp(ProcessData.BatchRslts.Batch.BatchNr)) + .AddOperation(checkUiOp) + .EnterState(); + do { + e = StateMachine.WaitRunDevsRunOps(); + if (e.Contains(Event.UiCmdStop)) goto stop; + } + while (e.Contains(Event.Busy)); + } + + /// + /// Procedure completed, branch depending on the result of evacuation + /// + Bridge.OnProcedureCompleted(this, new ProcedureCompletedEventArgs(StateMachine.Procedure)); switch (evacRetv) { case Event.Error: goto error; diff --git a/TBF/BenchControl/Sequences/ProcessData.cs b/TBF/BenchControl/Sequences/ProcessData.cs index 8cb396496..467ca3763 100644 --- a/TBF/BenchControl/Sequences/ProcessData.cs +++ b/TBF/BenchControl/Sequences/ProcessData.cs @@ -17,6 +17,7 @@ namespace TBF.BenchControl.Sequences /// public static IBenchInfo BenchInfo; public static IErrorFlags ErrorFlagsComp; + public static IStatisticsMonitoring StatisticsMonitoringComp; public static Output.DB.SensusOracle.Database OracleDB; /// diff --git a/TBF/BenchControl/StateMachine.cs b/TBF/BenchControl/StateMachine.cs index 4f3db327c..8c8b9a750 100644 --- a/TBF/BenchControl/StateMachine.cs +++ b/TBF/BenchControl/StateMachine.cs @@ -232,6 +232,8 @@ namespace TBF.BenchControl if (cmpnt is Elde.ControlBoardDev) ControlBoard = cmpnt as Elde.ControlBoardDev; if (cmpnt is IBenchInfo) ProcessData.BenchInfo = cmpnt as IBenchInfo; if (cmpnt is IErrorFlags) ProcessData.ErrorFlagsComp = cmpnt as IErrorFlags; + if (cmpnt is IStatisticsMonitoring) ProcessData.StatisticsMonitoringComp = cmpnt as IStatisticsMonitoring; + if ((cmpnt is Output.DB.SensusOracle.Database) && (ProcessData.OracleDB == null)) { ProcessData.OracleDB = cmpnt as Output.DB.SensusOracle.Database; diff --git a/TBF/BenchControl/TbfComponents.cs b/TBF/BenchControl/TbfComponents.cs index 25fb145aa..20b77989c 100644 --- a/TBF/BenchControl/TbfComponents.cs +++ b/TBF/BenchControl/TbfComponents.cs @@ -133,7 +133,6 @@ namespace TBF.BenchControl Factories.Add(new Output.DB.SensusOracle.Factory()); Factories.Add(new Output.EventTriggers.Iperl.Factory()); Factories.Add(new Output.EventTriggers.Standard.Factory()); - Factories.Add(new Output.EventTriggers.Statistics.Factory()); Factories.Add(new Output.FileWriters.Basic.FactorySingle()); Factories.Add(new Output.FileWriters.Basic.FactoryCompound()); Factories.Add(new Output.FileWriters.Basic.FactoryHeatMeters()); @@ -185,7 +184,8 @@ namespace TBF.BenchControl Factories.Add(new Elde.ValveEx.ValveFactory()); Factories.Add(new Various.ErrorFlags.Factory()); Factories.Add(new Various.Evaporation.Factory()); - Factories.Add(new Various.TankWithLevelMsrmnt.Factory()); + Factories.Add(new Various.StatisticsMonitoring.Factory()); + Factories.Add(new Various.TankWithLevelMsrmnt.Factory()); Factories.Add(new WaterMeters.Munich.WaterMeterFactory()); /// 'WaterMeters.Munich' Factories.Add(new WaterMeters.WaterMeter.WaterMeterFactory()); /// 'WaterMeter' } diff --git a/TBF/BenchControl/Various/StatisticsMonitoring/Factory.cs b/TBF/BenchControl/Various/StatisticsMonitoring/Factory.cs new file mode 100644 index 000000000..95ac16ae0 --- /dev/null +++ b/TBF/BenchControl/Various/StatisticsMonitoring/Factory.cs @@ -0,0 +1,27 @@ +/// +/// Copyright (c) 2020 Sensus Slovensko a.s. +/// +using System; +using System.Collections.Generic; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Various.StatisticsMonitoring +{ + public class Factory : IComponentFactory + { + public string ClassName { get { return this.GetType().Namespace.Substring(17); } } + + public void ResetStaticProperties() { ProcessStatistics.ResetStaticProperties(); } + + public IComponent DummyComponent() { return new ProcessStatistics(); } + + public IComponent GetComponent(IComponentCfg cfg, IList components) { return new ProcessStatistics(cfg); } + + public IComponentCfg DefaultConfig() { return new StatisticsCfg(this.GetType().Namespace.Substring(25), this); } + + public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component) + { + return ComponentCfgBase.CreateFromDbEntity(StatisticsCfg.Serializer, component, this);; + } + } +} diff --git a/TBF/BenchControl/Various/StatisticsMonitoring/ProcessStatistics.cs b/TBF/BenchControl/Various/StatisticsMonitoring/ProcessStatistics.cs new file mode 100644 index 000000000..bd0889f31 --- /dev/null +++ b/TBF/BenchControl/Various/StatisticsMonitoring/ProcessStatistics.cs @@ -0,0 +1,204 @@ +/// +/// Copyright (c) 2020 Sensus Slovensko a.s. +/// +using System; +using System.Collections.Generic; +using log4net; +using NHibernate; +using Events.Entities; +using Results.Entities; + +namespace TBF.BenchControl.Various.StatisticsMonitoring +{ + public class ProcessStatistics : ComponentBase, IOperation, GenericDevices.IStatisticsMonitoring + { + private static readonly ILog log = LogManager.GetLogger(typeof(ProcessStatistics)); + public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(1)); } + + readonly StatisticsCfg statisticsCfg; + + int lastBatchNr; + + + public ProcessStatistics() {} + + public ProcessStatistics(Generic.IComponentCfg cfg) + : base(cfg) + { + statisticsCfg = cfg as StatisticsCfg; + ApplyConfig(); + log.Debug(this.ToString()); + } + + + void ApplyConfig() + { + } + + #region Configuration Change Handling + + public static void OnCfgChange(object sender, CfgChangeArgs args) + { + if (CfgChangeHandler == null) return; + try { CfgChangeHandler(sender, args); } + catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); } + } + + public static event EventHandler CfgChangeHandler; + + public override void StartChangeHandler() + { + CfgChangeHandler += delegate(object sender, CfgChangeArgs args) + { + StatisticsCfg newCfg = args.Cfg as StatisticsCfg; + if (newCfg != null && newCfg.Name.Equals(Name)) + { + if (args.Command == CfgChangeCmd.CfgChange) + { + statisticsCfg.EventSource = newCfg.EventSource; + statisticsCfg.iPerlHeadFailureRateThreshold = newCfg.iPerlHeadFailureRateThreshold; + + ApplyConfig(); + } + } + }; + } + + #endregion Configuration Change Handling + + + /// + /// Writes the test cycle results into a file + /// Events: + /// Event.StatisticsProcessed + /// Event.Busy + /// + /// Results to write into a file + /// Reference to the operation + public IOperation ProcessStatisticsOp(int lastBatchNr) + { + this.lastBatchNr = lastBatchNr; + return this; + } + + + public void Start() + { + Process(lastBatchNr, statisticsCfg); + } + public Event Run() + { + return Event.StatisticsProcessed; + } + public void Stop() + { + } + + /// + /// Process recent batch results and calculate statistics of iPERL head failures + /// + /// Number of the last saved batch + void Process(int batchNr, StatisticsCfg statisticsCfg) + { + const int RequiredUsages = 10; + const int MaxBatches = 20; + + float iperlHeadFailureRateThreshold = (float)statisticsCfg.iPerlHeadFailureRateThreshold / 100.0f; + + int completeBatchesProcessed = 0; + + int[] usages = new int[Config.Data.WMsCount]; + int[] failures = new int[Config.Data.WMsCount]; + for (int i = 0; i < Config.Data.WMsCount; i++) usages[i] = failures[i] = 0; + + /// + /// Read results of recent batches (up to 'MaxBatches') + /// Take into account only batches where the 1st test in named 'RFID' and + /// at least one water meter completed all tests. + /// + try + { + ISession session = Results.DB.CreateSession(); + + int usagesMin; + do + { + usagesMin = 0; + IList batches = session.QueryOver() + .Where(x => x.Id == batchNr) + .List(); + batchNr--; + if (batches.Count != 1 || batches[0].TestRslts.Count < 1 || batches[0].TestRslts[0].MethodClass != "TestMethods.iPerlCommunication") + { + continue; + } + + bool isACompleteBatch = false; + foreach (var wm in batches[0].WaterMeters) + { + int i = wm.WMPosition - 1; + if (0 <= i && i < Config.Data.WMsCount && usages[i] < RequiredUsages && !wm.Disabled && wm.CompletedFromTests()) + { + isACompleteBatch = true; + usages[i]++; + if (!wm.MeterTestRslts[0].Passed) failures[i]++; + } + } + + usagesMin = int.MaxValue; + for (int i = 0; i < Config.Data.WMsCount; i++) if (usagesMin > usages[i]) usagesMin = usages[i]; + + if (isACompleteBatch) completeBatchesProcessed++; + } + while ((usagesMin < RequiredUsages) && (batchNr > 0) && (completeBatchesProcessed < MaxBatches)); + } + catch (Exception exc) + { + log.ErrorFormat("Failed to calculate iPERL head usage statistics: {0}", exc.Message); + } + + /// + /// Find out whether at lest one event needs to be triggered + /// + bool doTriggerEvents = false; + for (int i = 0; i < Config.Data.WMsCount; i++) + { + if ((usages[i] > 0) && (iperlHeadFailureRateThreshold > 0) && (float)failures[i] / (float)usages[i] >= iperlHeadFailureRateThreshold) + { + doTriggerEvents = true; + break; + } + } + + if (doTriggerEvents) + { + /// + /// Trigger events + /// + try + { + ISession session = Events.DB.CreateSession(); + Events.DB.LoadSubscribers(session); + + for (int i = 0; i < Config.Data.WMsCount; i++) + { + if ((usages[i] > 0) && (iperlHeadFailureRateThreshold > 0) && (float)failures[i] / (float)usages[i] >= iperlHeadFailureRateThreshold) + { + TBF.UiBridge.Bridge.TriggerEvent(session, + statisticsCfg.EventSource, + EventClass.EquipmentHW, + Severity.Error, + string.Format("Príliš veľa chýb hlavice č. {0}", i + 1), + string.Format("Percento chýb je {0}%", (100 * failures[i]) / usages[i]), + SubscriberGroup.Metrology | SubscriberGroup.Maintenance | SubscriberGroup.Production); + } + } + } + catch (Exception exc) + { + log.ErrorFormat("Failed to trigger events: source = {0}, message = {1}", statisticsCfg.EventSource, exc.Message); + } + } + } + } +} diff --git a/TBF/BenchControl/Various/StatisticsMonitoring/StatisticsCfg.cs b/TBF/BenchControl/Various/StatisticsMonitoring/StatisticsCfg.cs new file mode 100644 index 000000000..29861a066 --- /dev/null +++ b/TBF/BenchControl/Various/StatisticsMonitoring/StatisticsCfg.cs @@ -0,0 +1,127 @@ +/// +/// Copyright (c) 2020 Sensus Slovensko a.s. +/// +using System; +using System.Xml.Serialization; +using Config.Entities; +using TBF.BenchControl.Generic; +using TBF.Resources; +using System.Collections.Generic; + +namespace TBF.BenchControl.Various.StatisticsMonitoring +{ + /// + /// Serializable configuration of Various.StatisticsMonitoring component. + /// + public class StatisticsCfg : ComponentCfgBase, Generic.IComponentCfg, Config.Entities.IParamsProvider + { + public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(StatisticsCfg) })[0]; + public override XmlSerializer GetSerializer() { return Serializer; } + + public IComponentCfgCtrl GetControl() { return new Configs.ParamsProvider.ComponentCfgCtrl(this, null); } + + /// + /// Serialized parameters + /// + public string EventSource; + public int iPerlHeadFailureRateThreshold; /// 0 = off, 1..100% event is triggered when percentage reaches this level + + /// Private parameterless constructor invoked by all other (public) constructors + StatisticsCfg() { } + + public StatisticsCfg(string name, IComponentFactory factory) + : this() + { + Name = name; + Factory = factory; + ParentName = string.Empty; + InitializeAll(); + } + + public string ComponentName { get { return Name; } } + + public void InitializeAll() + { + EventSource = "Štatistiky"; /// 0 + iPerlHeadFailureRateThreshold = 20; /// 1 + } + + string[] paramNames = new string[] + { + "Event source", /// 0 + "Threshold for iPERL head failure rate [%] (0=off)", /// 1 + }; + public string ParamName(int i) { return paramNames[i]; } + public int ParamsCount() { return paramNames.Length; } + + public IList ParamValues(int i) + { + return null; + } + + public string ToString(int i) + { + switch (i) + { + case -1: return string.Format("Name={0}, EventSource={1}, FailureRatePct={2}, ...", Name, EventSource, iPerlHeadFailureRateThreshold); + case 0: return EventSource; + case 1: return iPerlHeadFailureRateThreshold.ToString(); + default: return string.Empty; + } + } + + public CfgUpdateFlags UpdateParam(int i, string strValue) + { + switch (i) + { + case 0: EventSource = strValue; return CfgUpdateFlags.AnyChange; + case 1: iPerlHeadFailureRateThreshold = int.Parse(strValue); return CfgUpdateFlags.AnyChange; + default: return CfgUpdateFlags.None; + } + } + + /// + /// Validate string form of a parameter value + /// + /// Parameter index + /// String form of a parameter + /// Message in case value is not valid + /// true when string form of a parameter is OK + public bool ValidateParam(int i, string strValue, out string message) + { + message = string.Empty; + int percentage; + + switch (i) + { + case 0: + return true; + case 1: + if (int.TryParse(strValue, out percentage) && (0 <= percentage) && (percentage <= 100)) return true; + message = "Threshold for iPERL head failure rate in % (0 = off)"; + return false; + default: + message = "Invalid index"; + return false; + } + } + + void CopyContentTo(StatisticsCfg prms) + { + prms.EventSource = this.EventSource; /// 0 + prms.iPerlHeadFailureRateThreshold = this.iPerlHeadFailureRateThreshold; /// 1 + } + + public Config.Entities.IParamsProvider Clone() + { + StatisticsCfg pars = new StatisticsCfg(); + CopyContentTo(pars); + return pars; + } + + public bool UpdateEmbeddedDbEntity() + { + return true; /// =OK, do nothing + } + } +} diff --git a/TBF/Properties/AssemblyInfo.cs b/TBF/Properties/AssemblyInfo.cs index 2919e00de..736478cf5 100644 --- a/TBF/Properties/AssemblyInfo.cs +++ b/TBF/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("2.26.1457.0")] -[assembly: AssemblyFileVersion("2.26.1457.0")] +[assembly: AssemblyVersion("2.26.1458.0")] +[assembly: AssemblyFileVersion("2.26.1458.0")] diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index 297a8bdb9..e39503ed1 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -626,6 +626,7 @@ + @@ -909,9 +910,6 @@ - - - @@ -1585,6 +1583,9 @@ WaterLevelForm.cs + + +