private ITelemetryDocument CreateTelemetryDocument <TTelemetry>(
            TTelemetry telemetry,
            IEnumerable <DocumentStream> documentStreams,
            Func <DocumentStream, QuickPulseQuotaTracker> getQuotaTracker,
            Func <DocumentStream, bool> checkDocumentStreamFilters,
            Func <TTelemetry, ITelemetryDocument> convertTelemetryToTelemetryDocument)
        {
            // check which document streams are interested in this telemetry
            ITelemetryDocument telemetryDocument = null;
            var matchingDocumentStreamIds        = new List <string>();

            foreach (DocumentStream matchingDocumentStream in documentStreams.Where(checkDocumentStreamFilters))
            {
                // for each interested document stream only let the document through if there's quota available for that stream
                if (getQuotaTracker(matchingDocumentStream).ApplyQuota())
                {
                    // only create the telemetry document once
                    telemetryDocument = telemetryDocument ?? convertTelemetryToTelemetryDocument(telemetry);

                    matchingDocumentStreamIds.Add(matchingDocumentStream.Id);
                }
            }

            if (telemetryDocument != null)
            {
                telemetryDocument.DocumentStreamIds = matchingDocumentStreamIds.ToArray();

                // this document will count as 1 towards the global quota regardless of number of streams that are interested in it
                telemetryDocument = this.globalQuotaTracker.ApplyQuota() ? telemetryDocument : null;
            }

            return(telemetryDocument);
        }
        private void CollectException(ExceptionTelemetry exceptionTelemetry)
        {
            if (this.exceptionQuotaTracker.ApplyQuota())
            {
                ITelemetryDocument telemetryDocument = ConvertExceptionToTelemetryDocument(exceptionTelemetry);

                this.dataAccumulatorManager.CurrentDataAccumulator.TelemetryDocuments.Push(telemetryDocument);
            }
        }
        private void CollectDependency(DependencyTelemetry dependencyTelemetry)
        {
            if (this.dependencyQuotaTracker.ApplyQuota())
            {
                ITelemetryDocument telemetryDocument = ConvertDependencyToTelemetryDocument(dependencyTelemetry);

                this.dataAccumulatorManager.CurrentDataAccumulator.TelemetryDocuments.Push(telemetryDocument);
            }
        }
        private void CollectRequest(RequestTelemetry requestTelemetry)
        {
            if (this.requestQuotaTracker.ApplyQuota())
            {
                ITelemetryDocument telemetryDocument = ConvertRequestToTelemetryDocument(requestTelemetry);

                this.dataAccumulatorManager.CurrentDataAccumulator.TelemetryDocuments.Push(telemetryDocument);
            }
        }
        private static void SetCommonTelemetryDocumentData(ITelemetryDocument telemetryDocument, ITelemetry telemetry)
        {
            if (telemetry.Context == null)
            {
                return;
            }

            telemetryDocument.OperationName     = TruncateValue(telemetry.Context.Operation?.Name);
            telemetryDocument.InternalNodeName  = TruncateValue(telemetry.Context.GetInternalContext()?.NodeName);
            telemetryDocument.CloudRoleName     = TruncateValue(telemetry.Context.Cloud?.RoleName);
            telemetryDocument.CloudRoleInstance = TruncateValue(telemetry.Context.Cloud?.RoleInstance);
        }
        private void ProcessTelemetry(ITelemetry telemetry)
        {
            // only process items that are going to the instrumentation key that our module is initialized with
            if (string.IsNullOrWhiteSpace(this.config?.InstrumentationKey) ||
                !string.Equals(telemetry?.Context?.InstrumentationKey, this.config.InstrumentationKey, StringComparison.OrdinalIgnoreCase))
            {
                return;
            }

            var telemetryAsRequest    = telemetry as RequestTelemetry;
            var telemetryAsDependency = telemetry as DependencyTelemetry;
            var telemetryAsException  = telemetry as ExceptionTelemetry;
            var telemetryAsEvent      = telemetry as EventTelemetry;
            var telemetryAsTrace      = telemetry as TraceTelemetry;

            // update aggregates
            bool?originalRequestTelemetrySuccessValue = null;

            if (telemetryAsRequest != null)
            {
                // special treatment for RequestTelemetry.Success
                originalRequestTelemetrySuccessValue = telemetryAsRequest.Success;
                telemetryAsRequest.Success           = IsRequestSuccessful(telemetryAsRequest);

                this.UpdateRequestAggregates(telemetryAsRequest);
            }
            else if (telemetryAsDependency != null)
            {
                this.UpdateDependencyAggregates(telemetryAsDependency);
            }
            else if (telemetryAsException != null)
            {
                this.UpdateExceptionAggregates();
            }

            // get a local reference, the accumulator might get swapped out at any time
            // in case we continue to process this configuration once the accumulator is out, increase the reference count so that this accumulator is not sent out before we're done
            CollectionConfigurationAccumulator configurationAccumulatorLocal =
                this.dataAccumulatorManager.CurrentDataAccumulator.CollectionConfigurationAccumulator;

            // if the accumulator is swapped out and a sample is created and sent out - all while between these two lines, this telemetry item gets lost
            // however, that is not likely to happen
            configurationAccumulatorLocal.AddRef();

            try
            {
                // collect full telemetry items
                if (!this.disableFullTelemetryItems)
                {
                    ITelemetryDocument           telemetryDocument = null;
                    IEnumerable <DocumentStream> documentStreams   = configurationAccumulatorLocal.CollectionConfiguration.DocumentStreams;

                    //!!! report runtime errors for filter groups?
                    CollectionConfigurationError[] groupErrors;

                    if (telemetryAsRequest != null)
                    {
                        telemetryDocument = this.CreateTelemetryDocument(
                            telemetryAsRequest,
                            documentStreams,
                            documentStream => documentStream.RequestQuotaTracker,
                            documentStream => documentStream.CheckFilters(telemetryAsRequest, out groupErrors),
                            ConvertRequestToTelemetryDocument);
                    }
                    else if (telemetryAsDependency != null)
                    {
                        telemetryDocument = this.CreateTelemetryDocument(
                            telemetryAsDependency,
                            documentStreams,
                            documentStream => documentStream.DependencyQuotaTracker,
                            documentStream => documentStream.CheckFilters(telemetryAsDependency, out groupErrors),
                            ConvertDependencyToTelemetryDocument);
                    }
                    else if (telemetryAsException != null)
                    {
                        telemetryDocument = this.CreateTelemetryDocument(
                            telemetryAsException,
                            documentStreams,
                            documentStream => documentStream.ExceptionQuotaTracker,
                            documentStream => documentStream.CheckFilters(telemetryAsException, out groupErrors),
                            ConvertExceptionToTelemetryDocument);
                    }
                    else if (telemetryAsEvent != null)
                    {
                        telemetryDocument = this.CreateTelemetryDocument(
                            telemetryAsEvent,
                            documentStreams,
                            documentStream => documentStream.EventQuotaTracker,
                            documentStream => documentStream.CheckFilters(telemetryAsEvent, out groupErrors),
                            ConvertEventToTelemetryDocument);
                    }
                    else if (telemetryAsTrace != null)
                    {
                        telemetryDocument = this.CreateTelemetryDocument(
                            telemetryAsTrace,
                            documentStreams,
                            documentStream => documentStream.TraceQuotaTracker,
                            documentStream => documentStream.CheckFilters(telemetryAsTrace, out groupErrors),
                            ConvertTraceToTelemetryDocument);
                    }

                    if (telemetryDocument != null)
                    {
                        this.dataAccumulatorManager.CurrentDataAccumulator.TelemetryDocuments.Push(telemetryDocument);
                    }

                    this.dataAccumulatorManager.CurrentDataAccumulator.GlobalDocumentQuotaReached = this.globalQuotaTracker.QuotaExhausted;
                }

                // collect calculated metrics
                CollectionConfigurationError[] filteringErrors;
                string projectionError = null;

                if (telemetryAsRequest != null)
                {
                    QuickPulseTelemetryProcessor.ProcessMetrics(
                        configurationAccumulatorLocal,
                        configurationAccumulatorLocal.CollectionConfiguration.RequestMetrics,
                        telemetryAsRequest,
                        out filteringErrors,
                        ref projectionError);
                }
                else if (telemetryAsDependency != null)
                {
                    QuickPulseTelemetryProcessor.ProcessMetrics(
                        configurationAccumulatorLocal,
                        configurationAccumulatorLocal.CollectionConfiguration.DependencyMetrics,
                        telemetryAsDependency,
                        out filteringErrors,
                        ref projectionError);
                }
                else if (telemetryAsException != null)
                {
                    QuickPulseTelemetryProcessor.ProcessMetrics(
                        configurationAccumulatorLocal,
                        configurationAccumulatorLocal.CollectionConfiguration.ExceptionMetrics,
                        telemetryAsException,
                        out filteringErrors,
                        ref projectionError);
                }
                else if (telemetryAsEvent != null)
                {
                    QuickPulseTelemetryProcessor.ProcessMetrics(
                        configurationAccumulatorLocal,
                        configurationAccumulatorLocal.CollectionConfiguration.EventMetrics,
                        telemetryAsEvent,
                        out filteringErrors,
                        ref projectionError);
                }
                else if (telemetryAsTrace != null)
                {
                    QuickPulseTelemetryProcessor.ProcessMetrics(
                        configurationAccumulatorLocal,
                        configurationAccumulatorLocal.CollectionConfiguration.TraceMetrics,
                        telemetryAsTrace,
                        out filteringErrors,
                        ref projectionError);
                }

                //!!! report errors from string[] errors; and string projectionError;
            }
            finally
            {
                // special treatment for RequestTelemetry.Success - restore the value
                if (telemetryAsRequest != null)
                {
                    telemetryAsRequest.Success = originalRequestTelemetrySuccessValue;
                }

                configurationAccumulatorLocal.Release();
            }
        }