/// <summary> /// This method is designed to handle parsing of log entries in real time /// </summary> public void AnalyzeLine(ScanLineArgs args) { var lastIndex = -99; try { if (!_isRunning) { return; } #region UnitTesting if (StoreLog) { StoredLog += args.Line + Environment.NewLine; } #endregion UnitTesting lock (_activePatterns) { if (_activePatterns.Count == 0) { return; } for (var i = _activePatterns.Count - 1; i >= 0; i--) { lastIndex = i; var item = _activePatterns[i]; if (!item.Scan(args)) { continue; } switch (item.ScanType) { case ScanType.FirstOccurance: _activePatterns.Remove(item); break; case ScanType.Repeating: break; } } } } catch (Exception ex) { Log.WriteError($"_activeRecipies.Count={_activePatterns.Count}, i={lastIndex}", typeof(RealTimePatternScanService).FullName, MethodBase.GetCurrentMethod().Name, ex); } }
/// <summary> /// Returns true when the Pattern found a match /// </summary> public bool Scan(ScanLineArgs args) { if (!Active) { return(false); } // The Pattern was found, thus we no longer need to search for it if (Found) { return(false); } #region Start // To start a EventPattern, search for any START line // There can be one or more start lines, any of them will start the EventPattern if (!_hasStarted) { foreach (var step in Events.Where(n => (n.EventType == EventType.Start || n.EventType == EventType.Search) && n.Found == false)) { if (!StepScan(step as EventPattern, args)) { continue; } if (step.EventType == EventType.Search) { OnFound?.Invoke(this); Log.WriteError($"{Name}: Pattern Search was found.", typeof(PatternComplex).FullName, MethodBase.GetCurrentMethod().Name); if (ScanType == ScanType.Repeating) { Reset(); } return(true); } _hasStarted = true; return(false); // Full patter is not found yet } return(false); // Full EventPattern is not found yet } #endregion Start #region Body // Within the body of the EventPattern you will find 3 types of lines: Optional, Required, RequiredInOrder // Once a line is found, then don't search for it again // Optional and Required lines can occur in any order up to a RequiredInOrder line // Start from the top of the list of body messages until you run into a RequiredInOrder // Attempt to find the first RequiredInOrder line you run into, but not the second // Once a RequiredinOrder is found, then any lines prior to the RequriedInOrder that is not found should be flagged OutOfOrder foreach (var step in Events.Where(n => n.EventType == EventType.Body && n.Found == false)) { if (step.Options.RequiredInOrder) { if (StepScan(step as EventPattern, args)) { // Set all non-found lines prior to the RequiredInOrder as Out of Order foreach (var step2 in Events.Where(n => n.EventType == EventType.Body && n.Found == false)) { if (step2 == step) { break; } step2.OutOfOrder = true; } } return(false); // Full EventPattern is not found yet } if (StepScan(step as EventPattern, args)) { return(false); // Full EventPattern is not found yet } // If we found the start of a 'stop & stop' pair, then move onto the next line. - Sara if (step.BodyStartFound) { break; } } #endregion #region Stop // To Stop a EventPattern, all required lines must be found and then a stop line // If you run into a Stop line before all required lines are found then the EventPattern is reset and not found foreach (var step in Events.Where(n => n.EventType == EventType.Stop || n.EventType == EventType.Reset || n.EventType == EventType.Restart).Where(n => n.Found == false)) { if (!StepScan(step as EventPattern, args)) { continue; } if (step.EventType == EventType.Reset) { Log.WriteError($"{Name}: Pattern was Reset!", typeof(PatternComplex).FullName, MethodBase.GetCurrentMethod().Name); OnReset?.Invoke(this, args.iLine); Reset(); return(false); // Full EventPattern is not found, but reset found - Failure! } if (step.EventType == EventType.Restart) { var newEvents = new List <IEventPattern>(); // Remove all steps above the Restart var index = Events.IndexOf(step) + (step.Options.OneOrMore ? 1 : 0); for (int i = index; i < Events.Count; i++) { newEvents.Add(Events[i]); } Events = newEvents; return(false); } var success = true; // Check if all Required and RequiredInOrder were found foreach (var step3 in Events.Where(n => n.Found == false)) { if (!step3.Options.Required && !step3.Options.RequiredInOrder) { continue; } success = false; break; } if (!success) { Log.WriteError($"{Name}: Pattern started but was not complete!", typeof(PatternComplex).FullName, MethodBase.GetCurrentMethod().Name); Reset(); return(false); // Full EventPattern is not found, but stop found - Failure! } Log.Write($" {Name}: Pattern FOUND!!!", typeof(PatternComplex).FullName, MethodBase.GetCurrentMethod().Name, LogEntryType.Debug); OnFound?.Invoke(this); if (ScanType == ScanType.Repeating) { Reset(); } return(true); // Full eventPattern found! } #endregion Stop if (args.LastLine && _hasStarted) { var success = true; foreach (var step3 in Events.Where(n => n.Found == false)) { if (!step3.Options.Required && !step3.Options.RequiredInOrder) { continue; } success = false; break; } if (!success) { return(false); } OnFound?.Invoke(this); return(true); // Full EventPattern found! } // To Reset a EventPattern, a reset line must be found // If this occurs the EventPattern is reset return(false); }
/// <summary> /// Returns true when the Step found a match /// </summary> public bool StepScan(EventPattern step, ScanLineArgs args) { var s = string.Empty; var expression = step.RegularExpression; if (step.Options.BodyStop && step.BodyStartFound) { expression = step.RegularExpressionBodyStop; } step.Found = step.IsRegularExpression ? RegularExpression.HasMatch(args.Line, expression) : Common.GetStringFromLog(args.Line, step.RegularExpression, ref s); if (step.Found) { Log.Write($" {step.Parent.Name}: Step {step.EventType}, \"{step.RegularExpression.Insert(1, "__")}\"", typeof(EventPattern).FullName, MethodBase.GetCurrentMethod().Name, LogEntryType.Debug); // 'Prior' option requires that a exact EventPattern is found prior to this EventPattern if (step.Options.Prior && LastFound != null) { var _priorStep = step.Parent.Events[step.Parent.Events.IndexOf(step) - step.Options.PriorIndex]; if ((!_priorStep.Found && _priorStep.EventTag == step.Options.PriorPattern) || _priorStep.EventTag != step.Options.PriorPattern) { Log.Write($"EventPattern found, however the expected Prior EventPattern should be '{step.Options.PriorPattern}' at Index {step.Options.PriorIndex}", typeof(EventPattern).FullName, MethodBase.GetCurrentMethod().Name, LogEntryType.Debug); step.Found = false; return(false); } } // 'FirstRepeat' will only allow the first match to stay a match, any events that are found after are skipped if (step.Options.FirstRepeat && LastFound != null && LastFound.Options.FirstRepeat && LastFound.EventTag == step.EventTag) { step.Found = false; return(false); } if (step.Options.BodyStop) { if (step.BodyStartFound) { step.DateTimeBodyStop = RegularExpression.GetDateTime(EventService.GetDateTimeRegularExpression(args.SourceType), args.Line); step.iLineBodyStop = args.iLine; step.LineBodyStop = args.Line; } else { step.DateTime = RegularExpression.GetDateTime(EventService.GetDateTimeRegularExpression(args.SourceType), args.Line); step.iLine = args.iLine; step.Line = args.Line; } } else { step.DateTime = RegularExpression.GetDateTime(EventService.GetDateTimeRegularExpression(args.SourceType), args.Line); step.iLine = args.iLine; step.Line = args.Line; } step.Found = true; step.Match(step.Parent); // Last Repeat if (step.Options.LastRepeat && LastFound != null && LastFound.Options.LastRepeat && step.EventTag == LastFound.EventTag) { step.Parent.Events.Remove(LastFound); LastFound = null; } // 'BodyStop' option represents a start and stop eventPattern. if (step.Options.BodyStop) { if (!step.BodyStartFound) { step.BodyStartFound = true; step.Found = false; return(false); } step.BodyStopFound = true; } // When an EventPattern is found that can occur OneOrMore times // Clone the EventPattern // If Required or RequiredInOrder, remove these flags and make the next EventPattern Optional if (step.Options.OneOrMore) { var index = step.Parent.Events.FindIndex(p => p.Identifier == step.Identifier); var e = step.Clone(step.Parent); e.NewIdentifier(); if (step.Options.Required || step.Options.RequiredInOrder) { e.Options.Required = false; e.Options.RequiredInOrder = false; e.Options.Optional = true; } step.Parent.Events.Insert(index + 1, e); } LastFound = step; } return(step.Found); }