public StartStopActivityComputer()

in src/TraceEvent/Computers/StartStopActivityComputer.cs [35:501]


        public StartStopActivityComputer(TraceLogEventSource source, ActivityComputer taskComputer, bool ignoreApplicationInsightsRequestsWithRelatedActivityId = true)
        {
            m_ignoreApplicationInsightsRequestsWithRelatedActivityId = ignoreApplicationInsightsRequestsWithRelatedActivityId;
            taskComputer.NoCache = true;            // Can't cache start-stops (at the moment)
            m_source = source;
            m_activeStartStopActivities = new Dictionary<StartStopKey, StartStopActivity>();
            m_taskComputer = taskComputer;

            // Whenever a new Activity is created, propagate the start-stop activity from the creator
            // to the created task.  
            taskComputer.Create += delegate (TraceActivity activity, TraceEvent data)
            {
                TraceActivity creator = activity.Creator;
                if (creator == null)
                {
                    return;
                }

                StartStopActivity startStopActivity = m_traceActivityToStartStopActivity.Get((int)creator.Index);
                if (startStopActivity == null)
                {
                    return;
                }

                m_traceActivityToStartStopActivity.Set((int)activity.Index, startStopActivity);
            };

            // Only need to fix up V4.6 Windows-ASP activity ids.   It can be removed after we
            // don't care about V4.6 runtimes (since it is fixed in V4.6.2 and beyond). 
            // It basically remembers the related activity ID of the last RequestSend event on
            // each thread, which we use to fix the activity ID of the RequestStart event 
            KeyValuePair<Guid, Guid>[] threadToLastAspNetGuids = new KeyValuePair<Guid, Guid>[m_source.TraceLog.Threads.Count];
#if HTTP_SERVICE_EVENTS
            // Sadly, the Microsoft-Windows-HttpService HTTP_OPCODE_DELIVER event gets logged in
            // the kernel, so you don't know what process or thread is going to be get the request
            // We hack around this by looking for a nearby ReadyTHread or CSwitch event.  These
            // variables remember the information needed to transfer these to cswitch in the 
            // correct process.  
            // remembers the last deliver event. 
            string lastHttpServiceDeliverUrl = null;
            Guid lastHttpServiceDeliverActivityID = new Guid();
            int lastHttpServiceReceiveRequestThreadId = 0;
            int lastHttpServiceReceiveRequestTargetProcessId = 0;

            Dictionary<long, int> mapConnectionToTargetProcess = new Dictionary<long, int>();
#endif 
            var dynamicParser = source.Dynamic;
            dynamicParser.All += delegate (TraceEvent data)
            {
                // Special case IIS.  It does not use start and stop opcodes (Ugg), but otherwise 
                // follows normal start-stop activity ID conventions.   We also want it to work even
                // though it is not a EventSource.  
                if (data.ID <= (TraceEventID)2 && data.ProviderGuid == MicrosoftWindowsIISProvider)
                {
                    if (data.ID == (TraceEventID)1)
                    {
                        // TODO HACK.  We have seen IIS Start and stop events that only have a 
                        // context ID and no more.  They also seem to be some sort of nested event
                        // It really looks like a bug that they were emitted.  Ignore them. 
                        if (16 < data.EventDataLength)
                        {
                            string extraStartInfo = data.PayloadByName("RequestURL") as string;
                            OnStart(data, extraStartInfo, null, null, null, "IISRequest");
                        }
                    }
                    else if (data.ID == (TraceEventID)2)
                    {
                        // TODO HACK.  We have seen IIS Start and stop events that only have a 
                        // context ID and no more.  They also seem to be some sort of nested event
                        // It really looks like a bug that they were emitted.  Ignore them.
                        if (16 < data.EventDataLength)
                        {
                            OnStop(data);
                        }
                    }
                }
#if HTTP_SERVICE_EVENTS
                else if (data.Task == (TraceEventTask)1 && data.ProviderGuid == MicrosoftWindowsHttpService)
                {
                    if (data.ID == (TraceEventID)1)  // HTTP_TASK_REQUEST / HTTP_OPCODE_RECEIVE_REQUEST
                    {
                        Debug.Assert(data.EventName == "HTTP_TASK_REQUEST/HTTP_OPCODE_RECEIVE_REQUEST");
                        lastHttpServiceReceiveRequestTargetProcessId = 0;
                        lastHttpServiceReceiveRequestThreadId = data.ThreadID;
                        object connectionID = data.PayloadByName("ConnectionId");
                        if (connectionID != null && connectionID is long)
                            mapConnectionToTargetProcess.TryGetValue((long)connectionID, out lastHttpServiceReceiveRequestTargetProcessId);
                    }
                    else if (data.ID == (TraceEventID)3) // HTTP_TASK_REQUEST/HTTP_OPCODE_DELIVER 
                    {
                        Debug.Assert(data.EventName == "HTTP_TASK_REQUEST/HTTP_OPCODE_DELIVER");
                        if (lastHttpServiceReceiveRequestThreadId == data.ThreadID && lastHttpServiceReceiveRequestTargetProcessId != 0)
                        {   
                            lastHttpServiceDeliverUrl = data.PayloadByName("Url") as string;
                            lastHttpServiceDeliverActivityID = data.ActivityID;
                        }
                        else
                        {
                            lastHttpServiceDeliverUrl = null;
                            lastHttpServiceReceiveRequestTargetProcessId = 0;
                        }
                        lastHttpServiceReceiveRequestThreadId = 0;
                    }
                    else if (data.ID == (TraceEventID)12 || data.ID == (TraceEventID)8) // HTTP_TASK_REQUEST/HTTP_OPCODE_FAST_SEND  HTTP_TASK_REQUEST/HTTP_OPCODE_FAST_RESPONSE
                    {
                        if (data.ID == (TraceEventID)8)
                        {
                            object connectionID = data.PayloadByName("ConnectionId");
                            if (connectionID != null && connectionID is long)
                                mapConnectionToTargetProcess[(long)connectionID] = data.ProcessID;
                        }
                        Debug.Assert(data.ID != (TraceEventID)12 || data.EventName == "HTTP_TASK_REQUEST/HTTP_OPCODE_FAST_SEND");
                        Debug.Assert(data.ID != (TraceEventID)8 || data.EventName == "HTTP_TASK_REQUEST/HTTP_OPCODE_FAST_RESPONSE");
                        OnStop(data);
                    }
                }
#endif
                // TODO decide what the correct heuristic for deciding what start-stop events are interesting.  
                // Currently I only do this for things that might be an EventSource 
                if (!TraceEventProviders.MaybeAnEventSource(data.ProviderGuid))
                {
                    return;
                }

                // Try to filter out things quickly.   We really only care about start and stop events 
                // (except in special cases where the conventions were not followed and we fix them up). 
                if (data.Opcode != TraceEventOpcode.Start && data.Opcode != TraceEventOpcode.Stop)
                {
                    // In V4.6 the activity ID for Microsoft-Windows-ASPNET/Request/Start is improperly set, but we can fix it by 
                    // looking at the 'send' event that happens just before it.   Can be removed when V4.6 no longer deployed.  
                    // TODO remove (including threadToLastAspNetGuid) after 9/2016
                    if (data.Opcode == (TraceEventOpcode)9 && data.ProviderGuid == MicrosoftWindowsASPNetProvider)
                    {
                        TraceThread thread = data.Thread();
                        if (thread != null)
                        {
                            threadToLastAspNetGuids[(int)thread.ThreadIndex] = new KeyValuePair<Guid, Guid>(data.ActivityID, data.RelatedActivityID);
                        }
                    }
                    // These providers are weird in that they don't event do start and stop opcodes.  This is unfortunate.  
                    else if (data.Opcode == TraceEventOpcode.Info && data.ProviderGuid == AdoNetProvider)
                    {
                        FixAndProcessAdoNetEvents(data);
                    }

                    return;
                }

                // OK so now we only have EventSources with start and stop opcodes.
                // There are a few that don't follow conventions completely, and then we handle the 'normal' case 
                if (data.ProviderGuid == MicrosoftApplicationInsightsDataProvider)
                {
                    FixAndProcessAppInsightsEvents(data);
                }
                else if (data.ProviderGuid == FrameworkEventSourceTraceEventParser.ProviderGuid)
                {
                    FixAndProcessFrameworkEvents(data);
                }
                else if (data.ProviderGuid == MicrosoftWindowsASPNetProvider)
                {
                    FixAndProcessWindowsASP(data, threadToLastAspNetGuids);
                }
                else if (data.ProviderGuid == MicrosoftDiagnosticsActivityTrackingProvider)
                {
                    ProcessActivityTrackingProviderEvents(data);
                }
                else // Normal case EventSource Start-Stop events that follow proper conventions.  
                {
                    // We currently only handle Start-Stops that use the ActivityPath convention
                    // We could change this, but it is not clear what value it has to do that.  
                    Guid activityID = data.ActivityID;
                    if (StartStopActivityComputer.IsActivityPath(activityID, data.ProcessID))
                    {
                        if (data.Opcode == TraceEventOpcode.Start)
                        {
                            if (data.ProviderGuid == MicrosoftDiagnosticsDiagnosticSourceProvider)
                            {
                                // Inside the function, it will filter the events by 'EventName'. 
                                // It will only process "Microsoft.EntityFrameworkCore.BeforeExecuteCommand" and "Microsoft.AspNetCore.Hosting.BeginRequest".
                                if (TryProcessDiagnosticSourceStartEvents(data))
                                {
                                    return;
                                }
                            }

                            string extraStartInfo = null;
                            // Include the first argument in extraInfo if it is a string (e.g. a URL or other identifier).  
                            if (0 < data.PayloadNames.Length)
                            {
                                try { extraStartInfo = data.PayloadValue(0) as string; }
                                catch (Exception) { }
                                if (extraStartInfo != null)
                                {
                                    extraStartInfo = "/" + data.payloadNames[0] + "=" + extraStartInfo;
                                }
                            }
                            OnStart(data, extraStartInfo);
                        }
                        else
                        {
                            Debug.Assert(data.Opcode == TraceEventOpcode.Stop);
                            OnStop(data);
                        }
                    }
                    else
                    {
                        Trace.WriteLine("Skipping start at  " + data.TimeStampRelativeMSec.ToString("n3") + " name = " + data.EventName);
                    }
                }
            };

#if HTTP_SERVICE_EVENTS
#if TODO_FIX_NOW // FIX NOW Use or remove. 
            // We monitor ReadyThread to make HttpService events more useful (see nodes above on lastHttpServiceUrl)
            m_source.Kernel.DispatcherReadyThread += delegate (DispatcherReadyThreadTraceData data)
            {
                if (lastHttpServiceUrl == null)
                    return;

            };
#endif

            m_source.Kernel.ThreadCSwitch += delegate (CSwitchTraceData data)
            {
                // This code is to transfer information from the Microsoft-Windows-HttpService HTTP_TASK_REQUEST/HTTP_OPCODE_DELIVER
                // event (that happens in the System process, not the target, and move it to the context switch that wakes up
                // in order to service the event. 
                if (lastHttpServiceDeliverUrl == null)
                    return;
                if (data.ProcessID != lastHttpServiceReceiveRequestTargetProcessId)
                    return;
                // Test Stack

                Guid activityID = lastHttpServiceDeliverActivityID;
                OnStart(data, "url=" + lastHttpServiceDeliverUrl, &activityID, null, null, "HttpServiceRec");
                lastHttpServiceDeliverUrl = null;
                lastHttpServiceDeliverActivityID = Guid.Empty;
            };
#endif
            // Show the exception handling call stacks as a separate Activity.
            // This can help users notice the time spent in the exception handling logic.
            var clrExceptionParser = m_source.Clr;
            clrExceptionParser.ExceptionCatchStart += delegate (ExceptionHandlingTraceData data)
            {
                OnStart(data, data.MethodName, null, null, null, "ExceptionHandling");
            };
            clrExceptionParser.ExceptionCatchStop += delegate (EmptyTraceData data)
            {
                OnStop(data);
            };

            var aspNetParser = new AspNetTraceEventParser(m_source);
            aspNetParser.AspNetReqStart += delegate (AspNetStartTraceData data)
            {
                // if the related activity is not present, try using the context ID as the creator ID to look up.   
                // The ASPNet events reuse the IIS ID which means first stop kills both.   As it turns out
                // IIS stops before ASP (also incorrect) but it mostly this is benign...  
                StartStopActivity creator = null;
                if (data.RelatedActivityID == Guid.Empty)
                {
                    creator = GetActiveStartStopActivityTable(data.ContextId, data.ProcessID);
                }

                Guid activityId = data.ContextId;
                OnStart(data, data.Path, &activityId, null, creator, null, false);
            };
            aspNetParser.AspNetReqStop += delegate (AspNetStopTraceData data)
            {
                Guid activityId = data.ContextId;
                OnStop(data, &activityId);
            };
            // There are other ASP.NET events that have context information and this is useful
            aspNetParser.AspNetReqStartHandler += delegate (AspNetStartHandlerTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPipelineModuleEnter += delegate (AspNetPipelineModuleEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqGetAppDomainEnter += delegate (AspNetGetAppDomainEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };

            // These are probably not important, but they may help.  
            aspNetParser.AspNetReqRoleManagerBegin += delegate (AspNetRoleManagerBeginTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqRoleManagerGetUserRoles += delegate (AspNetRoleManagerGetUserRolesTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqRoleManagerEnd += delegate (AspNetRoleManagerEndTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqMapHandlerEnter += delegate (AspNetMapHandlerEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqMapHandlerLeave += delegate (AspNetMapHandlerLeaveTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqHttpHandlerEnter += delegate (AspNetHttpHandlerEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqHttpHandlerLeave += delegate (AspNetHttpHandlerLeaveTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPagePreInitEnter += delegate (AspNetPagePreInitEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPagePreInitLeave += delegate (AspNetPagePreInitLeaveTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPageInitEnter += delegate (AspNetPageInitEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPageInitLeave += delegate (AspNetPageInitLeaveTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPageLoadEnter += delegate (AspNetPageLoadEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPageLoadLeave += delegate (AspNetPageLoadLeaveTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPagePreRenderEnter += delegate (AspNetPagePreRenderEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPagePreRenderLeave += delegate (AspNetPagePreRenderLeaveTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPageSaveViewstateEnter += delegate (AspNetPageSaveViewstateEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPageSaveViewstateLeave += delegate (AspNetPageSaveViewstateLeaveTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPageRenderEnter += delegate (AspNetPageRenderEnterTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };
            aspNetParser.AspNetReqPageRenderLeave += delegate (AspNetPageRenderLeaveTraceData data)
            {
                SetThreadToStartStopActivity(data, data.ContextId);
            };

            var WCFParser = new ApplicationServerTraceEventParser(m_source);

            WCFParser.WebHostRequestStart += delegate (Multidata69TemplateATraceData data)
            {
                OnStart(data, data.VirtualPath);
            };
            WCFParser.WebHostRequestStop += delegate (OneStringsTemplateATraceData data)
            {
                OnStop(data);
            };

            // Microsoft-Windows-Application Server-Applications/TransportReceive/Stop
            WCFParser.MessageReceivedByTransport += delegate (Multidata29TemplateHATraceData data)
            {
                // This actually looks like a Stop opcode, but it is really a start because
                // it has a RelatedActivityID   
                OnStart(data, data.ListenAddress, null, null, null, "OperationDispatch");
            };

            // These Stop the Starts.  We don't want leaks in the common case.   
            WCFParser.DispatchFailed += delegate (Multidata38TemplateHATraceData data)
            {
                OnStop(data);
            };
            WCFParser.DispatchSuccessful += delegate (Multidata38TemplateHATraceData data)
            {
                OnStop(data);
            };

            WCFParser.OperationInvoked += delegate (Multidata24TemplateHATraceData data)
            {
                // The creator uses the same ID as myself.  
                OnStart(data, data.MethodName, null, null, GetActiveStartStopActivityTable(data.ActivityID, data.ProcessID));
            };
            WCFParser.OperationCompleted += delegate (Multidata28TemplateHATraceData data)
            {
                OnStop(data);
            };

            WCFParser.ServiceActivationStart += SetThreadToStartStopActivity;
            WCFParser.ServiceHostFactoryCreationStart += SetThreadToStartStopActivity;
            WCFParser.ServiceHostStarted += SetThreadToStartStopActivity;
            WCFParser.HttpMessageReceiveStart += SetThreadToStartStopActivity;
            WCFParser.HttpContextBeforeProcessAuthentication += SetThreadToStartStopActivity;
            WCFParser.TokenValidationStarted += SetThreadToStartStopActivity;
            WCFParser.MessageReadByEncoder += SetThreadToStartStopActivity;
            WCFParser.HttpResponseReceiveStart += SetThreadToStartStopActivity;
            WCFParser.SocketReadStop += SetThreadToStartStopActivity;
            WCFParser.SocketAsyncReadStop += SetThreadToStartStopActivity;
            WCFParser.SignatureVerificationStart += SetThreadToStartStopActivity;
            WCFParser.SignatureVerificationSuccess += SetThreadToStartStopActivity;
            WCFParser.ChannelReceiveStop += SetThreadToStartStopActivity;
            WCFParser.DispatchMessageStart += SetThreadToStartStopActivity;
            WCFParser.IncrementBusyCount += SetThreadToStartStopActivity;
            WCFParser.DispatchMessageBeforeAuthorization += SetThreadToStartStopActivity;
            WCFParser.ActionItemScheduled += SetThreadToStartStopActivity;
            WCFParser.GetServiceInstanceStart += SetThreadToStartStopActivity;
            WCFParser.GetServiceInstanceStop += SetThreadToStartStopActivity;
            WCFParser.ActionItemCallbackInvoked += SetThreadToStartStopActivity;
            WCFParser.ChannelReceiveStart += SetThreadToStartStopActivity;
            WCFParser.OutgoingMessageSecured += SetThreadToStartStopActivity;
            WCFParser.SocketWriteStart += SetThreadToStartStopActivity;
            WCFParser.SocketAsyncWriteStart += SetThreadToStartStopActivity;
            WCFParser.BinaryMessageEncodingStart += SetThreadToStartStopActivity;
            WCFParser.MtomMessageEncodingStart += SetThreadToStartStopActivity;
            WCFParser.TextMessageEncodingStart += SetThreadToStartStopActivity;
            WCFParser.BinaryMessageDecodingStart += SetThreadToStartStopActivity;
            WCFParser.MtomMessageDecodingStart += SetThreadToStartStopActivity;
            WCFParser.TextMessageDecodingStart += SetThreadToStartStopActivity;
            WCFParser.StreamedMessageWrittenByEncoder += SetThreadToStartStopActivity;
            WCFParser.MessageWrittenAsynchronouslyByEncoder += SetThreadToStartStopActivity;
            WCFParser.BufferedAsyncWriteStop += SetThreadToStartStopActivity;
            WCFParser.HttpPipelineProcessResponseStop += SetThreadToStartStopActivity;
            WCFParser.WebSocketAsyncWriteStop += SetThreadToStartStopActivity;
            WCFParser.MessageSentByTransport += SetThreadToStartStopActivity;
            WCFParser.HttpSendStop += SetThreadToStartStopActivity;
            WCFParser.DispatchMessageStop += SetThreadToStartStopActivity;
            WCFParser.DispatchSuccessful += SetThreadToStartStopActivity;

            // Server-side quota information.
            WCFParser.MaxReceivedMessageSizeExceeded += SetThreadToStartStopActivity;
            WCFParser.MaxPendingConnectionsExceeded += SetThreadToStartStopActivity;
            WCFParser.ReaderQuotaExceeded += SetThreadToStartStopActivity;
            WCFParser.NegotiateTokenAuthenticatorStateCacheExceeded += SetThreadToStartStopActivity;
            WCFParser.NegotiateTokenAuthenticatorStateCacheRatio += SetThreadToStartStopActivity;
            WCFParser.SecuritySessionRatio += SetThreadToStartStopActivity;
            WCFParser.PendingConnectionsRatio += SetThreadToStartStopActivity;
            WCFParser.ConcurrentCallsRatio += SetThreadToStartStopActivity;
            WCFParser.ConcurrentSessionsRatio += SetThreadToStartStopActivity;
            WCFParser.ConcurrentInstancesRatio += SetThreadToStartStopActivity;
            WCFParser.PendingAcceptsAtZero += SetThreadToStartStopActivity;

            // WCF client operations.
            // TODO FIX NOW, I have never run these!  Get some data to test against.  
            WCFParser.ClientOperationPrepared += delegate (Multidata22TemplateHATraceData data)
            {
                string extraInformation = "/Action=" + data.ServiceAction + "/URL=" + data.Destination;
                OnStart(data, extraInformation, null, null, GetActiveStartStopActivityTable(data.ActivityID, data.ProcessID), "ClientOperation");
            };
            WCFParser.ServiceChannelCallStop += delegate (Multidata22TemplateHATraceData data)
            {
                OnStop(data);
            };
        }