Add ProxyMeter to MeterFactoryBase which invokes real Meter if provided. (#631)
* Add ProxyMeter to MeterFactoryBase which invokes real Meter if provided. * remove unwanted copy of a test file. Co-authored-by: Sergey Kanzhelev <S.Kanzhelev@live.com>
This commit is contained in:
parent
e56ee5d46b
commit
f333287509
|
|
@ -13,14 +13,19 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// </copyright>
|
||||
using System;
|
||||
|
||||
namespace OpenTelemetry.Metrics
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates Meters for an instrumentation library.
|
||||
/// Libraries should use this class as follows to obtain Meter instance.
|
||||
/// MeterFactoryBase.Default.GetMeter("libraryname", "version").
|
||||
/// </summary>
|
||||
public class MeterFactoryBase
|
||||
{
|
||||
private static NoOpMeter noOpMeter = new NoOpMeter();
|
||||
private static ProxyMeter proxyMeter = new ProxyMeter();
|
||||
private static bool isInitialized;
|
||||
private static MeterFactoryBase defaultFactory = new MeterFactoryBase();
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -32,14 +37,50 @@ namespace OpenTelemetry.Metrics
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an IMeter for a given name and version.
|
||||
/// Sets the default instance of <see cref="MeterFactoryBase"/>.
|
||||
/// </summary>
|
||||
/// <param name="meterFactory">Instance of <see cref="MeterFactoryBase"/>.</param>
|
||||
/// <remarks>
|
||||
/// This method can only be called once. Calling it multiple times will throw an <see cref="System.InvalidOperationException"/>.
|
||||
/// </remarks>
|
||||
/// <exception cref="System.InvalidOperationException">Thrown when called multiple times.</exception>
|
||||
public static void SetDefault(MeterFactoryBase meterFactory)
|
||||
{
|
||||
if (isInitialized)
|
||||
{
|
||||
throw new InvalidOperationException("Default factory is already set");
|
||||
}
|
||||
|
||||
defaultFactory = meterFactory ?? throw new ArgumentNullException(nameof(meterFactory));
|
||||
|
||||
// some libraries might have already used and cached ProxyMeter.
|
||||
// let's update it to real one and forward all calls.
|
||||
|
||||
// resource assignment is not possible for libraries that cache tracer before SDK is initialized.
|
||||
// SDK (Tracer) must be at least partially initialized before any collection starts to capture resources.
|
||||
// we might be able to work this around with events.
|
||||
proxyMeter.UpdateMeter(defaultFactory.GetMeter(null));
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Meter for a given name and version.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the instrumentation library.</param>
|
||||
/// <param name="version">Version of the instrumentation library (optional).</param>
|
||||
/// <returns>Meter with the given component name and version.</returns>
|
||||
/// <returns>Meter for the given name and version information.</returns>
|
||||
public virtual Meter GetMeter(string name, string version = null)
|
||||
{
|
||||
return noOpMeter;
|
||||
return isInitialized ? defaultFactory.GetMeter(name, version) : proxyMeter;
|
||||
}
|
||||
|
||||
// for tests
|
||||
internal void Reset()
|
||||
{
|
||||
proxyMeter = new ProxyMeter();
|
||||
isInitialized = false;
|
||||
defaultFactory = new MeterFactoryBase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// <copyright file="NoOpMeter.cs" company="OpenTelemetry Authors">
|
||||
// <copyright file="ProxyMeter.cs" company="OpenTelemetry Authors">
|
||||
// Copyright 2018, OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
@ -15,49 +15,66 @@
|
|||
// </copyright>
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace OpenTelemetry.Metrics
|
||||
{
|
||||
internal sealed class NoOpMeter : Meter
|
||||
/// <summary>
|
||||
/// Proxy Meter which act as a No-Op Meter, until real meter is provided.
|
||||
/// </summary>
|
||||
internal sealed class ProxyMeter : Meter
|
||||
{
|
||||
public NoOpMeter()
|
||||
private Meter realMeter;
|
||||
|
||||
public ProxyMeter()
|
||||
{
|
||||
}
|
||||
|
||||
public override CounterMetric<double> CreateDoubleCounter(string name, bool monotonic = true)
|
||||
{
|
||||
return NoOpCounterMetric<double>.Instance;
|
||||
return this.realMeter != null ? this.realMeter.CreateDoubleCounter(name, monotonic) : NoOpCounterMetric<double>.Instance;
|
||||
}
|
||||
|
||||
public override MeasureMetric<double> CreateDoubleMeasure(string name, bool absolute = true)
|
||||
{
|
||||
return NoOpMeasureMetric<double>.Instance;
|
||||
return this.realMeter != null ? this.realMeter.CreateDoubleMeasure(name, absolute) : NoOpMeasureMetric<double>.Instance;
|
||||
}
|
||||
|
||||
public override DoubleObserverMetric CreateDoubleObserver(string name, Action<DoubleObserverMetric> callback, bool absolute = true)
|
||||
{
|
||||
return NoOpDoubleObserverMetric.Instance;
|
||||
return this.realMeter != null ? this.realMeter.CreateDoubleObserver(name, callback, absolute) : NoOpDoubleObserverMetric.Instance;
|
||||
}
|
||||
|
||||
public override CounterMetric<long> CreateInt64Counter(string name, bool monotonic = true)
|
||||
{
|
||||
return NoOpCounterMetric<long>.Instance;
|
||||
return this.realMeter != null ? this.realMeter.CreateInt64Counter(name, monotonic) : NoOpCounterMetric<long>.Instance;
|
||||
}
|
||||
|
||||
public override MeasureMetric<long> CreateInt64Measure(string name, bool absolute = true)
|
||||
{
|
||||
return NoOpMeasureMetric<long>.Instance;
|
||||
return this.realMeter != null ? this.realMeter.CreateInt64Measure(name, absolute) : NoOpMeasureMetric<long>.Instance;
|
||||
}
|
||||
|
||||
public override Int64ObserverMetric CreateInt64Observer(string name, Action<Int64ObserverMetric> callback, bool absolute = true)
|
||||
{
|
||||
return NoOpInt64ObserverMetric.Instance;
|
||||
return this.realMeter != null ? this.realMeter.CreateInt64Observer(name, callback, absolute) : NoOpInt64ObserverMetric.Instance;
|
||||
}
|
||||
|
||||
public override LabelSet GetLabelSet(IEnumerable<KeyValuePair<string, string>> labels)
|
||||
{
|
||||
// return no op
|
||||
return LabelSet.BlankLabelSet;
|
||||
return this.realMeter != null ? this.realMeter.GetLabelSet(labels) : LabelSet.BlankLabelSet;
|
||||
}
|
||||
|
||||
public void UpdateMeter(Meter realMeter)
|
||||
{
|
||||
if (this.realMeter != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// just in case user calls init concurrently
|
||||
Interlocked.CompareExchange(ref this.realMeter, realMeter, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using OpenTelemetry.Metrics.Export;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
// <copyright file="MeterFactoryBaseTests.cs" company="OpenTelemetry Authors">
|
||||
// Copyright 2018, OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using OpenTelemetry.Metrics.Configuration;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Metrics.Config.Test
|
||||
{
|
||||
public class MeterFactoryBaseTests : IDisposable
|
||||
{
|
||||
public MeterFactoryBaseTests()
|
||||
{
|
||||
MeterFactoryBase.Default.Reset();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MeterFactory_Default()
|
||||
{
|
||||
Assert.NotNull(MeterFactoryBase.Default);
|
||||
var defaultMeter = MeterFactoryBase.Default.GetMeter("");
|
||||
Assert.NotNull(defaultMeter);
|
||||
Assert.Same(defaultMeter, MeterFactoryBase.Default.GetMeter("named meter"));
|
||||
|
||||
var counter = defaultMeter.CreateDoubleCounter("ctr");
|
||||
Assert.IsType<NoOpCounterMetric<double>>(counter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MeterFactory_SetDefault()
|
||||
{
|
||||
var factory = MeterFactory.Create(b => { });
|
||||
MeterFactoryBase.SetDefault(factory);
|
||||
|
||||
var defaultMeter = MeterFactoryBase.Default.GetMeter("");
|
||||
Assert.NotNull(defaultMeter);
|
||||
Assert.IsType<MeterSdk>(defaultMeter);
|
||||
|
||||
Assert.NotSame(defaultMeter, MeterFactoryBase.Default.GetMeter("named meter"));
|
||||
|
||||
var counter = defaultMeter.CreateDoubleCounter("ctr");
|
||||
Assert.IsType<DoubleCounterMetricSdk>(counter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MeterFactory_SetDefaultNull()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => MeterFactoryBase.SetDefault(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MeterFactory_SetDefaultTwice_Throws()
|
||||
{
|
||||
MeterFactoryBase.SetDefault(MeterFactory.Create(b => { }));
|
||||
Assert.Throws<InvalidOperationException>(() => MeterFactoryBase.SetDefault(MeterFactory.Create(b => { })));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MeterFactory_UpdateDefault_CachedTracer()
|
||||
{
|
||||
var defaultMeter = MeterFactoryBase.Default.GetMeter("");
|
||||
var noOpCounter = defaultMeter.CreateDoubleCounter("ctr");
|
||||
Assert.IsType<NoOpCounterMetric<double>>(noOpCounter);
|
||||
|
||||
MeterFactoryBase.SetDefault(MeterFactory.Create(b => { }));
|
||||
var counter = defaultMeter.CreateDoubleCounter("ctr");
|
||||
Assert.IsType<DoubleCounterMetricSdk>(counter);
|
||||
|
||||
var newdefaultMeter = MeterFactoryBase.Default.GetMeter("");
|
||||
Assert.NotSame(defaultMeter, newdefaultMeter);
|
||||
Assert.IsType<MeterSdk>(newdefaultMeter);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
MeterFactoryBase.Default.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
// <copyright file="MeterFactoryBaseTests.cs" company="OpenTelemetry Authors">
|
||||
// Copyright 2018, OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTelemetry.Metrics;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Tests.Impl.Trace.Config
|
||||
{
|
||||
public class MeterFactoryBaseTests
|
||||
{
|
||||
[Fact]
|
||||
public void MeterFactoryBase_Default()
|
||||
{
|
||||
Assert.NotNull(MeterFactoryBase.Default);
|
||||
var defaultMeter = MeterFactoryBase.Default.GetMeter("");
|
||||
Assert.NotNull(defaultMeter);
|
||||
Assert.IsType<NoOpMeter>(defaultMeter);
|
||||
|
||||
var namedMeter = MeterFactoryBase.Default.GetMeter("named meter");
|
||||
// The same NoOpMeter must be returned always.
|
||||
Assert.Same(defaultMeter, namedMeter);
|
||||
|
||||
var counter = defaultMeter.CreateDoubleCounter("somename");
|
||||
Assert.IsType<NoOpCounterMetric<double>>(counter);
|
||||
|
||||
var labels1 = new List<KeyValuePair<string, string>>();
|
||||
labels1.Add(new KeyValuePair<string, string>("dim1", "value1"));
|
||||
var counterBoundIntrument = counter.Bind(labels1);
|
||||
Assert.IsType<NoOpBoundCounterMetric<double>>(counterBoundIntrument);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue