internal MeterProviderBuilder AddReader(MetricReader reader) { if (this.MetricReaders.Count >= 1) { throw new InvalidOperationException("Only one Metricreader is allowed."); } this.MetricReaders.Add(reader); return(this); }
public bool MoveNext() { if (this.node != null) { this.Current = this.node.Value; this.node = this.node.Next; return(true); } return(false); }
public CompositeMetricReader AddReader(MetricReader reader) { Guard.Null(reader, nameof(reader)); var node = new DoublyLinkedListNode(reader) { Previous = this.tail, }; this.tail.Next = node; this.tail = node; return(this); }
public CompositeMetricReader AddReader(MetricReader reader) { Guard.ThrowIfNull(reader); var node = new DoublyLinkedListNode(reader) { Previous = this.tail, }; this.tail.Next = node; this.tail = node; this.count++; return(this); }
static bool TryFindExporter(MetricReader reader, out T exporter) { if (reader is BaseExportingMetricReader exportingMetricReader) { exporter = exportingMetricReader.Exporter as T; return(exporter != null); } if (reader is CompositeMetricReader compositeMetricReader) { foreach (MetricReader childReader in compositeMetricReader) { if (TryFindExporter(childReader, out exporter)) { return(true); } } } exporter = null; return(false); }
internal MeterProviderSdk( Resource resource, IEnumerable <string> meterSources, List <MeterProviderBuilderBase.InstrumentationFactory> instrumentationFactories, List <Func <Instrument, MetricStreamConfiguration> > viewConfigs, IEnumerable <MetricReader> readers) { this.Resource = resource; this.viewConfigs = viewConfigs; this.metrics = new Metric[MaxMetrics]; this.metricsCurrentBatch = new Metric[MaxMetrics]; AggregationTemporality temporality = AggregationTemporality.Cumulative; foreach (var reader in readers) { Guard.Null(reader, nameof(reader)); reader.SetParentProvider(this); // TODO: Actually support multiple readers. // Currently the last reader's temporality wins. temporality = reader.PreferredAggregationTemporality; if (this.reader == null) { this.reader = reader; } else if (this.reader is CompositeMetricReader compositeReader) { compositeReader.AddReader(reader); } else { this.reader = new CompositeMetricReader(new[] { this.reader, reader }); } } if (instrumentationFactories.Any()) { foreach (var instrumentationFactory in instrumentationFactories) { this.instrumentations.Add(instrumentationFactory.Factory()); } } // Setup Listener Func <Instrument, bool> shouldListenTo = instrument => false; if (meterSources.Any(s => s.Contains('*'))) { var regex = GetWildcardRegex(meterSources); shouldListenTo = instrument => regex.IsMatch(instrument.Meter.Name); } else if (meterSources.Any()) { var meterSourcesToSubscribe = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var meterSource in meterSources) { meterSourcesToSubscribe.Add(meterSource); } shouldListenTo = instrument => meterSourcesToSubscribe.Contains(instrument.Meter.Name); } this.listener = new MeterListener(); var viewConfigCount = this.viewConfigs.Count; if (viewConfigCount > 0) { this.listener.InstrumentPublished = (instrument, listener) => { if (!shouldListenTo(instrument)) { OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "Instrument belongs to a Meter not subscribed by the provider.", "Use AddMeter to add the Meter to the provider."); return; } // Creating list with initial capacity as the maximum // possible size, to avoid any array resize/copy internally. // There may be excess space wasted, but it'll eligible for // GC right after this method. var metricStreamConfigs = new List <MetricStreamConfiguration>(viewConfigCount); foreach (var viewConfig in this.viewConfigs) { var metricStreamConfig = viewConfig(instrument); if (metricStreamConfig != null) { metricStreamConfigs.Add(metricStreamConfig); } } if (metricStreamConfigs.Count == 0) { // No views matched. Add null // which will apply defaults. // Users can turn off this default // by adding a view like below as the last view. // .AddView(instrumentName: "*", MetricStreamConfiguration.Drop) metricStreamConfigs.Add(null); } 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)) { // TODO: Log that instrument is ignored // as the resulting Metric name is conflicting // with existing name. continue; } if (metricStreamConfig?.Aggregation == Aggregation.Drop) { // TODO: Log that instrument is ignored // as user explicitly asked to drop it // with View. continue; } var index = ++this.metricIndex; if (index >= MaxMetrics) { // TODO: Log that instrument is ignored // as max number of Metrics have reached. } 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, temporality, metricName, metricDescription, histogramBucketBounds, tagKeysInteresting); this.metrics[index] = metric; metrics.Add(metric); this.metricStreamNames.Add(metricStreamName); } } if (metrics.Count > 0) { listener.EnableMeasurementEvents(instrument, metrics); } } }; // Everything double this.listener.SetMeasurementEventCallback <double>(this.MeasurementRecordedDouble); this.listener.SetMeasurementEventCallback <float>((instrument, value, tags, state) => this.MeasurementRecordedDouble(instrument, value, tags, state)); // Everything long this.listener.SetMeasurementEventCallback <long>(this.MeasurementRecordedLong); this.listener.SetMeasurementEventCallback <int>((instrument, value, tags, state) => this.MeasurementRecordedLong(instrument, value, tags, state)); this.listener.SetMeasurementEventCallback <short>((instrument, value, tags, state) => this.MeasurementRecordedLong(instrument, value, tags, state)); this.listener.SetMeasurementEventCallback <byte>((instrument, value, tags, state) => this.MeasurementRecordedLong(instrument, value, tags, state)); this.listener.MeasurementsCompleted = (instrument, state) => this.MeasurementsCompleted(instrument, state); } else { this.listener.InstrumentPublished = (instrument, listener) => { if (!shouldListenTo(instrument)) { OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "Instrument belongs to a Meter not subscribed by the provider.", "Use AddMeter to add the Meter to the provider."); return; } try { if (!MeterProviderBuilderSdk.IsValidInstrumentName(instrument.Name)) { OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored( instrument.Name, instrument.Meter.Name, "Instrument name is invalid.", "The name must comply with the OpenTelemetry specification"); return; } var meterName = instrument.Meter.Name; var metricName = instrument.Name; var metricStreamName = $"{meterName}.{metricName}"; Metric metric = null; lock (this.instrumentCreationLock) { 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 View."); return; } var index = ++this.metricIndex; if (index >= MaxMetrics) { OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(metricName, instrument.Meter.Name, "Maximum allowed Metrics for the provider exceeded.", "Use views to drop unused instruments. Or configure Provider to allow higher limit."); return; } else { metric = new Metric(instrument, temporality, metricName, instrument.Description); this.metrics[index] = metric; this.metricStreamNames.Add(metricStreamName); } } listener.EnableMeasurementEvents(instrument, metric); } catch (Exception) { OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "SDK internal error occurred.", "Contact SDK owners."); } }; // Everything double this.listener.SetMeasurementEventCallback <double>(this.MeasurementRecordedDoubleSingleStream); this.listener.SetMeasurementEventCallback <float>((instrument, value, tags, state) => this.MeasurementRecordedDoubleSingleStream(instrument, value, tags, state)); // Everything long this.listener.SetMeasurementEventCallback <long>(this.MeasurementRecordedLongSingleStream); this.listener.SetMeasurementEventCallback <int>((instrument, value, tags, state) => this.MeasurementRecordedLongSingleStream(instrument, value, tags, state)); this.listener.SetMeasurementEventCallback <short>((instrument, value, tags, state) => this.MeasurementRecordedLongSingleStream(instrument, value, tags, state)); this.listener.SetMeasurementEventCallback <byte>((instrument, value, tags, state) => this.MeasurementRecordedLongSingleStream(instrument, value, tags, state)); this.listener.MeasurementsCompleted = (instrument, state) => this.MeasurementsCompletedSingleStream(instrument, state); } this.listener.Start();
internal MeterProviderSdk( Resource resource, IEnumerable <string> meterSources, List <MeterProviderBuilderBase.InstrumentationFactory> instrumentationFactories, List <Func <Instrument, MetricStreamConfiguration> > viewConfigs, int maxMetricStreams, int maxMetricPointsPerMetricStream, IEnumerable <MetricReader> readers) { this.Resource = resource; this.viewConfigs = viewConfigs; foreach (var reader in readers) { Guard.Null(reader, nameof(reader)); reader.SetParentProvider(this); reader.SetMaxMetricStreams(maxMetricStreams); reader.SetMaxMetricPointsPerMetricStream(maxMetricPointsPerMetricStream); if (this.reader == null) { this.reader = reader; } else if (this.reader is CompositeMetricReader compositeReader) { compositeReader.AddReader(reader); } else { this.reader = new CompositeMetricReader(new[] { this.reader, reader }); } } this.compositeMetricReader = this.reader as CompositeMetricReader; if (instrumentationFactories.Any()) { foreach (var instrumentationFactory in instrumentationFactories) { this.instrumentations.Add(instrumentationFactory.Factory()); } } // Setup Listener Func <Instrument, bool> shouldListenTo = instrument => false; if (meterSources.Any(s => s.Contains('*'))) { var regex = GetWildcardRegex(meterSources); shouldListenTo = instrument => regex.IsMatch(instrument.Meter.Name); } else if (meterSources.Any()) { var meterSourcesToSubscribe = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var meterSource in meterSources) { meterSourcesToSubscribe.Add(meterSource); } shouldListenTo = instrument => meterSourcesToSubscribe.Contains(instrument.Meter.Name); } this.listener = new MeterListener(); var viewConfigCount = this.viewConfigs.Count; // We expect that all the readers to be added are provided before MeterProviderSdk is built. // If there are no readers added, we do not enable measurements for the instruments. if (viewConfigCount > 0) { this.listener.InstrumentPublished = (instrument, listener) => { if (!shouldListenTo(instrument)) { OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "Instrument belongs to a Meter not subscribed by the provider.", "Use AddMeter to add the Meter to the provider."); return; } // Creating list with initial capacity as the maximum // possible size, to avoid any array resize/copy internally. // There may be excess space wasted, but it'll eligible for // GC right after this method. var metricStreamConfigs = new List <MetricStreamConfiguration>(viewConfigCount); foreach (var viewConfig in this.viewConfigs) { var metricStreamConfig = viewConfig(instrument); if (metricStreamConfig != null) { metricStreamConfigs.Add(metricStreamConfig); } } if (metricStreamConfigs.Count == 0) { // No views matched. Add null // which will apply defaults. // Users can turn off this default // by adding a view like below as the last view. // .AddView(instrumentName: "*", MetricStreamConfiguration.Drop) metricStreamConfigs.Add(null); } if (this.reader != null) { if (this.compositeMetricReader == null) { var metrics = this.reader.AddMetricsListWithViews(instrument, metricStreamConfigs); if (metrics.Count > 0) { listener.EnableMeasurementEvents(instrument, metrics); } } else { var metricsSuperList = this.compositeMetricReader.AddMetricsSuperListWithViews(instrument, metricStreamConfigs); if (metricsSuperList.Any(metrics => metrics.Count > 0)) { listener.EnableMeasurementEvents(instrument, metricsSuperList); } } } }; // Everything double this.listener.SetMeasurementEventCallback <double>(this.MeasurementRecordedDouble); this.listener.SetMeasurementEventCallback <float>((instrument, value, tags, state) => this.MeasurementRecordedDouble(instrument, value, tags, state)); // Everything long this.listener.SetMeasurementEventCallback <long>(this.MeasurementRecordedLong); this.listener.SetMeasurementEventCallback <int>((instrument, value, tags, state) => this.MeasurementRecordedLong(instrument, value, tags, state)); this.listener.SetMeasurementEventCallback <short>((instrument, value, tags, state) => this.MeasurementRecordedLong(instrument, value, tags, state)); this.listener.SetMeasurementEventCallback <byte>((instrument, value, tags, state) => this.MeasurementRecordedLong(instrument, value, tags, state)); this.listener.MeasurementsCompleted = (instrument, state) => this.MeasurementsCompleted(instrument, state); } else { this.listener.InstrumentPublished = (instrument, listener) => { if (!shouldListenTo(instrument)) { OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "Instrument belongs to a Meter not subscribed by the provider.", "Use AddMeter to add the Meter to the provider."); return; } try { if (!MeterProviderBuilderSdk.IsValidInstrumentName(instrument.Name)) { OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored( instrument.Name, instrument.Meter.Name, "Instrument name is invalid.", "The name must comply with the OpenTelemetry specification"); return; } if (this.reader != null) { if (this.compositeMetricReader == null) { var metric = this.reader.AddMetricWithNoViews(instrument); if (metric != null) { listener.EnableMeasurementEvents(instrument, metric); } } else { var metrics = this.compositeMetricReader.AddMetricsWithNoViews(instrument); if (metrics.Any(metric => metric != null)) { listener.EnableMeasurementEvents(instrument, metrics); } } } } catch (Exception) { OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "SDK internal error occurred.", "Contact SDK owners."); } }; // Everything double this.listener.SetMeasurementEventCallback <double>(this.MeasurementRecordedDoubleSingleStream); this.listener.SetMeasurementEventCallback <float>((instrument, value, tags, state) => this.MeasurementRecordedDoubleSingleStream(instrument, value, tags, state)); // Everything long this.listener.SetMeasurementEventCallback <long>(this.MeasurementRecordedLongSingleStream); this.listener.SetMeasurementEventCallback <int>((instrument, value, tags, state) => this.MeasurementRecordedLongSingleStream(instrument, value, tags, state)); this.listener.SetMeasurementEventCallback <short>((instrument, value, tags, state) => this.MeasurementRecordedLongSingleStream(instrument, value, tags, state)); this.listener.SetMeasurementEventCallback <byte>((instrument, value, tags, state) => this.MeasurementRecordedLongSingleStream(instrument, value, tags, state)); this.listener.MeasurementsCompleted = (instrument, state) => this.MeasurementsCompletedSingleStream(instrument, state); } this.listener.Start();
/// <summary> /// Adds a reader to the provider. /// </summary> /// <param name="meterProviderBuilder"><see cref="MeterProviderBuilder"/>.</param> /// <param name="reader"><see cref="MetricReader"/>.</param> /// <returns><see cref="MeterProvider"/>.</returns> public static MeterProviderBuilder AddReader(this MeterProviderBuilder meterProviderBuilder, MetricReader reader) { if (meterProviderBuilder is MeterProviderBuilderBase meterProviderBuilderBase) { return(meterProviderBuilderBase.AddReader(reader)); } return(meterProviderBuilder); }
internal MeterProviderBuilder AddReader(MetricReader reader) { this.MetricReaders.Add(reader); return(this); }
public DoublyLinkedListNode(MetricReader value) { this.Value = value; }