internal List <Metric> AddMetricsListWithViews(Instrument instrument, List <MetricStreamConfiguration> metricStreamConfigs)
        {
            var maxCountMetricsToBeCreated = metricStreamConfigs.Count;

            // Create list with initial capacity as the max metric count.
            // Due to duplicate/max limit, we may not end up using them
            // all, and that memory is wasted until Meter disposed.
            // TODO: Revisit to see if we need to do metrics.TrimExcess()
            var metrics = new List <Metric>(maxCountMetricsToBeCreated);

            lock (this.instrumentCreationLock)
            {
                for (int i = 0; i < maxCountMetricsToBeCreated; i++)
                {
                    var metricStreamConfig = metricStreamConfigs[i];
                    var meterName          = instrument.Meter.Name;
                    var metricName         = metricStreamConfig?.Name ?? instrument.Name;
                    var metricStreamName   = $"{meterName}.{metricName}";

                    if (!MeterProviderBuilderSdk.IsValidInstrumentName(metricName))
                    {
                        OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(
                            metricName,
                            instrument.Meter.Name,
                            "Metric name is invalid.",
                            "The name must comply with the OpenTelemetry specification.");

                        continue;
                    }

                    if (this.metricStreamNames.Contains(metricStreamName))
                    {
                        OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(metricName, instrument.Meter.Name, "Metric name conflicting with existing name.", "Either change the name of the instrument or change name using MeterProviderBuilder.AddView.");
                        continue;
                    }

                    if (metricStreamConfig?.Aggregation == Aggregation.Drop)
                    {
                        OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(metricName, instrument.Meter.Name, "View configuration asks to drop this instrument.", "Modify view configuration to allow this instrument, if desired.");
                        continue;
                    }

                    var index = ++this.metricIndex;
                    if (index >= this.maxMetricStreams)
                    {
                        OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(metricName, instrument.Meter.Name, "Maximum allowed Metric streams for the provider exceeded.", "Use MeterProviderBuilder.AddView to drop unused instruments. Or use MeterProviderBuilder.SetMaxMetricStreams to configure MeterProvider to allow higher limit.");
                    }
                    else
                    {
                        Metric   metric;
                        var      metricDescription     = metricStreamConfig?.Description ?? instrument.Description;
                        string[] tagKeysInteresting    = metricStreamConfig?.TagKeys;
                        double[] histogramBucketBounds = (metricStreamConfig is ExplicitBucketHistogramConfiguration histogramConfig &&
                                                          histogramConfig.Boundaries != null) ? histogramConfig.Boundaries : null;
                        metric = new Metric(instrument, this.Temporality, metricName, metricDescription, this.maxMetricPointsPerMetricStream, histogramBucketBounds, tagKeysInteresting);

                        this.metrics[index] = metric;
                        metrics.Add(metric);
                        this.metricStreamNames.Add(metricStreamName);
                    }
                }

                return(metrics);
            }
        }
 internal void RecordSingleStreamDoubleMeasurement(Metric metric, double value, ReadOnlySpan <KeyValuePair <string, object> > tags)
 {
     metric.UpdateDouble(value, tags);
 }
 internal void CompleteSingleStreamMeasurement(Metric metric)
 {
     metric.InstrumentDisposed = true;
 }
 internal void RecordSingleStreamLongMeasurement(Metric metric, long value, ReadOnlySpan <KeyValuePair <string, object> > tags)
 {
     metric.UpdateLong(value, tags);
 }
예제 #5
0
        public virtual void Collect()
        {
            lock (this.collectLock)
            {
                OpenTelemetrySdkEventSource.Log.MeterCollectInvoked(this.meterName);

                // collect all pending metric updates and send to batcher.
                // must sync to prevent multiple Collect occurring at same time.
                var boundInstrumentsToRemove = new List <LabelSet>();
                foreach (var longCounter in this.longCounters)
                {
                    var metricName        = longCounter.Key;
                    var counterInstrument = longCounter.Value;
                    var metric            = new Metric(this.meterName, metricName, this.meterName + metricName, AggregationType.LongSum);
                    foreach (var handle in counterInstrument.GetAllBoundInstruments())
                    {
                        var labelSet   = handle.Key;
                        var aggregator = handle.Value.GetAggregator();
                        aggregator.Checkpoint();
                        var metricData = aggregator.ToMetricData();
                        metricData.Labels = labelSet.Labels;
                        metric.Data.Add(metricData);

                        // Updates so far are pushed to Processor/Exporter.
                        // Adjust status accordinly.
                        // The status flows from initial UpdatePending, to
                        // NoPendingUpdate, to CandidateForRemoval, to physical removal.
                        // i.e UpdatePending->NoPendingUpdate->CandidateForRemoval->removal
                        if (handle.Value.Status == RecordStatus.CandidateForRemoval)
                        {
                            // The actual removal doesn't occur here as we are still
                            // iterating the dictionary.
                            boundInstrumentsToRemove.Add(labelSet);
                        }
                        else if (handle.Value.Status == RecordStatus.UpdatePending)
                        {
                            handle.Value.Status = RecordStatus.NoPendingUpdate;
                        }
                        else if (handle.Value.Status == RecordStatus.NoPendingUpdate)
                        {
                            handle.Value.Status = RecordStatus.CandidateForRemoval;
                        }
                    }

                    this.metricProcessor.Process(metric);
                    foreach (var boundInstrumentToRemove in boundInstrumentsToRemove)
                    {
                        // This actual unbinding or removal of the record occurs inside UnBind
                        // which synchronizes with Bind to ensure no record with pending update
                        // is lost.
                        counterInstrument.UnBind(boundInstrumentToRemove);
                    }

                    boundInstrumentsToRemove.Clear();
                }

                foreach (var doubleCounter in this.doubleCounters)
                {
                    var metricName        = doubleCounter.Key;
                    var counterInstrument = doubleCounter.Value;
                    var metric            = new Metric(this.meterName, metricName, this.meterName + metricName, AggregationType.DoubleSum);
                    foreach (var handle in counterInstrument.GetAllBoundInstruments())
                    {
                        var labelSet   = handle.Key;
                        var aggregator = handle.Value.GetAggregator();
                        aggregator.Checkpoint();
                        var metricData = aggregator.ToMetricData();
                        metricData.Labels = labelSet.Labels;
                        metric.Data.Add(metricData);

                        // Updates so far are pushed to Processor/Exporter.
                        // Adjust status accordinly.
                        // The status flows from initial UpdatePending, to
                        // NoPendingUpdate, to CandidateForRemoval, to physical removal.
                        // i.e UpdatePending->NoPendingUpdate->CandidateForRemoval->removal
                        if (handle.Value.Status == RecordStatus.CandidateForRemoval)
                        {
                            // The actual removal doesn't occur here as we are still
                            // iterating the dictionary.
                            boundInstrumentsToRemove.Add(labelSet);
                        }
                        else if (handle.Value.Status == RecordStatus.UpdatePending)
                        {
                            handle.Value.Status = RecordStatus.NoPendingUpdate;
                        }
                        else if (handle.Value.Status == RecordStatus.NoPendingUpdate)
                        {
                            handle.Value.Status = RecordStatus.CandidateForRemoval;
                        }
                    }

                    this.metricProcessor.Process(metric);
                    foreach (var boundInstrumentToRemove in boundInstrumentsToRemove)
                    {
                        // This actual unbinding or removal of the record occurs inside UnBind
                        // which synchronizes with Bind to ensure no record with pending update
                        // is lost.
                        counterInstrument.UnBind(boundInstrumentToRemove);
                    }

                    boundInstrumentsToRemove.Clear();
                }

                foreach (var longMeasure in this.longMeasures)
                {
                    var metricName        = longMeasure.Key;
                    var measureInstrument = longMeasure.Value;
                    var metric            = new Metric(this.meterName, metricName, this.meterName + metricName, AggregationType.Int64Summary);
                    foreach (var handle in measureInstrument.GetAllBoundInstruments())
                    {
                        var labelSet   = handle.Key;
                        var aggregator = handle.Value.GetAggregator();
                        aggregator.Checkpoint();
                        var metricData = aggregator.ToMetricData();
                        metricData.Labels = labelSet.Labels;
                        metric.Data.Add(metricData);
                    }

                    this.metricProcessor.Process(metric);
                }

                foreach (var doubleMeasure in this.doubleMeasures)
                {
                    var metricName        = doubleMeasure.Key;
                    var measureInstrument = doubleMeasure.Value;
                    var metric            = new Metric(this.meterName, metricName, this.meterName + metricName, AggregationType.DoubleSummary);
                    foreach (var handle in measureInstrument.GetAllBoundInstruments())
                    {
                        var labelSet   = handle.Key;
                        var aggregator = handle.Value.GetAggregator();
                        aggregator.Checkpoint();
                        var metricData = aggregator.ToMetricData();
                        metricData.Labels = labelSet.Labels;
                        metric.Data.Add(metricData);
                    }

                    this.metricProcessor.Process(metric);
                }

                foreach (var longObserver in this.longObservers)
                {
                    var metricName         = longObserver.Key;
                    var observerInstrument = longObserver.Value;
                    var metric             = new Metric(this.meterName, metricName, this.meterName + metricName, AggregationType.LongSum);
                    try
                    {
                        // TODO: Decide if we want to enforce a timeout. Issue # 542
                        observerInstrument.InvokeCallback();
                    }
                    catch (Exception ex)
                    {
                        OpenTelemetrySdkEventSource.Log.MetricObserverCallbackException(metricName, ex);
                    }

                    foreach (var handle in observerInstrument.GetAllHandles())
                    {
                        var labelSet   = handle.Key;
                        var aggregator = handle.Value.GetAggregator();
                        aggregator.Checkpoint();
                        var metricData = aggregator.ToMetricData();
                        metricData.Labels = labelSet.Labels;
                        metric.Data.Add(metricData);
                    }

                    this.metricProcessor.Process(metric);
                }

                foreach (var doubleObserver in this.doubleObservers)
                {
                    var metricName         = doubleObserver.Key;
                    var observerInstrument = doubleObserver.Value;
                    var metric             = new Metric(this.meterName, metricName, this.meterName + metricName, AggregationType.LongSum);
                    try
                    {
                        // TODO: Decide if we want to enforce a timeout. Issue # 542
                        observerInstrument.InvokeCallback();
                    }
                    catch (Exception ex)
                    {
                        OpenTelemetrySdkEventSource.Log.MetricObserverCallbackException(metricName, ex);
                    }

                    foreach (var handle in observerInstrument.GetAllHandles())
                    {
                        var labelSet   = handle.Key;
                        var aggregator = handle.Value.GetAggregator();
                        aggregator.Checkpoint();
                        var metricData = aggregator.ToMetricData();
                        metricData.Labels = labelSet.Labels;
                        metric.Data.Add(metricData);
                    }

                    this.metricProcessor.Process(metric);
                }
            }
        }