Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into pbsampler-nolinks
Browse files Browse the repository at this point in the history
  • Loading branch information
mbakalov committed Mar 6, 2021
2 parents 455c73f + af27e78 commit 255ddc7
Show file tree
Hide file tree
Showing 20 changed files with 779 additions and 45 deletions.
7 changes: 7 additions & 0 deletions OpenTelemetry.sln
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Shared", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp.AspNetCore.5.0", "test\TestApp.AspNetCore.5.0\TestApp.AspNetCore.5.0.csproj", "{972396A8-E35B-499C-9BA1-765E9B8822E1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "exception-handling", "docs\trace\exception-handling\exception-handling.csproj", "{08D29501-F0A3-468F-B18D-BD1821A72383}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -387,6 +389,10 @@ Global
{972396A8-E35B-499C-9BA1-765E9B8822E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{972396A8-E35B-499C-9BA1-765E9B8822E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{972396A8-E35B-499C-9BA1-765E9B8822E1}.Release|Any CPU.Build.0 = Release|Any CPU
{08D29501-F0A3-468F-B18D-BD1821A72383}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08D29501-F0A3-468F-B18D-BD1821A72383}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08D29501-F0A3-468F-B18D-BD1821A72383}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08D29501-F0A3-468F-B18D-BD1821A72383}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -416,6 +422,7 @@ Global
{B3F03725-23A0-4582-9526-F6A7E38F35CC} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
{13C10C9A-07E8-43EB-91F5-C2B116FBE0FC} = {3862190B-E2C5-418E-AFDC-DB281FB5C705}
{972396A8-E35B-499C-9BA1-765E9B8822E1} = {77C7929A-2EED-4AA6-8705-B5C443C8AA0F}
{08D29501-F0A3-468F-B18D-BD1821A72383} = {5B7FB835-3FFF-4BC2-99C5-A5B5FAE3C818}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521}
Expand Down
2 changes: 1 addition & 1 deletion docs/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<!-- https://dotnet.microsoft.com/download/dotnet-core -->
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>
<!-- https://dotnet.microsoft.com/download/dotnet-framework -->
<TargetFrameworks Condition="$(OS) == 'Windows_NT'">$(TargetFrameworks);net461;net462;net47;net471;net472;net48</TargetFrameworks>
</PropertyGroup>
Expand Down
53 changes: 53 additions & 0 deletions docs/trace/exception-handling/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// <copyright file="Program.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.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Trace;

public class Program
{
private static readonly ActivitySource MyActivitySource = new ActivitySource(
"MyCompany.MyProduct.MyLibrary");

public static void Main()
{
using var tracerProvider = Sdk.CreateTracerProviderBuilder(options =>
{
options.SetErrorStatusOnException = true;
})
.AddSource("MyCompany.MyProduct.MyLibrary")
.SetSampler(new AlwaysOnSampler())
.AddConsoleExporter()
.Build();

try
{
using (MyActivitySource.StartActivity("Foo"))
{
using (MyActivitySource.StartActivity("Bar"))
{
throw new Exception("Oops!");
}
}
}
catch (Exception)
{
// swallow the exception
}
}
}
115 changes: 115 additions & 0 deletions docs/trace/exception-handling/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Exception Handling

## User-handled Exception

The term `User-handled Exception` is used to describe exceptions that are
handled by the application.

While using `Activity` API, the common pattern would be:

```csharp
using (var activity = MyActivitySource.StartActivity("Foo"))
{
try
{
Func();
}
catch (SomeException ex)
{
activity?.SetStatus(Status.Error);
DoSomething();
}
catch (Exception)
{
activity?.SetStatus(Status.Error);
throw;
}
}
```

The above approach could become hard to manage if there are deeply nested
`Activity` objects, or there are activities created in a 3rd party library.

The following configuration will automatically detect exception and set the
activity status to `Error`:

```csharp
Sdk.CreateTracerProviderBuilder(options => {
options.SetErrorStatusOnException = true;
});
```

A complete example can be found [here](./Program.cs).

Note: this feature is platform dependent as it relies on
[System.Runtime.InteropServices.Marshal.GetExceptionPointers](https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.marshal.getexceptionpointers).

## Unhandled Exception

The term `Unhandled Exception` is used to describe exceptions that are not
handled by the application. When an unhandled exception happened, the behavior
will depend on the presence of a debugger:

* If there is no debugger, the exception will normally crash the process or
terminate the thread.
* If a debugger is attached, the debugger will be notified that an unhandled
exception happened.
* In case a postmortem debugger is configured, the postmortem debugger will be
activited and normally it will collect a crash dump.

It might be useful to automatically capture the unhandled exceptions, travel
through the unfinished activities and export them for troubleshooting. Here goes
one possible way of doing this:

**WARNING:** Use `AppDomain.UnhandledException` with caution. A throw in the
handler puts the process into an unrecoverable state.

<!-- markdownlint-disable MD013 -->
```csharp
using System;
using System.Diagnostics;
using OpenTelemetry;
using OpenTelemetry.Trace;

public class Program
{
private static readonly ActivitySource MyActivitySource = new ActivitySource("MyCompany.MyProduct.MyLibrary");

public static void Main()
{
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;

using var tracerProvider = Sdk.CreateTracerProviderBuilder(options =>
{
options.SetErrorStatusOnException = true;
})
.AddSource("MyCompany.MyProduct.MyLibrary")
.SetSampler(new AlwaysOnSampler())
.AddConsoleExporter()
.Build();

using (MyActivitySource.StartActivity("Foo"))
{
using (MyActivitySource.StartActivity("Bar"))
{
throw new Exception("Oops!");
}
}
}

private static void UnhandledExceptionHandler(object source, UnhandledExceptionEventArgs args)
{
var ex = (Exception)args.ExceptionObject;

var activity = Activity.Current;

while (activity != null)
{
activity.RecordException(ex);
activity.Dispose();
activity = activity.Parent;
}
}
}
```
<!-- markdownlint-enable MD013 -->
8 changes: 8 additions & 0 deletions docs/trace/exception-handling/exception-handling.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<!---
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="$(OpenTelemetryExporterConsolePkgVer)" />
-->
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Console\OpenTelemetry.Exporter.Console.csproj" />
</ItemGroup>
</Project>
5 changes: 5 additions & 0 deletions src/OpenTelemetry/.publicApi/net452/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
OpenTelemetry.Trace.ParentBasedSampler.ParentBasedSampler(OpenTelemetry.Trace.Sampler rootSampler, OpenTelemetry.Trace.Sampler remoteParentSampled = null, OpenTelemetry.Trace.Sampler remoteParentNotSampled = null, OpenTelemetry.Trace.Sampler localParentSampled = null, OpenTelemetry.Trace.Sampler localParentNotSampled = null) -> void
OpenTelemetry.Trace.TracerProviderOptions
OpenTelemetry.Trace.TracerProviderOptions.SetErrorStatusOnException.get -> bool
OpenTelemetry.Trace.TracerProviderOptions.SetErrorStatusOnException.set -> void
OpenTelemetry.Trace.TracerProviderOptions.TracerProviderOptions() -> void
static OpenTelemetry.Sdk.CreateTracerProviderBuilder(System.Action<OpenTelemetry.Trace.TracerProviderOptions> configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddLegacyActivity(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, string operationName) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderExtensions.ForceFlush(this OpenTelemetry.Trace.TracerProvider provider, int timeoutMilliseconds = -1) -> bool
5 changes: 5 additions & 0 deletions src/OpenTelemetry/.publicApi/net46/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
OpenTelemetry.Trace.ParentBasedSampler.ParentBasedSampler(OpenTelemetry.Trace.Sampler rootSampler, OpenTelemetry.Trace.Sampler remoteParentSampled = null, OpenTelemetry.Trace.Sampler remoteParentNotSampled = null, OpenTelemetry.Trace.Sampler localParentSampled = null, OpenTelemetry.Trace.Sampler localParentNotSampled = null) -> void
OpenTelemetry.Trace.TracerProviderOptions
OpenTelemetry.Trace.TracerProviderOptions.SetErrorStatusOnException.get -> bool
OpenTelemetry.Trace.TracerProviderOptions.SetErrorStatusOnException.set -> void
OpenTelemetry.Trace.TracerProviderOptions.TracerProviderOptions() -> void
static OpenTelemetry.Sdk.CreateTracerProviderBuilder(System.Action<OpenTelemetry.Trace.TracerProviderOptions> configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddLegacyActivity(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, string operationName) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderExtensions.ForceFlush(this OpenTelemetry.Trace.TracerProvider provider, int timeoutMilliseconds = -1) -> bool
14 changes: 14 additions & 0 deletions src/OpenTelemetry/.publicApi/net461/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
OpenTelemetry.Logs.LogRecord.ForEachScope<TState>(System.Action<object, TState> callback, TState state) -> void
OpenTelemetry.Logs.LogRecord.Message.get -> string
OpenTelemetry.Logs.LogRecord.StateValues.get -> System.Collections.Generic.IReadOnlyList<System.Collections.Generic.KeyValuePair<string, object>>
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeMessage.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeMessage.set -> void
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.set -> void
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.set -> void
OpenTelemetry.Trace.ParentBasedSampler.ParentBasedSampler(OpenTelemetry.Trace.Sampler rootSampler, OpenTelemetry.Trace.Sampler remoteParentSampled = null, OpenTelemetry.Trace.Sampler remoteParentNotSampled = null, OpenTelemetry.Trace.Sampler localParentSampled = null, OpenTelemetry.Trace.Sampler localParentNotSampled = null) -> void
OpenTelemetry.Trace.TracerProviderOptions
OpenTelemetry.Trace.TracerProviderOptions.SetErrorStatusOnException.get -> bool
OpenTelemetry.Trace.TracerProviderOptions.SetErrorStatusOnException.set -> void
OpenTelemetry.Trace.TracerProviderOptions.TracerProviderOptions() -> void
static OpenTelemetry.Sdk.CreateTracerProviderBuilder(System.Action<OpenTelemetry.Trace.TracerProviderOptions> configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddLegacyActivity(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, string operationName) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderExtensions.ForceFlush(this OpenTelemetry.Trace.TracerProvider provider, int timeoutMilliseconds = -1) -> bool
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
OpenTelemetry.Logs.LogRecord.ForEachScope<TState>(System.Action<object, TState> callback, TState state) -> void
OpenTelemetry.Logs.LogRecord.Message.get -> string
OpenTelemetry.Logs.LogRecord.StateValues.get -> System.Collections.Generic.IReadOnlyList<System.Collections.Generic.KeyValuePair<string, object>>
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeMessage.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeMessage.set -> void
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.IncludeScopes.set -> void
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ParseStateValues.set -> void
OpenTelemetry.Trace.ParentBasedSampler.ParentBasedSampler(OpenTelemetry.Trace.Sampler rootSampler, OpenTelemetry.Trace.Sampler remoteParentSampled = null, OpenTelemetry.Trace.Sampler remoteParentNotSampled = null, OpenTelemetry.Trace.Sampler localParentSampled = null, OpenTelemetry.Trace.Sampler localParentNotSampled = null) -> void
OpenTelemetry.Trace.TracerProviderOptions
OpenTelemetry.Trace.TracerProviderOptions.SetErrorStatusOnException.get -> bool
OpenTelemetry.Trace.TracerProviderOptions.SetErrorStatusOnException.set -> void
OpenTelemetry.Trace.TracerProviderOptions.TracerProviderOptions() -> void
static OpenTelemetry.Sdk.CreateTracerProviderBuilder(System.Action<OpenTelemetry.Trace.TracerProviderOptions> configure = null) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderBuilderExtensions.AddLegacyActivity(this OpenTelemetry.Trace.TracerProviderBuilder tracerProviderBuilder, string operationName) -> OpenTelemetry.Trace.TracerProviderBuilder
static OpenTelemetry.Trace.TracerProviderExtensions.ForceFlush(this OpenTelemetry.Trace.TracerProvider provider, int timeoutMilliseconds = -1) -> bool
9 changes: 5 additions & 4 deletions src/OpenTelemetry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ please check the latest changes

## Unreleased

* Added `ForceFlush` to `TracerProvider`. ([#1837](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1837))

* Added `TracerProviderOptions` and `SetErrorStatusOnException`.
([#1858](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1858))
* Added `ForceFlush` to `TracerProvider`.
([#1837](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1837))
* Added a TracerProvierBuilder extension method called
`AddLegacyActivityOperationName` which is used by instrumentation libraries
that use DiagnosticSource to get activities processed without
ActivitySourceAdapter.
[#1836](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1836)

([#1836](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1836))
* Added new constructor with optional parameters to allow customization of
`ParentBasedSampler` behavior. ([#1727](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1727))

Expand Down
36 changes: 34 additions & 2 deletions src/OpenTelemetry/Logs/LogRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#if NET461 || NETSTANDARD2_0
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Extensions.Logging;

Expand All @@ -26,9 +27,20 @@ namespace OpenTelemetry.Logs
/// </summary>
public sealed class LogRecord
{
internal LogRecord(DateTime timestamp, string categoryName, LogLevel logLevel, EventId eventId, object state, Exception exception)
private readonly IExternalScopeProvider scopeProvider;

internal LogRecord(
IExternalScopeProvider scopeProvider,
DateTime timestamp,
string categoryName,
LogLevel logLevel,
EventId eventId,
string message,
object state,
Exception exception,
IReadOnlyList<KeyValuePair<string, object>> stateValues)
{
this.Timestamp = timestamp;
this.scopeProvider = scopeProvider;

var activity = Activity.Current;
if (activity != null)
Expand All @@ -39,10 +51,13 @@ internal LogRecord(DateTime timestamp, string categoryName, LogLevel logLevel, E
this.TraceFlags = activity.ActivityTraceFlags;
}

this.Timestamp = timestamp;
this.CategoryName = categoryName;
this.LogLevel = logLevel;
this.EventId = eventId;
this.Message = message;
this.State = state;
this.StateValues = stateValues;
this.Exception = exception;
}

Expand All @@ -62,9 +77,26 @@ internal LogRecord(DateTime timestamp, string categoryName, LogLevel logLevel, E

public EventId EventId { get; }

public string Message { get; }

public object State { get; }

public IReadOnlyList<KeyValuePair<string, object>> StateValues { get; }

public Exception Exception { get; }

/// <summary>
/// Executes callback for each currently active scope objects in order
/// of creation. All callbacks are guaranteed to be called inline from
/// this method.
/// </summary>
/// <typeparam name="TState">State.</typeparam>
/// <param name="callback">The callback to be executed for every scope object.</param>
/// <param name="state">The state object to be passed into the callback.</param>
public void ForEachScope<TState>(Action<object, TState> callback, TState state)
{
this.scopeProvider?.ForEachScope(callback, state);
}
}
}
#endif
Loading

0 comments on commit 255ddc7

Please sign in to comment.