Skip to content

Commit

Permalink
Support question mark in wildcard (#2875)
Browse files Browse the repository at this point in the history
  • Loading branch information
reyang authored Feb 10, 2022
1 parent 7826269 commit 1b5765b
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 37 deletions.
4 changes: 4 additions & 0 deletions src/OpenTelemetry.Api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

* Improved wildcard support for `AddSource`, `AddMeter` to cover `?` (which
matches exactly one character).
([#2875](https://github.com/open-telemetry/opentelemetry-dotnet/pull/2875))

## 1.2.0-rc2

Released 2022-Feb-02
Expand Down
47 changes: 47 additions & 0 deletions src/OpenTelemetry/Internal/WildcardHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// <copyright file="WildcardHelper.cs" company="OpenTelemetry Authors">
// Copyright The 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.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace OpenTelemetry;

internal static class WildcardHelper
{
public static bool ContainsWildcard(string value)
{
if (value == null)
{
return false;
}

return value.Contains('*') || value.Contains('?');
}

public static Regex GetWildcardRegex(IEnumerable<string> patterns = default)
{
if (patterns == null)
{
return null;
}

var convertedPattern = string.Join(
"|",
from p in patterns select "(?:" + Regex.Escape(p).Replace("\\*", ".*").Replace("\\?", ".") + ')');
return new Regex('^' + convertedPattern + '$', RegexOptions.Compiled | RegexOptions.IgnoreCase);
}
}
11 changes: 2 additions & 9 deletions src/OpenTelemetry/Metrics/MeterProviderSdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Text.RegularExpressions;
using OpenTelemetry.Internal;
using OpenTelemetry.Resources;

Expand Down Expand Up @@ -82,9 +81,9 @@ internal MeterProviderSdk(

// Setup Listener
Func<Instrument, bool> shouldListenTo = instrument => false;
if (meterSources.Any(s => s.Contains('*')))
if (meterSources.Any(s => WildcardHelper.ContainsWildcard(s)))
{
var regex = GetWildcardRegex(meterSources);
var regex = WildcardHelper.GetWildcardRegex(meterSources);
shouldListenTo = instrument => regex.IsMatch(instrument.Meter.Name);
}
else if (meterSources.Any())
Expand Down Expand Up @@ -235,12 +234,6 @@ internal MeterProviderSdk(
}

this.listener.Start();

static Regex GetWildcardRegex(IEnumerable<string> collection)
{
var pattern = '^' + string.Join("|", from name in collection select "(?:" + Regex.Escape(name).Replace("\\*", ".*") + ')') + '$';
return new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
}
}

internal Resource Resource { get; }
Expand Down
35 changes: 8 additions & 27 deletions src/OpenTelemetry/Trace/TracerProviderSdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using OpenTelemetry.Internal;
using OpenTelemetry.Resources;

Expand Down Expand Up @@ -50,13 +49,13 @@ internal TracerProviderSdk(
this.supportLegacyActivity = legacyActivityOperationNames.Count > 0;

bool legacyActivityWildcardMode = false;
Regex legacyActivityWildcardModeRegex = null;
var legacyActivityWildcardModeRegex = WildcardHelper.GetWildcardRegex();
foreach (var legacyName in legacyActivityOperationNames)
{
if (legacyName.Contains('*'))
if (WildcardHelper.ContainsWildcard(legacyName))
{
legacyActivityWildcardMode = true;
legacyActivityWildcardModeRegex = GetWildcardRegex(legacyActivityOperationNames);
legacyActivityWildcardModeRegex = WildcardHelper.GetWildcardRegex(legacyActivityOperationNames);
break;
}
}
Expand Down Expand Up @@ -211,27 +210,15 @@ internal TracerProviderSdk(
this.getRequestedDataAction = this.RunGetRequestedDataOtherSampler;
}

// Sources can be null. This happens when user
// is only interested in InstrumentationLibraries
// which do not depend on ActivitySources.
if (sources.Any())
{
// Sources can be null. This happens when user
// is only interested in InstrumentationLibraries
// which do not depend on ActivitySources.

var wildcardMode = false;

// Validation of source name is already done in builder.
foreach (var name in sources)
{
if (name.Contains('*'))
{
wildcardMode = true;
break;
}
}

if (wildcardMode)
if (sources.Any(s => WildcardHelper.ContainsWildcard(s)))
{
var regex = GetWildcardRegex(sources);
var regex = WildcardHelper.GetWildcardRegex(sources);

// Function which takes ActivitySource and returns true/false to indicate if it should be subscribed to
// or not.
Expand Down Expand Up @@ -264,12 +251,6 @@ internal TracerProviderSdk(

ActivitySource.AddActivityListener(listener);
this.listener = listener;

Regex GetWildcardRegex(IEnumerable<string> collection)
{
var pattern = '^' + string.Join("|", from name in collection select "(?:" + Regex.Escape(name).Replace("\\*", ".*") + ')') + '$';
return new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
}
}

internal Resource Resource { get; }
Expand Down
2 changes: 1 addition & 1 deletion test/OpenTelemetry.Tests/Metrics/MetricAPITest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public void MeterSourcesWildcardSupportMatchTest(bool hasView)

var exportedItems = new List<Metric>();
var meterProviderBuilder = Sdk.CreateMeterProviderBuilder()
.AddMeter("AbcCompany.XyzProduct.*")
.AddMeter("AbcCompany.XyzProduct.Component?")
.AddMeter("DefCompany.*.ComponentC")
.AddMeter("GhiCompany.qweProduct.ComponentN") // Mixing of non-wildcard meter name and wildcard meter name.
.AddInMemoryExporter(exportedItems);
Expand Down
80 changes: 80 additions & 0 deletions test/OpenTelemetry.Tests/Trace/TracerProviderSdkTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,86 @@ public TracerProviderSdkTest()
Activity.DefaultIdFormat = ActivityIdFormat.W3C;
}

[Fact]
public void TracerProviderSdkAddSource()
{
using var source1 = new ActivitySource($"{Utils.GetCurrentMethodName()}.1");
using var source2 = new ActivitySource($"{Utils.GetCurrentMethodName()}.2");

using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource(source1.Name)
.Build();

using (var activity = source1.StartActivity("test"))
{
Assert.NotNull(activity);
}

using (var activity = source2.StartActivity("test"))
{
Assert.Null(activity);
}
}

[Fact]
public void TracerProviderSdkAddSourceWithWildcards()
{
using var source1 = new ActivitySource($"{Utils.GetCurrentMethodName()}.A");
using var source2 = new ActivitySource($"{Utils.GetCurrentMethodName()}.Ab");
using var source3 = new ActivitySource($"{Utils.GetCurrentMethodName()}.Abc");
using var source4 = new ActivitySource($"{Utils.GetCurrentMethodName()}.B");

using (var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource($"{Utils.GetCurrentMethodName()}.*")
.Build())
{
using (var activity = source1.StartActivity("test"))
{
Assert.NotNull(activity);
}

using (var activity = source2.StartActivity("test"))
{
Assert.NotNull(activity);
}

using (var activity = source3.StartActivity("test"))
{
Assert.NotNull(activity);
}

using (var activity = source4.StartActivity("test"))
{
Assert.NotNull(activity);
}
}

using (var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource($"{Utils.GetCurrentMethodName()}.?")
.Build())
{
using (var activity = source1.StartActivity("test"))
{
Assert.NotNull(activity);
}

using (var activity = source2.StartActivity("test"))
{
Assert.Null(activity);
}

using (var activity = source3.StartActivity("test"))
{
Assert.Null(activity);
}

using (var activity = source4.StartActivity("test"))
{
Assert.NotNull(activity);
}
}
}

[Fact]
public void TracerProviderSdkInvokesSamplingWithCorrectParameters()
{
Expand Down

0 comments on commit 1b5765b

Please sign in to comment.