diff --git a/src/Dependencies.props b/src/Dependencies.props new file mode 100644 index 0000000..5154012 --- /dev/null +++ b/src/Dependencies.props @@ -0,0 +1,10 @@ + + + + 1.8.0 + 11.0.0 + 7.1.0 + 4.7.0 + + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d37e64d..da9e319 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,12 +1,47 @@ + + + + + netstandard2.0 + + + + latest + 0.0.0 + enable + nullable + + - $(MSBuildThisFileDirectory.TrimEnd('\').TrimEnd('/')) - $([System.IO.Path]::Combine($(CCSourceDirectory), 'Settings.props')) - $([System.IO.Path]::Combine($(CCSourceDirectory), 'Version.props')) - $([System.IO.Path]::Combine($(CCSourceDirectory), 'Package.props')) + Elastic APM .NET Agent Extensions + Swiss Life authors and contributors + Swiss Life + Copyright © $(Company) $([System.DateTime]::Now.Year) + https://github.com/SwissLife-OSS/elastic-apm-extensions/blob/master/LICENSE + https://github.com/SwissLife-OSS/elastic-apm-extensions + Release notes: https://github.com/SwissLife-OSS/elastic-apm-extensions/releases/$(Version) + true + https://github.com/SwissLife-OSS/elastic-apm-extensions/raw/master/logo.png + false - - - + + true + true + https://github.com/SwissLife-OSS/elastic-apm-extensions.git + GitHub + true + snupkg + + + + portable + true + + + + + + diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets deleted file mode 100644 index 473fcc1..0000000 --- a/src/Directory.Build.targets +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/Elastic.Apm.Extensions.sln b/src/Elastic.Apm.Extensions.sln new file mode 100644 index 0000000..b691caf --- /dev/null +++ b/src/Elastic.Apm.Extensions.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30907.101 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elastic.Apm.GraphQL.HotChocolate", "Elastic.Apm.GraphQL.HotChocolate\Elastic.Apm.GraphQL.HotChocolate.csproj", "{FF6547C4-550A-4F3C-88AB-7DE2C88947C5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elastic.Apm.Messaging.MassTransit", "Elastic.Apm.Messaging.MassTransit\Elastic.Apm.Messaging.MassTransit.csproj", "{9F5A0818-9E19-4B24-B955-4DBFE871271F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Debug|x64.ActiveCfg = Debug|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Debug|x64.Build.0 = Debug|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Debug|x86.ActiveCfg = Debug|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Debug|x86.Build.0 = Debug|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Release|Any CPU.Build.0 = Release|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Release|x64.ActiveCfg = Release|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Release|x64.Build.0 = Release|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Release|x86.ActiveCfg = Release|Any CPU + {FF6547C4-550A-4F3C-88AB-7DE2C88947C5}.Release|x86.Build.0 = Release|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Debug|x64.ActiveCfg = Debug|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Debug|x64.Build.0 = Debug|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Debug|x86.ActiveCfg = Debug|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Debug|x86.Build.0 = Debug|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Release|Any CPU.Build.0 = Release|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Release|x64.ActiveCfg = Release|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Release|x64.Build.0 = Release|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Release|x86.ActiveCfg = Release|Any CPU + {9F5A0818-9E19-4B24-B955-4DBFE871271F}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F5A91904-BC2B-4796-8836-2FB19ADC7015} + EndGlobalSection +EndGlobal diff --git a/src/Elastic.Apm.GraphQL.HotChocolate/Directory.Build.props b/src/Elastic.Apm.GraphQL.HotChocolate/Directory.Build.props new file mode 100644 index 0000000..0c0371b --- /dev/null +++ b/src/Elastic.Apm.GraphQL.HotChocolate/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + apm monitoring elastic elasticapm analytics graphql hotchocolate + + + diff --git a/src/Elastic.Apm.GraphQL.HotChocolate/Elastic.Apm.GraphQL.HotChocolate.csproj b/src/Elastic.Apm.GraphQL.HotChocolate/Elastic.Apm.GraphQL.HotChocolate.csproj new file mode 100644 index 0000000..5f616ca --- /dev/null +++ b/src/Elastic.Apm.GraphQL.HotChocolate/Elastic.Apm.GraphQL.HotChocolate.csproj @@ -0,0 +1,19 @@ + + + + Elastic.Apm.GraphQL.HotChocolate + Elastic.Apm.GraphQL.HotChocolate + ElasticApm.GraphQL.HotChocolate + true + + + + + + + + + + + + diff --git a/src/Elastic.Apm.Internals/CompositeDisposable.cs b/src/Elastic.Apm.Internals/CompositeDisposable.cs new file mode 100644 index 0000000..d8e01f6 --- /dev/null +++ b/src/Elastic.Apm.Internals/CompositeDisposable.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +namespace Elastic.Apm +{ + internal sealed class CompositeDisposable : IDisposable + { + private readonly List _disposables = new List(); + private readonly object _lock = new object(); + + private bool _isDisposed; + + public void Dispose() + { + if (_isDisposed) + { + return; + } + + lock (_lock) + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + + foreach (var d in _disposables) + { + d.Dispose(); + } + } + } + + public CompositeDisposable Add(IDisposable disposable) + { + if (_isDisposed) + { + throw new ObjectDisposedException(nameof(CompositeDisposable)); + } + + _disposables.Add(disposable); + return this; + } + } +} diff --git a/src/Elastic.Apm.Messaging.MassTransit/Constants.cs b/src/Elastic.Apm.Messaging.MassTransit/Constants.cs new file mode 100644 index 0000000..cb2063f --- /dev/null +++ b/src/Elastic.Apm.Messaging.MassTransit/Constants.cs @@ -0,0 +1,26 @@ +namespace Elastic.Apm.Messaging.MassTransit +{ + internal struct Constants + { + internal const string TraceHeaderName = "Elastic.Apm"; + + internal struct DiagnosticListener + { + internal const string Name = "MassTransit"; + } + + internal struct Events + { + internal const string SendStart = "MassTransit.Transport.Send.Start"; + internal const string SendStop = "MassTransit.Transport.Send.Stop"; + internal const string ReceiveStart = "MassTransit.Transport.Receive.Start"; + internal const string ReceiveStop = "MassTransit.Transport.Receive.Stop"; + } + + internal struct Apm + { + internal const string Type = "messaging"; + internal const string SendAction = "send"; + } + } +} diff --git a/src/Elastic.Apm.Messaging.MassTransit/Directory.Build.props b/src/Elastic.Apm.Messaging.MassTransit/Directory.Build.props new file mode 100644 index 0000000..d5c44cd --- /dev/null +++ b/src/Elastic.Apm.Messaging.MassTransit/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + apm monitoring elastic elasticapm analytics messaging masstransit + + + diff --git a/src/Elastic.Apm.Messaging.MassTransit/Elastic.Apm.Messaging.MassTransit.csproj b/src/Elastic.Apm.Messaging.MassTransit/Elastic.Apm.Messaging.MassTransit.csproj new file mode 100644 index 0000000..20c8c55 --- /dev/null +++ b/src/Elastic.Apm.Messaging.MassTransit/Elastic.Apm.Messaging.MassTransit.csproj @@ -0,0 +1,20 @@ + + + + Elastic.Apm.Messaging.MassTransit + Elastic.Apm.Messaging.MassTransit + ElasticApm.Messaging.MassTransit + true + + + + + + + + + + + + + diff --git a/src/Elastic.Apm.Messaging.MassTransit/MassTransitDiagnosticInitializer.cs b/src/Elastic.Apm.Messaging.MassTransit/MassTransitDiagnosticInitializer.cs new file mode 100644 index 0000000..b5b87d5 --- /dev/null +++ b/src/Elastic.Apm.Messaging.MassTransit/MassTransitDiagnosticInitializer.cs @@ -0,0 +1,35 @@ +using System; +using System.Diagnostics; + +namespace Elastic.Apm.Messaging.MassTransit +{ + internal class MassTransitDiagnosticInitializer : IObserver, IDisposable + { + private readonly IApmAgent _apmAgent; + private IDisposable? _sourceSubscription; + + internal MassTransitDiagnosticInitializer(IApmAgent apmAgent) + { + _apmAgent = apmAgent; + } + + public void Dispose() => _sourceSubscription?.Dispose(); + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(DiagnosticListener value) + { + if (string.Equals(value.Name, Constants.DiagnosticListener.Name, + StringComparison.InvariantCultureIgnoreCase)) + { + _sourceSubscription = value.Subscribe(new MassTransitDiagnosticListener(_apmAgent)); + } + } + } +} diff --git a/src/Elastic.Apm.Messaging.MassTransit/MassTransitDiagnosticListener.cs b/src/Elastic.Apm.Messaging.MassTransit/MassTransitDiagnosticListener.cs new file mode 100644 index 0000000..f24ed55 --- /dev/null +++ b/src/Elastic.Apm.Messaging.MassTransit/MassTransitDiagnosticListener.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Elastic.Apm.Api; +using Elastic.Apm.Logging; +using MassTransit; + +namespace Elastic.Apm.Messaging.MassTransit +{ + internal class MassTransitDiagnosticListener : IObserver> + { + private readonly IApmAgent _apmAgent; + private readonly IApmLogger _logger; + + private readonly ConcurrentDictionary _activities = + new ConcurrentDictionary(); + + + internal MassTransitDiagnosticListener(IApmAgent apmAgent) + { + _apmAgent = apmAgent; + _logger = apmAgent.Logger; + } + + public void OnNext(KeyValuePair value) + { + if (!HasActivity(value.Key, out Activity? activity)) + { + return; + } + + switch (value.Key) + { + case Constants.Events.SendStart: + HandleSendStart(activity, value.Value); + return; + case Constants.Events.SendStop: + HandleStop(activity.SpanId, activity.Duration); + return; + case Constants.Events.ReceiveStart: + HandleReceiveStart(activity, value.Value); + return; + case Constants.Events.ReceiveStop: + HandleStop(activity.ParentSpanId, activity.Parent!.Duration); + return; + } + } + + public void OnError(Exception error) + { + } + + public void OnCompleted() + { + } + + private void HandleSendStart(Activity activity, object? context) + { + try + { + IExecutionSegment? executionSegment = _apmAgent.Tracer.GetExecutionSegment(); + if (executionSegment != null && context is SendContext sendContext) + { + var spanName = context is PublishContext ? "Publish" : "Send"; + spanName = $"{spanName} {sendContext.DestinationAddress.AbsolutePath}"; + var subType = sendContext.DestinationAddress.Scheme; + + ISpan span = executionSegment.StartSpan( + spanName, + Constants.Apm.Type, + subType, + Constants.Apm.SendAction); + + sendContext.SetTracingData(span); + + _activities.TryAdd(activity.SpanId, span); + } + } + catch (Exception ex) + { + var message = $"{Constants.Events.SendStart} instrumentation failed."; + _logger.Log(LogLevel.Error, message, ex, default); + } + } + + private void HandleReceiveStart(Activity activity, object? context) + { + try + { + if (context is ReceiveContext receiveContext) + { + DistributedTracingData? tracingData = receiveContext.GetTracingData(); + var transactionName = $"Receive {receiveContext.InputAddress.AbsolutePath}"; + + ITransaction transaction = _apmAgent.Tracer.StartTransaction( + transactionName, + Constants.Apm.Type, + tracingData); + + _activities.TryAdd(activity.SpanId, transaction); + } + } + catch (Exception ex) + { + var message = $"{Constants.Events.ReceiveStart} instrumentation failed."; + _logger.Log(LogLevel.Error, message, ex, default); + } + } + + private void HandleStop(ActivitySpanId? spanId, TimeSpan duration) + { + if (spanId.HasValue && + _activities.TryRemove(spanId.Value, out IExecutionSegment executionSegment)) + { + executionSegment.Duration = duration.TotalMilliseconds; + executionSegment.End(); + } + } + + private bool HasActivity(string eventName, [NotNullWhen(true)] out Activity? activity) + { + activity = Activity.Current; + if (activity == null) + { + var message = $"No activity was found for event: {eventName}"; + _logger.Log(LogLevel.Warning, message, default, default); + return false; + } + + return true; + } + } +} diff --git a/src/Elastic.Apm.Messaging.MassTransit/MassTransitDiagnosticsSubscriber.cs b/src/Elastic.Apm.Messaging.MassTransit/MassTransitDiagnosticsSubscriber.cs new file mode 100644 index 0000000..7d2e931 --- /dev/null +++ b/src/Elastic.Apm.Messaging.MassTransit/MassTransitDiagnosticsSubscriber.cs @@ -0,0 +1,29 @@ +using System; +using System.Diagnostics; +using Elastic.Apm.DiagnosticSource; + +namespace Elastic.Apm.Messaging.MassTransit +{ + /// + /// Diagnostic events subscriber for MassTransit. + /// + public class MassTransitDiagnosticsSubscriber : IDiagnosticsSubscriber + { + /// + public IDisposable Subscribe(IApmAgent components) + { + var compositeDisposable = new CompositeDisposable(); + + if (!components.ConfigurationReader.Enabled) + { + return compositeDisposable; + } + + var initializer = new MassTransitDiagnosticInitializer(components); + compositeDisposable.Add(initializer); + compositeDisposable.Add(DiagnosticListener.AllListeners.Subscribe(initializer)); + + return compositeDisposable; + } + } +} diff --git a/src/Elastic.Apm.Messaging.MassTransit/MassTransitExtensions.cs b/src/Elastic.Apm.Messaging.MassTransit/MassTransitExtensions.cs new file mode 100644 index 0000000..9a28013 --- /dev/null +++ b/src/Elastic.Apm.Messaging.MassTransit/MassTransitExtensions.cs @@ -0,0 +1,20 @@ +using Elastic.Apm.Api; +using MassTransit; + +namespace Elastic.Apm.Messaging.MassTransit +{ + internal static class MassTransitExtensions + { + internal static void SetTracingData(this SendContext context, ISpan span) + { + var tracingData = span.OutgoingDistributedTracingData.SerializeToString(); + context.Headers.Set(Constants.TraceHeaderName, tracingData); + } + + internal static DistributedTracingData? GetTracingData(this ReceiveContext context) + { + var tracingData = context.TransportHeaders.Get(Constants.TraceHeaderName); + return DistributedTracingData.TryDeserializeFromString(tracingData); + } + } +} diff --git a/src/Nullable.cs b/src/Nullable.cs new file mode 100644 index 0000000..fea248e --- /dev/null +++ b/src/Nullable.cs @@ -0,0 +1,135 @@ +#pragma warning disable MA0048 // File name must match type name +#define INTERNAL_NULLABLE_ATTRIBUTES +#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// This code was copied from https://raw.githubusercontent.com/dotnet/corefx/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs + +namespace System.Diagnostics.CodeAnalysis +{ + /// Specifies that null is allowed as an input even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class AllowNullAttribute : Attribute { } + + /// Specifies that null is disallowed as an input even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DisallowNullAttribute : Attribute { } + + /// Specifies that an output may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MaybeNullAttribute : Attribute { } + + /// Specifies that an output will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullAttribute : Attribute { } + + /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MaybeNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter may be null. + /// + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } + } + + /// Specifies that the output will be non-null if the named parameter is non-null. + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class NotNullIfNotNullAttribute : Attribute + { + /// Initializes the attribute with the associated parameter name. + /// + /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// Gets the associated parameter name. + public string ParameterName { get; } + } + + /// Applied to a method that will never return under any circumstance. + [AttributeUsage(AttributeTargets.Method, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DoesNotReturnAttribute : Attribute { } + + /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class DoesNotReturnIfAttribute : Attribute + { + /// Initializes the attribute with the specified parameter value. + /// + /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + /// the associated parameter matches this value. + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// Gets the condition parameter value. + public bool ParameterValue { get; } + } +} + +#endif diff --git a/src/Nullable.props b/src/Nullable.props new file mode 100644 index 0000000..30b4f1b --- /dev/null +++ b/src/Nullable.props @@ -0,0 +1,9 @@ + + + $(NoWarn);8600;8601;8602;8603;8604;CS0436 + + + + + + diff --git a/src/Package.props b/src/Package.props deleted file mode 100644 index f80396a..0000000 --- a/src/Package.props +++ /dev/null @@ -1,31 +0,0 @@ - - - - {Placeholder}- - Swiss Life authors and contributors - Swiss Life - Copyright © 2019 Swiss Life - https://github.com/SwissLife-OSS/{Placeholder}/blob/master/LICENSE - https://github.com/SwissLife-OSS/{Placeholder} - Release notes: https://github.com/SwissLife-OSS/{Placeholder}/releases/$(Version) - {Placeholder} - true - https://github.com/SwissLife-OSS/{Placeholder}/raw/master/logo.png - false - - - - true - true - https://github.com/SwissLife-OSS/{Placeholder}.git - GitHub - true - snupkg - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - - - - - - - diff --git a/src/Shared/TracerExtensions.cs b/src/Shared/TracerExtensions.cs new file mode 100644 index 0000000..e37a0bb --- /dev/null +++ b/src/Shared/TracerExtensions.cs @@ -0,0 +1,13 @@ +using Elastic.Apm.Api; + +namespace Elastic.Apm +{ + internal static class TracerExtensions + { + public static IExecutionSegment? GetExecutionSegment(this ITracer tracer) + { + ITransaction? transaction = tracer.CurrentTransaction; + return tracer.CurrentSpan ?? (IExecutionSegment)transaction; + } + } +} diff --git a/src/Version.props b/src/Version.props deleted file mode 100644 index 1f8399b..0000000 --- a/src/Version.props +++ /dev/null @@ -1,7 +0,0 @@ - - - - 0.0.0 - - - \ No newline at end of file