diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln index 1e214bee3cb..94fc0021654 100644 --- a/OpenTelemetry.sln +++ b/OpenTelemetry.sln @@ -196,6 +196,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentati EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples.GrpcService", "examples\GrpcService\Examples.GrpcService.csproj", "{DB942F5A-D571-4DEA-B1A7-B6BE0E24E6ED}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started", "docs\logs\getting-started\getting-started.csproj", "{B3F03725-23A0-4582-9526-F6A7E38F35CC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -378,6 +380,10 @@ Global {DB942F5A-D571-4DEA-B1A7-B6BE0E24E6ED}.Debug|Any CPU.Build.0 = Debug|Any CPU {DB942F5A-D571-4DEA-B1A7-B6BE0E24E6ED}.Release|Any CPU.ActiveCfg = Release|Any CPU {DB942F5A-D571-4DEA-B1A7-B6BE0E24E6ED}.Release|Any CPU.Build.0 = Release|Any CPU + {B3F03725-23A0-4582-9526-F6A7E38F35CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B3F03725-23A0-4582-9526-F6A7E38F35CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3F03725-23A0-4582-9526-F6A7E38F35CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B3F03725-23A0-4582-9526-F6A7E38F35CC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -406,6 +412,7 @@ Global {FCDCF532-A163-40DA-80B7-7530AA1182C4} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818} {B26BE278-C9DA-4067-A0EE-6A4227B3DC87} = {3862190B-E2C5-418E-AFDC-DB281FB5C705} {DB942F5A-D571-4DEA-B1A7-B6BE0E24E6ED} = {E359BB2B-9AEC-497D-B321-7DF2450C3B8E} + {B3F03725-23A0-4582-9526-F6A7E38F35CC} = {3862190B-E2C5-418E-AFDC-DB281FB5C705} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521} diff --git a/build/Common.props b/build/Common.props index 3a72e340d98..fbea8bc8cd9 100644 --- a/build/Common.props +++ b/build/Common.props @@ -31,6 +31,8 @@ [3.3.0] [16.7.1] [2.1.0,5.0) + [2.1.0,6.0) + [2.1.0,6.0) [1.0.0,2.0) [1.0.0,2.0) [12.0.2,13.0) diff --git a/docs/Directory.Build.props b/docs/Directory.Build.props index 36cb1aa1b19..8ce176a76ef 100644 --- a/docs/Directory.Build.props +++ b/docs/Directory.Build.props @@ -11,6 +11,7 @@ Please sort alphabetically. Refer to https://docs.microsoft.com/en-us/nuget/concepts/package-versioning for semver syntax. --> + [5.0.0-rc.1.20451.14,6.0) [0.4.0-beta.2,1.0) [0.4.0-beta.2,1.0) diff --git a/docs/logs/getting-started/Program.cs b/docs/logs/getting-started/Program.cs new file mode 100644 index 00000000000..65b5142b2ff --- /dev/null +++ b/docs/logs/getting-started/Program.cs @@ -0,0 +1,32 @@ +// +// 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. +// + +using Microsoft.Extensions.Logging; + +public class Program +{ + public static void Main() + { + using var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddOpenTelemetry(); + }); + var logger = loggerFactory.CreateLogger(); + + logger.LogInformation("Hello, World!"); + logger.LogInformation("Hello from {name} {price}.", "artichoke", 3.99); + } +} diff --git a/docs/logs/getting-started/README.md b/docs/logs/getting-started/README.md new file mode 100644 index 00000000000..6941cf47115 --- /dev/null +++ b/docs/logs/getting-started/README.md @@ -0,0 +1,3 @@ +# Getting Started with OpenTelemetry .NET in 5 Minutes + +TBD diff --git a/docs/logs/getting-started/getting-started.csproj b/docs/logs/getting-started/getting-started.csproj new file mode 100644 index 00000000000..fed46f5b594 --- /dev/null +++ b/docs/logs/getting-started/getting-started.csproj @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index 0575e5078d5..823e7c21b8f 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Added `ILogger`/`Microsoft.Extensions.Logging` integration + ([#1308](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1308)) + ## 0.6.0-beta.1 Released 2020-Sep-15 diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLogger.cs b/src/OpenTelemetry/Logs/OpenTelemetryLogger.cs new file mode 100644 index 00000000000..1f3fd82f9ea --- /dev/null +++ b/src/OpenTelemetry/Logs/OpenTelemetryLogger.cs @@ -0,0 +1,93 @@ +// +// 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. +// + +#if NETSTANDARD2_0 +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.Extensions.Logging; + +namespace OpenTelemetry.Logs +{ + internal class OpenTelemetryLogger : ILogger + { + private readonly string categoryName; + + internal OpenTelemetryLogger(string categoryName, OpenTelemetryLoggerOptions options) + { + this.categoryName = categoryName ?? throw new ArgumentNullException(nameof(categoryName)); + + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + } + + internal IExternalScopeProvider ScopeProvider { get; set; } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (!this.IsEnabled(logLevel)) + { + return; + } + + var timestamp = DateTime.UtcNow; + + if (state is IReadOnlyCollection> dict) + { + var isUnstructuredLog = dict.Count == 1; + + // TODO: remove the console output after finished the plumbing work to log processors/exporters + if (isUnstructuredLog) + { + foreach (var entry in dict) + { + Console.WriteLine($"{this.categoryName}({logLevel}, Id={eventId}): {entry.Value}"); + } + } + else + { + Console.WriteLine($"{this.categoryName}({logLevel}, Id={eventId}):"); + foreach (var entry in dict) + { + if (string.Equals(entry.Key, "{OriginalFormat}", StringComparison.Ordinal)) + { + Console.WriteLine($" $format: {entry.Value}"); + continue; + } + + Console.WriteLine($" {entry.Key}: {entry.Value}"); + } + } + + if (exception != null) + { + Console.WriteLine($" $exception: {exception}"); + } + } + } + + public bool IsEnabled(LogLevel logLevel) + { + return logLevel != LogLevel.None; + } + + public IDisposable BeginScope(TState state) => this.ScopeProvider?.Push(state) ?? null; + } +} +#endif diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggerOptions.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggerOptions.cs new file mode 100644 index 00000000000..f44baf424f2 --- /dev/null +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggerOptions.cs @@ -0,0 +1,26 @@ +// +// 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. +// + +#if NETSTANDARD2_0 +using Microsoft.Extensions.Logging; + +namespace OpenTelemetry.Logs +{ + public class OpenTelemetryLoggerOptions + { + } +} +#endif diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs new file mode 100644 index 00000000000..66aae355095 --- /dev/null +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs @@ -0,0 +1,79 @@ +// +// 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. +// + +#if NETSTANDARD2_0 +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace OpenTelemetry.Logs +{ + [ProviderAlias("OpenTelemetry")] + public class OpenTelemetryLoggerProvider : ILoggerProvider, ISupportExternalScope + { + private readonly IOptionsMonitor options; + private readonly IDictionary loggers; + private IExternalScopeProvider scopeProvider; + + public OpenTelemetryLoggerProvider(IOptionsMonitor options) + { + this.options = options; + this.loggers = new Dictionary(StringComparer.Ordinal); + } + + internal IExternalScopeProvider ScopeProvider + { + get + { + if (this.scopeProvider == null) + { + this.scopeProvider = new LoggerExternalScopeProvider(); + } + + return this.scopeProvider; + } + } + + void ISupportExternalScope.SetScopeProvider(IExternalScopeProvider scopeProvider) + { + // TODO: set existing loggers + this.scopeProvider = scopeProvider; + } + + public ILogger CreateLogger(string categoryName) + { + lock (this.loggers) + { + ILogger logger; + + if (this.loggers.TryGetValue(categoryName, out logger)) + { + return logger; + } + + logger = new OpenTelemetryLogger(categoryName, this.options.CurrentValue); + this.loggers.Add(categoryName, logger); + return logger; + } + } + + public void Dispose() + { + } + } +} +#endif diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs new file mode 100644 index 00000000000..bc44746b855 --- /dev/null +++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggingExtensions.cs @@ -0,0 +1,48 @@ +// +// 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. +// + +#if NETSTANDARD2_0 +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Configuration; +using OpenTelemetry.Logs; + +namespace Microsoft.Extensions.Logging +{ + public static class OpenTelemetryLoggingExtensions + { + public static ILoggingBuilder AddOpenTelemetry(this ILoggingBuilder builder, Action configure = null) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + builder.AddConfiguration(); + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); + + if (configure != null) + { + builder.Services.Configure(configure); + } + + return builder; + } + } +} +#endif diff --git a/src/OpenTelemetry/OpenTelemetry.csproj b/src/OpenTelemetry/OpenTelemetry.csproj index 7089e30f320..05f4a7c9bb5 100644 --- a/src/OpenTelemetry/OpenTelemetry.csproj +++ b/src/OpenTelemetry/OpenTelemetry.csproj @@ -18,6 +18,11 @@ + + + + +