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); }
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); } } }