Skip to content

Commit

Permalink
[otlp] UseOtlpExporter cross-cutting extension (#5400)
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeBlanch authored Mar 14, 2024
1 parent eb2dc44 commit a6a760f
Show file tree
Hide file tree
Showing 24 changed files with 1,679 additions and 303 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
OpenTelemetry.OpenTelemetryBuilderOtlpExporterExtensions
static OpenTelemetry.OpenTelemetryBuilderOtlpExporterExtensions.UseOtlpExporter(this OpenTelemetry.IOpenTelemetryBuilder! builder) -> OpenTelemetry.IOpenTelemetryBuilder!
static OpenTelemetry.OpenTelemetryBuilderOtlpExporterExtensions.UseOtlpExporter(this OpenTelemetry.IOpenTelemetryBuilder! builder, OpenTelemetry.Exporter.OtlpExportProtocol protocol, System.Uri! baseEndpoint) -> OpenTelemetry.IOpenTelemetryBuilder!
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#nullable enable

using Microsoft.Extensions.Configuration;
using OpenTelemetry.Exporter;
using OpenTelemetry.Internal;

namespace OpenTelemetry;

/// <summary>
/// Contains extension methods to facilitate registration of the OpenTelemetry
/// Protocol (OTLP) exporter into an <see cref="IOpenTelemetryBuilder"/>
/// instance.
/// </summary>
public static class OpenTelemetryBuilderOtlpExporterExtensions
{
/// <summary>
/// Uses OpenTelemetry Protocol (OTLP) exporter for all signals.
/// </summary>
/// <remarks>
/// Notes:
/// <list type="bullet">
/// <item>Calling this method automatically enables logging, metrics, and
/// tracing.</item>
/// <item>The exporter registered by this method will be added as the last
/// processor in the pipeline established for logging and tracing.</item>
/// <item>This method can only be called once. Subsequent calls will results
/// in a <see cref="NotSupportedException"/> being thrown.</item>
/// <item>This method cannot be called in addition to signal-specific
/// <c>AddOtlpExporter</c> methods. If this method is called signal-specific
/// <c>AddOtlpExporter</c> calls will result in a <see
/// cref="NotSupportedException"/> being thrown.</item>
/// </list>
/// </remarks>
/// <param name="builder"><see cref="IOpenTelemetryBuilder"/>.</param>
/// <returns>Supplied <see cref="IOpenTelemetryBuilder"/> for chaining calls.</returns>
public static IOpenTelemetryBuilder UseOtlpExporter(
this IOpenTelemetryBuilder builder)
=> UseOtlpExporter(builder, name: null, configuration: null, configure: null);

/// <summary><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)"/></summary>
/// <remarks><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)" path="/remarks"/></remarks>
/// <returns><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)" path="/returns"/></returns>
/// <param name="builder"><see cref="IOpenTelemetryBuilder"/>.</param>
/// <param name="protocol"><see cref="OtlpExportProtocol"/>.</param>
/// <param name="baseEndpoint">
/// <para>Base endpoint to use.</para>
/// Note: A signal-specific path will be appended to the base endpoint for
/// each signal automatically if the protocol is set to <see
/// cref="OtlpExportProtocol.HttpProtobuf"/>.
/// </param>
public static IOpenTelemetryBuilder UseOtlpExporter(
this IOpenTelemetryBuilder builder,
OtlpExportProtocol protocol,
Uri baseEndpoint)
{
Guard.ThrowIfNull(baseEndpoint);

return UseOtlpExporter(builder, name: null, configuration: null, configure: otlpBuilder =>
{
otlpBuilder.ConfigureDefaultExporterOptions(o =>
{
o.Protocol = protocol;
o.Endpoint = baseEndpoint;
});
});
}

/// <summary><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)"/></summary>
/// <remarks><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)" path="/remarks"/></remarks>
/// <returns><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)" path="/returns"/></returns>
/// <param name="builder"><see cref="IOpenTelemetryBuilder"/>.</param>
/// <param name="configure">Callback action for configuring <see cref="OtlpExporterBuilder"/>.</param>
internal static IOpenTelemetryBuilder UseOtlpExporter(
this IOpenTelemetryBuilder builder,
Action<OtlpExporterBuilder> configure)
{
Guard.ThrowIfNull(configure);

return UseOtlpExporter(builder, name: null, configuration: null, configure);
}

/// <summary><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)"/></summary>
/// <remarks><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)" path="/remarks"/></remarks>
/// <returns><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)" path="/returns"/></returns>
/// <param name="builder"><see cref="IOpenTelemetryBuilder"/>.</param>
/// <param name="configuration">
/// <para><see cref="IConfiguration"/> to bind onto <see cref="OtlpExporterBuilderOptions"/>.</para>
/// <para>Notes:
/// <list type="bullet">
/// <item docLink="true">See [TODO:Add doc link] for details on the configuration
/// schema.</item>
/// <item>The <see cref="OtlpExporterBuilderOptions"/> instance will be
/// named "otlp" by default when calling this method.</item>
/// </list>
/// </para>
/// </param>
internal static IOpenTelemetryBuilder UseOtlpExporter(
this IOpenTelemetryBuilder builder,
IConfiguration configuration)
{
Guard.ThrowIfNull(configuration);

return UseOtlpExporter(builder, name: null, configuration, configure: null);
}

/// <summary><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)"/></summary>
/// <remarks><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)" path="/remarks"/></remarks>
/// <returns><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder)" path="/returns"/></returns>
/// <param name="builder"><see cref="IOpenTelemetryBuilder"/>.</param>
/// <param name="name">Optional name which is used when retrieving options.</param>
/// <param name="configuration">
/// <para>Optional <see cref="IConfiguration"/> to bind onto <see
/// cref="OtlpExporterBuilderOptions"/>.</para>
/// <para>Notes:
/// <list type="bullet">
/// <item><inheritdoc cref="UseOtlpExporter(IOpenTelemetryBuilder,
/// IConfiguration)"
/// path="/param[@name='configuration']/para/list/item[@docLink='true']"/></item>
/// <item>If <paramref name="name"/> is not set the <see
/// cref="OtlpExporterBuilderOptions"/> instance will be named "otlp" by
/// default when <paramref name="configuration"/> is used.</item>
/// </list>
/// </para>
/// </param>
/// <param name="configure">Optional callback action for configuring <see cref="OtlpExporterBuilder"/>.</param>
internal static IOpenTelemetryBuilder UseOtlpExporter(
this IOpenTelemetryBuilder builder,
string? name,
IConfiguration? configuration,
Action<OtlpExporterBuilder>? configure)
{
Guard.ThrowIfNull(builder);

// Note: We automatically turn on signals for "UseOtlpExporter"
builder
.WithLogging()
.WithMetrics()
.WithTracing();

var otlpBuilder = new OtlpExporterBuilder(builder.Services, name, configuration);

configure?.Invoke(otlpBuilder);

return builder;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using Microsoft.Extensions.DependencyInjection;

namespace OpenTelemetry.Exporter;

internal static class OpenTelemetryBuilderServiceProviderExtensions
{
public static void EnsureSingleUseOtlpExporterRegistration(this IServiceProvider serviceProvider)
{
var registrations = serviceProvider.GetServices<UseOtlpExporterRegistration>();
if (registrations.Count() > 1)
{
throw new NotSupportedException("Multiple calls to UseOtlpExporter on the same IServiceCollection are not supported.");
}
}

public static void EnsureNoUseOtlpExporterRegistrations(this IServiceProvider serviceProvider)
{
var registrations = serviceProvider.GetServices<UseOtlpExporterRegistration>();
if (registrations.Any())
{
throw new NotSupportedException("Signal-specific AddOtlpExporter methods and the cross-cutting UseOtlpExporter method being invoked on the same IServiceCollection is not supported.");
}
}
}
Loading

0 comments on commit a6a760f

Please sign in to comment.