Skip to content

Commit

Permalink
Merge branch 'main' into 2361_cloning_methods
Browse files Browse the repository at this point in the history
  • Loading branch information
TimothyMothra authored Mar 31, 2022
2 parents 7b7a7b6 + 25ba213 commit 46ef282
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 86 deletions.
8 changes: 6 additions & 2 deletions docs/metrics/extending-the-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ not covered by the built-in exporters:
done via `OpenTelemetry.SuppressInstrumentationScope`.
* Exporters receives a batch of `Metric`, and each `Metric`
can contain 1 or more `MetricPoint`s.
The exporter should perform all actions (e.g. serializing etc.) with
the `Metric`s and `MetricsPoint`s in the batch before returning control from
`Export`, once the control is returned, the exporter can no longer make any
assumptions about the state of the batch or anything inside it.
* Exporters should use `ParentProvider.GetResource()` to get the `Resource`
associated with the provider.

Expand All @@ -54,8 +58,8 @@ class MyExporter : BaseExporter<Metric>
}
```

A demo exporter which simply writes metric name and metric point start time
, tags to the console is shown [here](./MyExporter.cs).
A demo exporter which simply writes metric name, metric point start time
and tags to the console is shown [here](./MyExporter.cs).

Apart from the exporter itself, you should also provide extension methods as
shown [here](./MyExporterExtensions.cs). This allows users to add the Exporter
Expand Down
6 changes: 6 additions & 0 deletions src/OpenTelemetry/Internal/OpenTelemetrySdkEventSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,12 @@ public void MetricReaderEvent(string message)
this.WriteEvent(40, message);
}

[Event(41, Message = "View Configuration ignored for Instrument '{0}', Meter '{1}'. Reason: '{2}'. Measurements from the instrument will use default configuration for Aggregation. Suggested action: '{3}'", Level = EventLevel.Warning)]
public void MetricViewIgnored(string instrumentName, string meterName, string reason, string fix)
{
this.WriteEvent(41, instrumentName, meterName, reason, fix);
}

#if DEBUG
public class OpenTelemetryEventListener : EventListener
{
Expand Down
29 changes: 13 additions & 16 deletions src/OpenTelemetry/Metrics/AggregatorStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ internal sealed class AggregatorStore
private int batchSize = 0;
private int metricCapHitMessageLogged;
private bool zeroTagMetricPointInitialized;
private DateTimeOffset startTimeExclusive;
private DateTimeOffset endTimeInclusive;

internal AggregatorStore(
string name,
Expand All @@ -66,7 +64,7 @@ internal AggregatorStore(
this.aggType = aggType;
this.outputDelta = temporality == AggregationTemporality.Delta;
this.histogramBounds = histogramBounds;
this.startTimeExclusive = DateTimeOffset.UtcNow;
this.StartTimeExclusive = DateTimeOffset.UtcNow;
if (tagKeysInteresting == null)
{
this.updateLongCallback = this.UpdateLong;
Expand All @@ -86,6 +84,10 @@ internal AggregatorStore(

private delegate void UpdateDoubleDelegate(double value, ReadOnlySpan<KeyValuePair<string, object>> tags);

internal DateTimeOffset StartTimeExclusive { get; private set; }

internal DateTimeOffset EndTimeInclusive { get; private set; }

internal void Update(long value, ReadOnlySpan<KeyValuePair<string, object>> tags)
{
this.updateLongCallback(value, tags);
Expand All @@ -109,7 +111,7 @@ internal int Snapshot()
this.SnapshotCumulative(indexSnapshot);
}

this.endTimeInclusive = DateTimeOffset.UtcNow;
this.EndTimeInclusive = DateTimeOffset.UtcNow;
return this.batchSize;
}

Expand All @@ -128,9 +130,9 @@ internal void SnapshotDelta(int indexSnapshot)
this.batchSize++;
}

if (this.endTimeInclusive != default)
if (this.EndTimeInclusive != default)
{
this.startTimeExclusive = this.endTimeInclusive;
this.StartTimeExclusive = this.EndTimeInclusive;
}
}

Expand All @@ -139,7 +141,7 @@ internal void SnapshotCumulative(int indexSnapshot)
for (int i = 0; i <= indexSnapshot; i++)
{
ref var metricPoint = ref this.metricPoints[i];
if (metricPoint.StartTime == default)
if (!metricPoint.IsInitialized)
{
continue;
}
Expand All @@ -151,9 +153,7 @@ internal void SnapshotCumulative(int indexSnapshot)
}

internal MetricPointsAccessor GetMetricPoints()
{
return new MetricPointsAccessor(this.metricPoints, this.currentMetricPointBatch, this.batchSize, this.startTimeExclusive, this.endTimeInclusive);
}
=> new(this.metricPoints, this.currentMetricPointBatch, this.batchSize);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void InitializeZeroTagPointIfNotInitialized()
Expand All @@ -164,8 +164,7 @@ private void InitializeZeroTagPointIfNotInitialized()
{
if (!this.zeroTagMetricPointInitialized)
{
var dt = DateTimeOffset.UtcNow;
this.metricPoints[0] = new MetricPoint(this.aggType, dt, null, null, this.histogramBounds);
this.metricPoints[0] = new MetricPoint(this, this.aggType, null, null, this.histogramBounds);
this.zeroTagMetricPointInitialized = true;
}
}
Expand Down Expand Up @@ -231,8 +230,7 @@ private int LookupAggregatorStore(string[] tagKeys, object[] tagValues, int leng
}

ref var metricPoint = ref this.metricPoints[aggregatorIndex];
var dt = DateTimeOffset.UtcNow;
metricPoint = new MetricPoint(this.aggType, dt, sortedTags.Keys, sortedTags.Values, this.histogramBounds);
metricPoint = new MetricPoint(this, this.aggType, sortedTags.Keys, sortedTags.Values, this.histogramBounds);

// Add to dictionary *after* initializing MetricPoint
// as other threads can start writing to the
Expand Down Expand Up @@ -282,8 +280,7 @@ private int LookupAggregatorStore(string[] tagKeys, object[] tagValues, int leng
}

ref var metricPoint = ref this.metricPoints[aggregatorIndex];
var dt = DateTimeOffset.UtcNow;
metricPoint = new MetricPoint(this.aggType, dt, givenTags.Keys, givenTags.Values, this.histogramBounds);
metricPoint = new MetricPoint(this, this.aggType, givenTags.Keys, givenTags.Values, this.histogramBounds);

// Add to dictionary *after* initializing MetricPoint
// as other threads can start writing to the
Expand Down
4 changes: 2 additions & 2 deletions src/OpenTelemetry/Metrics/MeterProviderBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ public static MeterProviderBuilder AddView(this MeterProviderBuilder meterProvid
/// <remarks>
/// <list type="bullet">
/// <item>Note: An invalid <see cref="MetricStreamConfiguration"/>
/// returned from <paramref name="viewConfig"/> will cause a dropping
/// behavior for the instrument being configured, no error will be
/// returned from <paramref name="viewConfig"/> will cause the
/// view to be ignored, no error will be
/// thrown at runtime.</item>
/// <item>See View specification here : https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#view.</item>
/// </list>
Expand Down
9 changes: 3 additions & 6 deletions src/OpenTelemetry/Metrics/MeterProviderSdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,7 @@ internal MeterProviderSdk(
}
catch (Exception ex)
{
// TODO: This allocates the string even if none listening,
// could be improved with a separate dedicated method.
OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(instrument.Name, instrument.Meter.Name, "Applying View Configuration failed with error:" + ex.Message, "Fix the view configuration.");
return;
OpenTelemetrySdkEventSource.Log.MetricViewIgnored(instrument.Name, instrument.Meter.Name, ex.Message, "Fix the view configuration.");
}

if (metricStreamConfig != null)
Expand Down Expand Up @@ -207,7 +204,7 @@ internal MeterProviderSdk(
}
}

OpenTelemetrySdkEventSource.Log.MeterProviderSdkEvent($"Succeeded publishing Instrument = \"{instrument.Name}\" of Meter = \"{instrument.Meter.Name}\".");
OpenTelemetrySdkEventSource.Log.MeterProviderSdkEvent($"Completed publishing Instrument = \"{instrument.Name}\" of Meter = \"{instrument.Meter.Name}\".");
}
catch (Exception)
{
Expand Down Expand Up @@ -272,7 +269,7 @@ internal MeterProviderSdk(
}
}

OpenTelemetrySdkEventSource.Log.MeterProviderSdkEvent($"Succeeded publishing Instrument = \"{instrument.Name}\" of Meter = \"{instrument.Meter.Name}\".");
OpenTelemetrySdkEventSource.Log.MeterProviderSdkEvent($"Completed publishing Instrument = \"{instrument.Name}\" of Meter = \"{instrument.Meter.Name}\".");
}
catch (Exception)
{
Expand Down
30 changes: 11 additions & 19 deletions src/OpenTelemetry/Metrics/MetricPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ namespace OpenTelemetry.Metrics
/// </summary>
public struct MetricPoint
{
private readonly AggregatorStore aggregatorStore;

private readonly AggregationType aggType;

private HistogramBuckets histogramBuckets;
Expand All @@ -39,19 +41,18 @@ public struct MetricPoint
private MetricPointValueStorage deltaLastValue;

internal MetricPoint(
AggregatorStore aggregatorStore,
AggregationType aggType,
DateTimeOffset startTime,
string[] keys,
object[] values,
double[] histogramExplicitBounds)
{
Debug.Assert(aggregatorStore != null, "AggregatorStore was null.");
Debug.Assert((keys?.Length ?? 0) == (values?.Length ?? 0), "Key and value array lengths did not match.");
Debug.Assert(histogramExplicitBounds != null, "Histogram explicit Bounds was null.");

this.aggType = aggType;
this.StartTime = startTime;
this.Tags = new ReadOnlyTagCollection(keys, values);
this.EndTime = default;
this.runningValue = default;
this.snapshotValue = default;
this.deltaLastValue = default;
Expand All @@ -69,6 +70,9 @@ internal MetricPoint(
{
this.histogramBuckets = null;
}

// Note: Intentionally set last because this is used to detect valid MetricPoints.
this.aggregatorStore = aggregatorStore;
}

/// <summary>
Expand All @@ -83,26 +87,12 @@ public readonly ReadOnlyTagCollection Tags
/// <summary>
/// Gets the start time associated with the metric point.
/// </summary>
public DateTimeOffset StartTime
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal set;
}
public readonly DateTimeOffset StartTime => this.aggregatorStore.StartTimeExclusive;

/// <summary>
/// Gets the end time associated with the metric point.
/// </summary>
public DateTimeOffset EndTime
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal set;
}
public readonly DateTimeOffset EndTime => this.aggregatorStore.EndTimeInclusive;

internal MetricPointStatus MetricPointStatus
{
Expand All @@ -113,6 +103,8 @@ internal MetricPointStatus MetricPointStatus
private set;
}

internal readonly bool IsInitialized => this.aggregatorStore != null;

/// <summary>
/// Gets the sum long value associated with the metric point.
/// </summary>
Expand Down
36 changes: 5 additions & 31 deletions src/OpenTelemetry/Metrics/MetricPointsAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
// limitations under the License.
// </copyright>

using System;
using OpenTelemetry.Internal;

namespace OpenTelemetry.Metrics
Expand All @@ -28,28 +27,22 @@ public readonly struct MetricPointsAccessor
private readonly MetricPoint[] metricsPoints;
private readonly int[] metricPointsToProcess;
private readonly long targetCount;
private readonly DateTimeOffset start;
private readonly DateTimeOffset end;

internal MetricPointsAccessor(MetricPoint[] metricsPoints, int[] metricPointsToProcess, long targetCount, DateTimeOffset start, DateTimeOffset end)
internal MetricPointsAccessor(MetricPoint[] metricsPoints, int[] metricPointsToProcess, long targetCount)
{
Guard.ThrowIfNull(metricsPoints);

this.metricsPoints = metricsPoints;
this.metricPointsToProcess = metricPointsToProcess;
this.targetCount = targetCount;
this.start = start;
this.end = end;
}

/// <summary>
/// Returns an enumerator that iterates through the <see cref="MetricPointsAccessor"/>.
/// </summary>
/// <returns><see cref="Enumerator"/>.</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(this.metricsPoints, this.metricPointsToProcess, this.targetCount, this.start, this.end);
}
=> new(this.metricsPoints, this.metricPointsToProcess, this.targetCount);

/// <summary>
/// Enumerates the elements of a <see cref="MetricPointsAccessor"/>.
Expand All @@ -58,31 +51,22 @@ public struct Enumerator
{
private readonly MetricPoint[] metricsPoints;
private readonly int[] metricPointsToProcess;
private readonly DateTimeOffset start;
private readonly DateTimeOffset end;
private readonly long targetCount;
private long index;

internal Enumerator(MetricPoint[] metricsPoints, int[] metricPointsToProcess, long targetCount, DateTimeOffset start, DateTimeOffset end)
internal Enumerator(MetricPoint[] metricsPoints, int[] metricPointsToProcess, long targetCount)
{
this.metricsPoints = metricsPoints;
this.metricPointsToProcess = metricPointsToProcess;
this.targetCount = targetCount;
this.index = -1;
this.start = start;
this.end = end;
}

/// <summary>
/// Gets the <see cref="MetricPoint"/> at the current position of the enumerator.
/// </summary>
public ref readonly MetricPoint Current
{
get
{
return ref this.metricsPoints[this.metricPointsToProcess[this.index]];
}
}
=> ref this.metricsPoints[this.metricPointsToProcess[this.index]];

/// <summary>
/// Advances the enumerator to the next element of the <see
Expand All @@ -93,17 +77,7 @@ public ref readonly MetricPoint Current
/// langword="false"/> if the enumerator has passed the end of the
/// collection.</returns>
public bool MoveNext()
{
while (++this.index < this.targetCount)
{
ref var metricPoint = ref this.metricsPoints[this.metricPointsToProcess[this.index]];
metricPoint.StartTime = this.start;
metricPoint.EndTime = this.end;
return true;
}

return false;
}
=> ++this.index < this.targetCount;
}
}
}
16 changes: 15 additions & 1 deletion src/OpenTelemetry/Metrics/MetricReaderExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,21 @@ internal Metric AddMetricWithNoViews(Instrument instrument)
}
else
{
var metric = new Metric(instrumentIdentity, this.Temporality, this.maxMetricPointsPerMetricStream);
Metric metric = null;
try
{
metric = new Metric(instrumentIdentity, this.Temporality, this.maxMetricPointsPerMetricStream);
}
catch (NotSupportedException nse)
{
// TODO: This allocates string even if none listening.
// Could be improved with separate Event.
// Also the message could call out what Instruments
// and types (eg: int, long etc) are supported.
OpenTelemetrySdkEventSource.Log.MetricInstrumentIgnored(metricName, instrument.Meter.Name, "Unsupported instrument. Details: " + nse.Message, "Switch to a supported instrument type.");
return null;
}

this.instrumentIdentityToMetric[instrumentIdentity] = metric;
this.metrics[index] = metric;
this.metricStreamNames.Add(metricStreamName);
Expand Down
Loading

0 comments on commit 46ef282

Please sign in to comment.