Add Logs support for ASP.NET Core apps (#1133)

* Add OpenTelemetry Logs

* Remove commented code

* Rename OpenTelemetry.AutoInstrumentation.StartupBootstrapper to OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper.

* PR feedback

* PR feedback
This commit is contained in:
Rajkumar Rangaraj 2022-08-30 09:59:14 -07:00 committed by GitHub
parent 879cb17326
commit aa32666cb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 319 additions and 4 deletions

View File

@ -135,6 +135,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApplication.StackExchan
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApplication.GrpcNetClient", "test\test-applications\integrations\TestApplication.GrpcNetClient\TestApplication.GrpcNetClient.csproj", "{0605872C-AB2B-4167-9B00-A525090D10BE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper", "src\OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper\OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper.csproj", "{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -571,6 +573,18 @@ Global
{0605872C-AB2B-4167-9B00-A525090D10BE}.Release|x64.Build.0 = Release|x64
{0605872C-AB2B-4167-9B00-A525090D10BE}.Release|x86.ActiveCfg = Release|x86
{0605872C-AB2B-4167-9B00-A525090D10BE}.Release|x86.Build.0 = Release|x86
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Debug|x64.ActiveCfg = Debug|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Debug|x64.Build.0 = Debug|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Debug|x86.ActiveCfg = Debug|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Debug|x86.Build.0 = Debug|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Release|Any CPU.Build.0 = Release|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Release|x64.ActiveCfg = Release|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Release|x64.Build.0 = Release|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Release|x86.ActiveCfg = Release|Any CPU
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -617,6 +631,7 @@ Global
{E7C2D2CF-C965-449D-A02C-02F7837D0C6D} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{671EB8F0-E164-4E9F-B423-27AF4B59D360} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{0605872C-AB2B-4167-9B00-A525090D10BE} = {E409ADD3-9574-465C-AB09-4324D205CC7C}
{C1AEDAE0-6629-4C88-AB35-AB5B81FD50F6} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}

View File

@ -205,6 +205,15 @@ partial class Build
.EnableNoRestore()
.SetFramework(TargetFramework.NETCOREAPP3_1)
.SetOutput(TracerHomeDirectory / TargetFramework.NETCOREAPP3_1));
DotNetPublish(s => s
.SetProject(Solution.GetProject(Projects.AutoInstrumentationAspNetCoreBootstrapper))
.SetConfiguration(BuildConfiguration)
.SetTargetPlatformAnyCPU()
.EnableNoBuild()
.EnableNoRestore()
.SetFramework(TargetFramework.NETCOREAPP3_1)
.SetOutput(TracerHomeDirectory / TargetFramework.NETCOREAPP3_1));
});
Target PublishNativeProfiler => _ => _

View File

@ -5,6 +5,7 @@ public static class Projects
public const string AutoInstrumentationNative = "OpenTelemetry.AutoInstrumentation.Native";
public const string AutoInstrumentationStartupHook = "OpenTelemetry.AutoInstrumentation.StartupHook";
public const string AutoInstrumentationAdditionalDeps = "OpenTelemetry.AutoInstrumentation.AdditionalDeps";
public const string AutoInstrumentationAspNetCoreBootstrapper = "OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper";
public static class Tests
{

View File

@ -19,7 +19,11 @@
"OTEL_DOTNET_AUTO_TRACES_CONSOLE_EXPORTER_ENABLED": "true",
"OTEL_DOTNET_AUTO_TRACES_PLUGINS": "Examples.AspNetCoreMvc.OtelSdkPlugin, Examples.AspNetCoreMvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"OTEL_SERVICE_NAME": "StartupHook.IISExpress",
"OTEL_TRACES_EXPORTER": "otlp"
"OTEL_TRACES_EXPORTER": "otlp",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper",
"OTEL_DOTNET_AUTO_LOGS_CONSOLE_EXPORTER_ENABLED": "true",
"OTEL_DOTNET_AUTO_LOGS_PARSE_STATE_VALUES": "true",
"OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE": "true"
},
"use64Bit": true,
"nativeDebugging": true
@ -55,7 +59,12 @@
"OTEL_DOTNET_AUTO_TRACES_CONSOLE_EXPORTER_ENABLED": "true",
"OTEL_DOTNET_AUTO_TRACES_PLUGINS": "Examples.AspNetCoreMvc.OtelSdkPlugin, Examples.AspNetCoreMvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"OTEL_SERVICE_NAME": "StartupHook.Self-hosted",
"OTEL_TRACES_EXPORTER": "otlp"
"OTEL_TRACES_EXPORTER": "otlp",
"OTEL_DOTNET_AUTO_HOME": "$(SolutionDir)bin\\tracer-home",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper",
"OTEL_DOTNET_AUTO_LOGS_CONSOLE_EXPORTER_ENABLED": "true",
"OTEL_DOTNET_AUTO_LOGS_PARSE_STATE_VALUES": "true",
"OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE": "true"
},
"use64Bit": true,
"nativeDebugging": true,

View File

@ -0,0 +1,85 @@
// <copyright file="BootstrapperHostingStartup.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;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
using OpenTelemetry.AutoInstrumentation.Configuration;
using OpenTelemetry.Logs;
[assembly: HostingStartup(typeof(OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper.BootstrapperHostingStartup))]
namespace OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper;
/// <summary>
/// Add summary.
/// </summary>
public class BootstrapperHostingStartup : IHostingStartup
{
private readonly LogSettings settings;
/// <summary>
/// Initializes a new instance of the <see cref="BootstrapperHostingStartup"/> class.
/// </summary>
public BootstrapperHostingStartup()
{
settings = LogSettings.FromDefaultSources();
}
/// <summary>
/// This method gets called by the runtime to lightup ASP.NET Core OpenTelemetry Logs Collection.
/// </summary>
/// <param name="builder">The <see cref="IWebHostBuilder"/>.</param>
public void Configure(IWebHostBuilder builder)
{
builder.ConfigureLogging(logging => logging.AddOpenTelemetry(options =>
{
if (settings.ConsoleExporterEnabled)
{
options.AddConsoleExporter();
}
switch (settings.LogExporter)
{
case LogExporter.Otlp:
#if NETCOREAPP3_1
if (settings.Http2UnencryptedSupportEnabled)
{
// Adding the OtlpExporter creates a GrpcChannel.
// This switch must be set before creating a GrpcChannel/HttpClient when calling an insecure gRPC service.
// See: https://docs.microsoft.com/aspnet/core/grpc/troubleshoot#call-insecure-grpc-services-with-net-core-client
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
}
#endif
options.AddOtlpExporter(options =>
{
if (settings.OtlpExportProtocol.HasValue)
{
options.Protocol = settings.OtlpExportProtocol.Value;
}
});
break;
case LogExporter.None:
break;
default:
throw new ArgumentOutOfRangeException($"Traces exporter '{settings.LogExporter}' is incorrect");
}
options.ParseStateValues = settings.ParseStateValues;
options.IncludeFormattedMessage = settings.IncludeFormattedMessage;
}));
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.3.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs" Version="1.3.0-rc.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenTelemetry.AutoInstrumentation\OpenTelemetry.AutoInstrumentation.csproj" />
</ItemGroup>
</Project>

View File

@ -16,6 +16,7 @@
using System.Diagnostics;
using System.Diagnostics.Metrics;
using OpenTelemetry.Logs;
namespace OpenTelemetry.AutoInstrumentation.Configuration;
@ -51,7 +52,7 @@ public class ConfigurationKeys
public const string FlushOnUnhandledException = "OTEL_DOTNET_AUTO_FLUSH_ON_UNHANDLEDEXCEPTION";
/// <summary>
/// Configuration keys for trace exporter
/// Configuration keys for traces.
/// </summary>
public static class Traces
{
@ -98,7 +99,7 @@ public class ConfigurationKeys
}
/// <summary>
/// Configuration keys for metrics exporter
/// Configuration keys for metrics.
/// </summary>
public static class Metrics
{
@ -144,6 +145,40 @@ public class ConfigurationKeys
public const string AdditionalSources = "OTEL_DOTNET_AUTO_METRICS_ADDITIONAL_SOURCES";
}
/// <summary>
/// Configuration keys for logs.
/// </summary>
public static class Logs
{
/// <summary>
/// Configuration key for the logs exporter to be used.
/// Default is <c>"otlp"</c>.
/// </summary>
public const string Exporter = "OTEL_LOGS_EXPORTER";
/// <summary>
/// Configuration key for whether the logs console exporter is enabled.
/// </summary>
public const string ConsoleExporterEnabled = "OTEL_DOTNET_AUTO_LOGS_CONSOLE_EXPORTER_ENABLED";
/// <summary>
/// Configuration key for whether or not log state should be parsed into
/// <see cref="LogRecord.StateValues"/> on generated <see cref="LogRecord"/>s.
/// </summary>
public const string ParseStateValues = "OTEL_DOTNET_AUTO_LOGS_PARSE_STATE_VALUES";
/// <summary>
/// Configuration key for whether or not formatted log message
/// should be included on generated <see cref="LogRecord"/>s.
/// </summary>
public const string IncludeFormattedMessage = "OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE";
/// <summary>
/// Configuration key for colon (:) separated list of logs plugins represented by <see cref="System.Type.AssemblyQualifiedName"/>.
/// </summary>
public const string ProviderPlugins = "OTEL_DOTNET_AUTO_LOGS_PLUGINS";
}
/// <summary>
/// Configuration keys for Sdk
/// </summary>

View File

@ -0,0 +1,33 @@
// <copyright file="LogExporter.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>
namespace OpenTelemetry.AutoInstrumentation.Configuration;
/// <summary>
/// Enum representing supported log exporters.
/// </summary>
public enum LogExporter
{
/// <summary>
/// None exporter.
/// </summary>
None,
/// <summary>
/// OTLP exporter.
/// </summary>
Otlp,
}

View File

@ -0,0 +1,107 @@
// <copyright file="LogSettings.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;
using System.Collections.Generic;
namespace OpenTelemetry.AutoInstrumentation.Configuration;
/// <summary>
/// Log Settings
/// </summary>
public class LogSettings : Settings
{
/// <summary>
/// Initializes a new instance of the <see cref="LogSettings"/> class
/// using the specified <see cref="IConfigurationSource"/> to initialize values.
/// </summary>
/// <param name="source">The <see cref="IConfigurationSource"/> to use when retrieving configuration values.</param>
private LogSettings(IConfigurationSource source)
: base(source)
{
LogExporter = ParseLogExporter(source);
ConsoleExporterEnabled = source.GetBool(ConfigurationKeys.Logs.ConsoleExporterEnabled) ?? false;
ParseStateValues = source.GetBool(ConfigurationKeys.Logs.ParseStateValues) ?? false;
IncludeFormattedMessage = source.GetBool(ConfigurationKeys.Logs.IncludeFormattedMessage) ?? false;
var providerPlugins = source.GetString(ConfigurationKeys.Logs.ProviderPlugins);
if (providerPlugins != null)
{
foreach (var pluginAssemblyQualifiedName in providerPlugins.Split(Constants.ConfigurationValues.DotNetQualifiedNameSeparator))
{
LogPlugins.Add(pluginAssemblyQualifiedName);
}
}
}
/// <summary>
/// Gets the logs exporter.
/// </summary>
public LogExporter LogExporter { get; }
/// <summary>
/// Gets a value indicating whether the ParseStateValues is enabled.
/// </summary>
public bool ParseStateValues { get; }
/// <summary>
/// Gets a value indicating whether the IncludeFormattedMessage is enabled.
/// </summary>
public bool IncludeFormattedMessage { get; }
/// <summary>
/// Gets a value indicating whether the console exporter is enabled.
/// </summary>
public bool ConsoleExporterEnabled { get; }
/// <summary>
/// Gets the list of plugins represented by <see cref="Type.AssemblyQualifiedName"/>.
/// </summary>
public IList<string> LogPlugins { get; } = new List<string>();
internal static LogSettings FromDefaultSources()
{
var configurationSource = new CompositeConfigurationSource
{
new EnvironmentConfigurationSource(),
#if NETFRAMEWORK
// on .NET Framework only, also read from app.config/web.config
new NameValueConfigurationSource(System.Configuration.ConfigurationManager.AppSettings)
#endif
};
return new LogSettings(configurationSource);
}
private static LogExporter ParseLogExporter(IConfigurationSource source)
{
var logExporterEnvVar = source.GetString(ConfigurationKeys.Logs.Exporter)
?? Constants.ConfigurationValues.Exporters.Otlp;
switch (logExporterEnvVar)
{
case null:
case "":
case Constants.ConfigurationValues.Exporters.Otlp:
return LogExporter.Otlp;
case Constants.ConfigurationValues.None:
return LogExporter.None;
default:
throw new FormatException($"Log exporter '{logExporterEnvVar}' is not supported");
}
}
}

View File

@ -16,5 +16,6 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper")]
[assembly: InternalsVisibleTo("OpenTelemetry.AutoInstrumentation.Tests")]
[assembly: InternalsVisibleTo("IntegrationTests")]