Пример #1
0
        public EventQueue(Dictionary <string, BaseProcessor> procs)
        {
            F2BSection   config   = F2B.Config.Instance;
            QueueElement queuecfg = config.Queue;

            limit      = queuecfg.MaxSize.Value;
            maxtime    = queuecfg.MaxTime.Value;
            nconsumers = queuecfg.Consumers.Value;
            dropped    = 0;
            max_errs   = 5;

            cancel      = new CancellationTokenSource();
            queueLow    = new BlockingCollection <Tuple <EventEntry, string> >();
            queueMedium = new BlockingCollection <Tuple <EventEntry, string> >();
            queueHigh   = new BlockingCollection <Tuple <EventEntry, string> >();
            queue       = new[] { queueHigh, queueMedium, queueLow };
            processors  = procs;

            ethreads = new EventQueueThread[nconsumers];
            abort    = null;
            if (maxtime > 0)
            {
                abort          = new System.Timers.Timer(maxtime * 1000 / 10);
                abort.Elapsed += Abort;
            }
        }
Пример #2
0
        private Dictionary <string, BaseProcessor> InitializeProcessors()
        {
            F2BSection          config     = F2B.Config.Instance;
            ProcessorCollection processors = config.Processors;

            Dictionary <string, BaseProcessor> ret = new Dictionary <string, BaseProcessor>();

            // create processors
            for (int i = 0; i < processors.Count; i++)
            {
                ProcessorElement processor = processors[(int)i];

                // test invalid configuration
                if (processor.Name == null || processor.Name == "")
                {
                    throw new Exception("Undefined processor #" + (processors.Count + 1) + " name");
                }
                if (ret.ContainsKey(processor.Name))
                {
                    throw new Exception("Duplicate processor name: " + processor.Name);
                }

                // add reference to next processor name
                if (i < processors.Count - 1)
                {
                    string nextName = processors[(int)(i + 1)].Name;
                    if (processor.Goto.Next == string.Empty)
                    {
                        processor.Goto.Next = nextName;
                    }
                    if (processor.Goto.Error == string.Empty)
                    {
                        if (processor.Goto.OnErrorNext)
                        {
                            processor.Goto.Error = nextName;
                        }
                        else
                        {
                            processor.Goto.Error = null;
                        }
                    }
                    if (processor.Goto.Success == string.Empty)
                    {
                        processor.Goto.Success = nextName;
                    }
                    if (processor.Goto.Failure == string.Empty)
                    {
                        processor.Goto.Failure = nextName;
                    }
                }

                // create processor
                string clazzName = "F2B.processors." + processor.Type + "Processor";
                Type   clazzType = Type.GetType(clazzName); // + "`1[F2B.ProcessorElement]");

                if (clazzType == null)
                {
                    Log.Error("processor[" + processor.Name + "@" + processor.Type
                              + "]: unable to resolve class \"" + clazzName + "\"");
                }
                else if (clazzType.IsSubclassOf(typeof(BoolProcessor)))
                {
                    Log.Info("processor[" + processor.Name + "@" + processor.Type
                             + "]: next->" + processor.Goto.Next
                             + ", error->" + processor.Goto.Error
                             + ", success->" + processor.Goto.Success
                             + ", failure->" + processor.Goto.Failure);
                }
                else
                {
                    Log.Info("processor[" + processor.Name + "@" + processor.Type
                             + "]: next->" + processor.Goto.Next
                             + ", error->" + processor.Goto.Error);
                }

                //ConstructorInfo ctor = clazzType.GetConstructor(new[] { typeof(ProcessorElement), typeof(Action<EventEntry, string, bool>) });
                //ret[processor.Name] = (BaseProcessor)ctor.Invoke(new object[] { processor, Delegate.CreateDelegate(GetType(), this, "Produce") });
                ConstructorInfo ctor = clazzType.GetConstructor(new[] { typeof(ProcessorElement), GetType() });
                ret[processor.Name] = (BaseProcessor)ctor.Invoke(new object[] { processor, this });
            }

            return(ret);
        }
Пример #3
0
        private Dictionary <string, BaseInput> InitializeInputs(EventQueue queue)
        {
            F2BSection          config     = F2B.Config.Instance;
            InputCollection     inputs     = config.Inputs;
            SelectorCollection  selectors  = config.Selectors;
            ProcessorCollection processors = config.Processors;

            string firstProcName = null;

            if (processors.Count > 0)
            {
                firstProcName = processors[0].Name;
            }

            Dictionary <string, BaseInput> ret = new Dictionary <string, BaseInput>();

            // create log data sources and selectors
            foreach (InputElement input in inputs)
            {
                Log.Info("input[" + input.Name + "]");
                if (string.IsNullOrEmpty(input.Name))
                {
                    Log.Warn("input[" + input.Name + "] undefined input name");
                    continue;
                }

                foreach (SelectorElement selector in selectors)
                {
                    if (!string.IsNullOrEmpty(selector.InputName) && selector.InputName != input.Name)
                    {
                        continue;
                    }
                    if (!string.IsNullOrEmpty(selector.InputType) && selector.InputType != input.Type)
                    {
                        continue;
                    }

                    // create input
                    string clazzName = "F2B.inputs." + input.Type + "Input";
                    Type   clazzType = Type.GetType(clazzName);

                    if (clazzType == null)
                    {
                        Log.Error("input[" + input.Name + "]/selector[" + selector.Name
                                  + "]: unable to resolve class \"" + clazzName + "\"");
                    }
                    else
                    {
                        Log.Info("input[" + input.Name + "]/selector[" + selector.Name
                                 + "]: creating new " + clazzName + " input");
                    }

                    ConstructorInfo ctor = clazzType.GetConstructor(
                        new[] { typeof(InputElement), typeof(SelectorElement), typeof(EventQueue) });
                    BaseInput logInput = (BaseInput)ctor.Invoke(new object[] { input, selector, queue });
                    ret[input.Name + "/" + selector.Name] = logInput;
                }
            }

            return(ret);
        }
Пример #4
0
        private void Consume(object data)
        {
            if (data == null)
            {
                Log.Error("Log event consumption: got null data?!");
                return;
            }

            EventQueueThread ethread = (EventQueueThread)data;

            Log.Info("Log event consumption (thread " + ethread.Number + "): start");

            EventEntry evtlog;
            string     procName;
            string     logpfx;
            long       tnevts  = 0;
            long       errcnt  = 0;
            long       errtime = DateTime.Now.Ticks;

            string     firstProcName = null;
            F2BSection config        = F2B.Config.Instance;

            if (config.Processors.Count > 0)
            {
                firstProcName = config.Processors[0].Name;
            }

            while (started)
            {
                evtlog   = null;
                procName = null;
                tnevts++;
                logpfx = string.Format("Consuming({0}/{1}): ", ethread.Number, tnevts);

                try
                {
                    Tuple <EventEntry, string> entry;
#if DEBUG
                    if (Log.Level == EventLogEntryType.Information)
                    {
                        Log.Info(logpfx + "queue High(" + queueHigh.Count + ")/Medium(" + queueMedium.Count + ")/Low(" + queueLow.Count + ")");
                    }
                    int queueIndex =
#endif
                    BlockingCollection <Tuple <EventEntry, string> > .TakeFromAny(queue, out entry, cancel.Token);

#if DEBUG
                    if (Log.Level == EventLogEntryType.Information)
                    {
                        Log.Info(logpfx + "queue High(" + queueHigh.Count + ")/Medium(" + queueMedium.Count + ")/Low(" + queueLow.Count + "): queueIndex = " + queueIndex);
                    }
#endif
                    evtlog   = entry.Item1;
                    procName = entry.Item2;
                }
                catch (OperationCanceledException)
                {
                    Log.Info(logpfx + "Log event consumption canceled (started=" + started + ")");
                    continue;
                }

#if DEBUG
                // evtlog can become null only if F2BLogAnalyzer runs in interactive
                // mode and user requested dump of its current state by pressing "d" key
                bool   debug     = evtlog == null;
                string debugFile = procName;

                if (!debug && (evtlog.LogData.GetType() == typeof(EventRecordWrittenEventArgs) || evtlog.LogData.GetType().IsSubclassOf(typeof(EventRecordWrittenEventArgs))))
                {
                    EventRecordWrittenEventArgs evtarg = evtlog.LogData as EventRecordWrittenEventArgs;
                    EventRecord evtrec = evtarg.EventRecord;

                    if (evtrec.ProviderName == "F2BDump")
                    {
                        // special windows EventLog event that can be used to request state dump
                        // (to be able to receive this event you must add selector for F2BDump events)
                        debug     = true;
                        debugFile = @"c:\F2B\dump.txt";

                        // process event XML data
                        string xmlString  = evtrec.ToXml();
                        var    doc        = XDocument.Parse(xmlString);
                        var    namespaces = new XmlNamespaceManager(new NameTable());
                        var    ns         = doc.Root.GetDefaultNamespace();
                        namespaces.AddNamespace("ns", ns.NamespaceName);

                        foreach (var element in doc.XPathSelectElements("/ns:Event/ns:EventData/ns:Data", namespaces))
                        {
                            debugFile = element.Value;
                        }
                    }
                }

                if (debug)
                {
                    Log.Warn(logpfx + "Dump processors debug info");
                    Utils.DumpProcessInfo(EventLogEntryType.Warning);
                    StreamWriter output = null;
                    lock (thisInst)
                    {
                        try
                        {
                            DateTime curr = DateTime.Now;
                            long     utc  = curr.ToUniversalTime().Ticks;

                            output = new StreamWriter(new FileStream(debugFile, FileMode.Append));
                            output.WriteLine("======================================================================");
                            output.WriteLine("======================================================================");
                            output.WriteLine("Timestamp: " + curr + " (UTC " + utc + ")");
                            foreach (BaseProcessor p in processors.Values)
                            {
                                output.WriteLine("========== " + p.GetType() + "[" + p.Name + "] processor ==========");
                                try
                                {
                                    p.Debug(output);
                                }
                                catch (Exception ex)
                                {
                                    Log.Error(logpfx + "Unable to dump " + p.GetType() + "[" + p.Name + "] debug info: " + ex.Message);
                                }
                            }

                            output.WriteLine("========== process environment ==========");
                            output.WriteLine("Environment.Is64BitProcess: {0}", Environment.Is64BitProcess);
                            output.WriteLine("Environment.Is64BitOperatingSystem: {0}", Environment.Is64BitOperatingSystem);
                            output.WriteLine("========== processors performance summary ==========");
                            IDictionary <string, ProcPerformance> summary = PerfSum();
                            foreach (string perfProcName in processors.Keys)
                            {
                                ProcPerformance p = summary[perfProcName];
                                output.WriteLine("Performance[{6}][{0}]: avg({1:0.00}/{2}={3:0.00}ms), min({4:0.00}ms), max({5:0.00}ms)", perfProcName, p.sum, p.count, p.sum / p.count, p.min, p.max, utc);
                            }

                            output.WriteLine("========== memory usage summary ==========");
                            Process currentProcess = Process.GetCurrentProcess();
                            string  linePrefix     = string.Format("Process[{0}][{1}]", utc, currentProcess.Id);
                            output.WriteLine("{0}: NonpagedSystemMemorySize64 = {1}", linePrefix, currentProcess.NonpagedSystemMemorySize64);
                            output.WriteLine("{0}: PagedMemorySize64 = {1}", linePrefix, currentProcess.PagedMemorySize64);
                            output.WriteLine("{0}: PagedSystemMemorySize64 = {1}", linePrefix, currentProcess.PagedSystemMemorySize64);
                            output.WriteLine("{0}: PeakPagedMemorySize64 = {1}", linePrefix, currentProcess.PeakPagedMemorySize64);
                            output.WriteLine("{0}: PeakVirtualMemorySize64 = {1}", linePrefix, currentProcess.PeakVirtualMemorySize64);
                            output.WriteLine("{0}: PeadWorkingSet64 = {1}", linePrefix, currentProcess.PeakWorkingSet64);
                            output.WriteLine("{0}: PrivateMemorySize64 = {1}", linePrefix, currentProcess.PrivateMemorySize64);
                            output.WriteLine("{0}: VirtualMemorySize64 = {1}", linePrefix, currentProcess.VirtualMemorySize64);
                            output.WriteLine("{0}: WorkingSet64 = {1}", linePrefix, currentProcess.WorkingSet64);
                            output.WriteLine("{0}: PrivilegedProcessorTime = {1}", linePrefix, currentProcess.PrivilegedProcessorTime);
                            output.WriteLine("{0}: StartTime = {1}", linePrefix, currentProcess.StartTime);
                            //output.WriteLine("{0}: ExitTime = {1}", linePrefix, currentProcess.ExitTime);
                            output.WriteLine("{0}: TotalProcessorTime = {1}", linePrefix, currentProcess.TotalProcessorTime);
                            output.WriteLine("{0}: UserProcessorTime = {1}", linePrefix, currentProcess.UserProcessorTime);
                        }
                        catch (Exception ex)
                        {
                            Log.Error(logpfx + "Unable to dump debug info (" + debugFile + "): " + ex.ToString());
                        }
                        finally
                        {
                            if (output != null)
                            {
                                output.Close();
                            }
                        }
                    }

                    continue;
                }
#endif

                if (evtlog == null)
                {
                    // special event used for debugging
                    continue;
                }

                logpfx = string.Format("Consuming({0}/{1}) event[{2}@{3}]: ",
                                       ethread.Number, tnevts, evtlog.Id, evtlog.Input.Name);

                BaseProcessor proc = null;
                if (string.IsNullOrEmpty(procName))
                {
                    procName = firstProcName;
                }

                //ethread.Reset();
                while (true)
                {
                    ethread.Process(procName);

                    if (procName == null)
                    {
                        Log.Info(logpfx + "NULL processor terminated event processing");
                        break;
                    }

                    if (!processors.ContainsKey(procName))
                    {
                        Log.Info(logpfx + "processor \"" + procName + "\" not found");
                        break;
                    }

                    Log.Info(logpfx + "processor \"" + procName + "\" executed");
                    proc = processors[procName];
                    evtlog.AddProcName(procName);

                    try
                    {
                        ethread.AbortAllowed = true;

                        if (nconsumers == 1 || typeof(IThreadSafeProcessor).IsAssignableFrom(proc.GetType()))
                        {
                            procName = proc.Execute(evtlog);
                        }
                        else
                        {
                            lock (proc)
                            {
                                procName = proc.Execute(evtlog);
                            }
                        }
                    }
                    catch (ThreadAbortException ex)
                    {
                        ethread.Reset();
                        Thread.ResetAbort();
                        Log.Warn(logpfx + "abort(" + proc.Name + ", "
                                 + errtime + ", " + errcnt + "): " + ex.Message);
                        break;
                    }
                    catch (Exception ex)
                    {
                        // use processor error configuration
                        procName = proc.goto_error;

                        errcnt++;
                        if (errcnt >= max_errs)
                        {
                            // reset exception counter (to log another group of exceptions)
                            long currtime = DateTime.Now.Ticks;
                            if (errtime + 60 * TimeSpan.TicksPerSecond < currtime)
                            {
                                errcnt  = 0;
                                errtime = currtime;
                            }
                        }

                        // log only limited number of execptions
                        if (errcnt < max_errs)
                        {
                            Log.Error(logpfx + "exception(" + proc.Name + ", "
                                      + errtime + ", " + errcnt + "): " + ex.ToString());
                        }
                    }
                    finally
                    {
                        ethread.AbortAllowed = false;
                    }

#if DEBUG
                    Log.Info(logpfx + "processor \"" + ethread.Name + "\" execution time: " + string.Format("{0:0.00}ms", ethread.ProcTime / 1000));
#endif
                }

#if DEBUG
                Log.Info(logpfx + "processor chain execution time: " + string.Format("{0:0.00}s", ethread.ChainTime / 1000));
#endif
                ethread.Reset();
            }

            Log.Info("Log event consumption (thread " + ethread.Number + "): finished");
        }