Skip to content

Commit

Permalink
[sdk-logs] Add LoggerProviderServiceCollectionBuilder to SDK (#4441)
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeBlanch authored Apr 26, 2023
1 parent 39314f8 commit e195dd8
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ namespace Microsoft.Extensions.DependencyInjection;

internal static class ProviderBuilderServiceCollectionExtensions
{
public static IServiceCollection AddOpenTelemetryLoggerProviderBuilderServices(this IServiceCollection services)
{
Debug.Assert(services != null, "services was null");

// TODO:
// services!.TryAddSingleton<LoggerProviderBuilderSdk>();
// services!.RegisterOptionsFactory(configuration => new BatchExportLogRecordProcessorOptions(configuration));

return services!;
}

public static IServiceCollection AddOpenTelemetryMeterProviderBuilderServices(this IServiceCollection services)
{
Debug.Assert(services != null, "services was null");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// <copyright file="LoggerProviderServiceCollectionBuilder.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>

#nullable enable

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OpenTelemetry.Internal;

namespace OpenTelemetry.Logs;

/// <summary>
/// Contains methods for registering actions into an <see
/// cref="IServiceCollection"/> which will be used to build a <see
/// cref="LoggerProvider"/> once the <see cref="IServiceProvider"/> is
/// available.
/// </summary>
internal sealed class LoggerProviderServiceCollectionBuilder : LoggerProviderBuilder, ILoggerProviderBuilder
{
private readonly bool allowBuild;
private IServiceCollection? services;

/// <summary>
/// Initializes a new instance of the <see cref="LoggerProviderServiceCollectionBuilder"/> class.
/// </summary>
public LoggerProviderServiceCollectionBuilder()
{
var services = new ServiceCollection();

services
.AddOpenTelemetrySharedProviderBuilderServices()
.AddOpenTelemetryLoggerProviderBuilderServices()
.TryAddSingleton<LoggerProvider>(
sp => throw new NotSupportedException("Self-contained LoggerProvider cannot be accessed using the application IServiceProvider call Build instead."));

services.ConfigureOpenTelemetryLoggerProvider((sp, builder) => this.services = null);

this.services = services;

this.allowBuild = true;
}

internal LoggerProviderServiceCollectionBuilder(IServiceCollection services)
{
Guard.ThrowIfNull(services);

services
.AddOpenTelemetryLoggerProviderBuilderServices()
.TryAddSingleton<LoggerProvider>(sp => new LoggerProviderSdk(sp, ownsServiceProvider: false));

services.ConfigureOpenTelemetryLoggerProvider((sp, builder) => this.services = null);

this.services = services;

this.allowBuild = false;
}

/// <inheritdoc />
LoggerProvider? ILoggerProviderBuilder.Provider => null;

/// <inheritdoc />
public override LoggerProviderBuilder AddInstrumentation<TInstrumentation>(Func<TInstrumentation> instrumentationFactory)
{
Guard.ThrowIfNull(instrumentationFactory);

this.ConfigureBuilderInternal((sp, builder) =>
{
builder.AddInstrumentation(instrumentationFactory);
});

return this;
}

/// <inheritdoc />
LoggerProviderBuilder ILoggerProviderBuilder.ConfigureServices(Action<IServiceCollection> configure)
=> this.ConfigureServicesInternal(configure);

/// <inheritdoc />
LoggerProviderBuilder IDeferredLoggerProviderBuilder.Configure(Action<IServiceProvider, LoggerProviderBuilder> configure)
=> this.ConfigureBuilderInternal(configure);

internal LoggerProvider Build()
{
if (!this.allowBuild)
{
throw new NotSupportedException("A LoggerProviderBuilder bound to external service cannot be built directly. Access the LoggerProvider using the application IServiceProvider instead.");
}

var services = this.services
?? throw new NotSupportedException("LoggerProviderBuilder build method cannot be called multiple times.");

this.services = null;

#if DEBUG
bool validateScopes = true;
#else
bool validateScopes = false;
#endif
var serviceProvider = services.BuildServiceProvider(validateScopes);

return new LoggerProviderSdk(serviceProvider, ownsServiceProvider: true);
}

private LoggerProviderBuilder ConfigureBuilderInternal(Action<IServiceProvider, LoggerProviderBuilder> configure)
{
var services = this.services
?? throw new NotSupportedException("Builder cannot be configured during LoggerProvider construction.");

services.ConfigureOpenTelemetryLoggerProvider(configure);

return this;
}

private LoggerProviderBuilder ConfigureServicesInternal(Action<IServiceCollection> configure)
{
Guard.ThrowIfNull(configure);

var services = this.services
?? throw new NotSupportedException("Services cannot be configured during LoggerProvider construction.");

configure(services);

return this;
}
}
29 changes: 29 additions & 0 deletions src/OpenTelemetry/Logs/LoggerProviderSdk.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// <copyright file="LoggerProviderSdk.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>

#nullable enable

namespace OpenTelemetry.Logs;

internal sealed class LoggerProviderSdk : LoggerProvider
{
public LoggerProviderSdk(
IServiceProvider serviceProvider,
bool ownsServiceProvider)
{
throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public void EnsureAotCompatibility()
Assert.True(process.ExitCode == 0, "Publishing the AotCompatibility app failed. See test output for more details.");

var warnings = expectedOutput.ToString().Split('\n', '\r').Where(line => line.Contains("warning IL"));
Assert.Equal(77, warnings.Count());
Assert.Equal(78, warnings.Count());
}
}
}

0 comments on commit e195dd8

Please sign in to comment.