Skip to content

Commit

Permalink
.NET Core 2.0/DiagnosticListener changes
Browse files Browse the repository at this point in the history
This attempts to use DiagnosticListener "correctly" but there is no correctly. I give up on getting the MVC version working. Entity Framework is better (except for ID constants, they aren't constants), but MVC is anonymous types and `DiagnosticAdapter` removed `netstandard` support.

I'm so done with this "API". I hope one day someone else improves it: https://github.com/dotnet/corefx/issues/18114#issuecomment-322345786
  • Loading branch information
NickCraver committed Aug 15, 2017
1 parent e1adee9 commit b9302c6
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 121 deletions.
2 changes: 1 addition & 1 deletion samples/Samples.AspNetCore/Controllers/TestController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public IActionResult EntityFrameworkCore()
{
using (MiniProfiler.Current.Step("Insertion"))
{
context.RouteHits.Add(new RouteHit { RouteName = name, HitCount = 1 });
context.RouteHits.Add(hit = new RouteHit { RouteName = name, HitCount = 1 });
context.SaveChanges();
}
}
Expand Down
100 changes: 0 additions & 100 deletions src/MiniProfiler.AspNetCore.Mvc/Internal/MvcViewDiagnosticListener.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<Description>Lightweight mini-profiler, designed for ASP.NET Core MVC (*not* System.Web) websites</Description>
<Authors>Nick Craver</Authors>
<PackageTags>ASP.NET Core;MVC;MVC Core;$(PackageBaseTags)</PackageTags>
<TargetFrameworks>net451;net46;netstandard1.6</TargetFrameworks>
<TargetFrameworks>net451;net46;netstandard1.6;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="1.1.1" />
Expand Down
10 changes: 7 additions & 3 deletions src/MiniProfiler.AspNetCore/DiagnosticInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,15 @@ public void Start()

void IObserver<DiagnosticListener>.OnNext(DiagnosticListener value)
{
foreach (var applicationInsightDiagnosticListener in _diagnosticListeners)
foreach (var listener in _diagnosticListeners)
{
if (applicationInsightDiagnosticListener.ListenerName == value.Name)
if (listener.ListenerName == value.Name)
{
_subscriptions.Add(value.SubscribeWithAdapter(applicationInsightDiagnosticListener));
#if NETSTANDARD2_0
_subscriptions.Add(value.Subscribe(listener));
#else
_subscriptions.Add(value.SubscribeWithAdapter(listener));
#endif
}
}
}
Expand Down
15 changes: 11 additions & 4 deletions src/MiniProfiler.AspNetCore/MiniProfiler.AspNetCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,21 @@
<Description>Lightweight mini-profiler, designed for ASP.NET Core (not System.Web) websites</Description>
<Authors>Nick Craver</Authors>
<PackageTags>ASP.NET Core;$(PackageBaseTags)</PackageTags>
<TargetFrameworks>net451;net46;netstandard1.5</TargetFrameworks>
<TargetFrameworks>net451;net46;netstandard1.5;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="4.4.1" />
<ProjectReference Include="..\MiniProfiler.Shared\MiniProfiler.Shared.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Html.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Html.Abstractions" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="1.1.0" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="4.3.0" />
<ProjectReference Include="..\MiniProfiler.Shared\MiniProfiler.Shared.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@
<Description>MiniProfiler: Integration for Entity Framework Core</Description>
<Authors>Nick Craver</Authors>
<PackageTags>Entity Framework;Entity Framework Core;$(PackageBaseTags)</PackageTags>
<TargetFrameworks>net451;net46;netstandard1.5</TargetFrameworks>
<TargetFrameworks>net451;net46;netstandard1.5;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<RootNamespace>StackExchange.Profiling.Data</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MiniProfiler.AspNetCore\MiniProfiler.AspNetCore.csproj" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard2.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
</ItemGroup>
</Project>
117 changes: 110 additions & 7 deletions src/MiniProfiler.EntityFrameworkCore/RelationalDiagnosticListener.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DiagnosticAdapter;
using StackExchange.Profiling.Internal;
using System;
using System.Collections.Concurrent;
#if NETSTANDARD2_0
using Microsoft.EntityFrameworkCore.Diagnostics;
using System.Collections.Generic;
#else
using Microsoft.Extensions.DiagnosticAdapter;
using System.Data.Common;
#endif

namespace StackExchange.Profiling.Data
{
Expand All @@ -25,9 +30,106 @@ private readonly ConcurrentDictionary<Guid, CustomTiming>
_commands = new ConcurrentDictionary<Guid, CustomTiming>(),
_opening = new ConcurrentDictionary<Guid, CustomTiming>(),
_closing = new ConcurrentDictionary<Guid, CustomTiming>();

#if NETSTANDARD2_0
// See https://github.com/aspnet/EntityFramework/issues/8007
private readonly ConcurrentDictionary<Guid, CustomTiming>
_readers = new ConcurrentDictionary<Guid, CustomTiming>();

public void OnCompleted() { }
public void OnError(Exception error) { }

// Until EF has a Guid on DbReader's in 2.0, we have to hackily do this
// Tracking here: https://github.com/aspnet/EntityFramework/issues/8007
public void OnNext(KeyValuePair<string, object> kv)
{
if (kv.Key == RelationalEventId.CommandExecuting.Name)
{
var data = (CommandEventData)kv.Value;
var timing = data.Command.GetTiming(data.ExecuteMethod + (data.IsAsync ? " (Async)" : null), MiniProfiler.Current);
if (timing != null)
{
_commands[data.CommandId] = timing;
}
}
else if (kv.Key == RelationalEventId.CommandExecuted.Name)
{
var data = (CommandExecutedEventData)kv.Value;
if (_commands.TryRemove(data.CommandId, out var current))
{
// A completion for a DataReader only means we *started* getting data back, not finished.
if (data.Result is RelationalDataReader reader)
{
_readers[data.CommandId] = current;
current.FirstFetchCompleted();
}
else
{
current.Stop();
}
}
}
else if (kv.Key == RelationalEventId.CommandError.Name)
{
var data = (CommandErrorEventData)kv.Value;
if (_commands.TryRemove(data.CommandId, out var command))
{
command.Errored = true;
command.Stop();
}
}
else if (kv.Key == RelationalEventId.DataReaderDisposing.Name)
{
var data = (DataReaderDisposingEventData)kv.Value;
if (_readers.TryRemove(data.CommandId, out var reader))
{
reader.Stop();
}
}
// TODO consider switching to ConnectionEndEventData.Duration
// This isn't as trivia as it appears due to the start offset of the request
else if (kv.Key == RelationalEventId.ConnectionOpening.Name)
{
var data = (ConnectionEventData)kv.Value;
_opening[data.ConnectionId] = MiniProfiler.Current.CustomTiming("sql",
data.IsAsync ? "Connection OpenAsync()" : "Connection Open()",
data.IsAsync ? "OpenAsync" : "Open");
}
else if (kv.Key == RelationalEventId.ConnectionOpened.Name)
{
var data = (ConnectionEndEventData)kv.Value;
if (_opening.TryRemove(data.ConnectionId, out var openingTiming))
{
openingTiming.Stop();
}
}
else if (kv.Key == RelationalEventId.ConnectionClosing.Name)
{
var data = (ConnectionEventData)kv.Value;
_closing[data.ConnectionId] = MiniProfiler.Current.CustomTiming("sql",
data.IsAsync ? "Connection CloseAsync()" : "Connection Close()",
data.IsAsync ? "CloseAsync" : "Close");
}
else if (kv.Key == RelationalEventId.ConnectionClosed.Name)
{
var data = (ConnectionEndEventData)kv.Value;
if (_closing.TryRemove(data.ConnectionId, out var closingTiming))
{
closingTiming.Stop();
}
}
else if (kv.Key == RelationalEventId.ConnectionError.Name)
{
var data = (ConnectionErrorEventData)kv.Value;
if (_opening.TryRemove(data.ConnectionId, out var openingTiming))
{
openingTiming.Errored = true;
}
if (_closing.TryRemove(data.ConnectionId, out var closingTiming))
{
closingTiming.Errored = true;
}
}
}
#else
private readonly ConcurrentDictionary<DbDataReader, CustomTiming>
_readers = new ConcurrentDictionary<DbDataReader, CustomTiming>();

Expand Down Expand Up @@ -106,7 +208,7 @@ public void OnDataReaderDisposing(DbDataReader dataReader)
reader.Stop();
}
}

/// <summary>
/// Handles ConnectionOpening events.
/// </summary>
Expand All @@ -120,7 +222,7 @@ public void OnConnectionOpening(Guid instanceId, bool async)
async ? "Connection OpenAsync()" : "Connection Open()",
async ? "OpenAsync" : "Open");
}

/// <summary>
/// Handles ConnectionOpened events.
/// </summary>
Expand All @@ -134,7 +236,7 @@ public void OnConnectionOpened(Guid instanceId)
openingTiming.Stop();
}
}

/// <summary>
/// Handles ConnectionClosing events.
/// </summary>
Expand All @@ -148,7 +250,7 @@ public void OnConnectionClosing(Guid instanceId, bool async)
async ? "Connection CloseAsync()" : "Connection Close()",
async ? "CloseAsync" : "Close");
}

/// <summary>
/// Handles ConnectionClosed events.
/// </summary>
Expand Down Expand Up @@ -180,6 +282,7 @@ public void OnConnectionError(Guid instanceId)
closingTiming.Errored = true;
}
}
#endif

// Transactions - Not in yet
//[DiagnosticName("Microsoft.EntityFrameworkCore.TransactionStarted")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
namespace StackExchange.Profiling.Internal
#if NETSTANDARD2_0
using System;
using System.Collections.Generic;
#endif

namespace StackExchange.Profiling.Internal
{
/// <summary>
/// Internal MiniProfiler interface for registering DiagnosticListeners, not meant for consumption.
/// This can and probably will break without warning. Don't use the .Internal namespace directly.
/// </summary>
public interface IMiniProfilerDiagnosticListener
#if NETSTANDARD2_0
: IObserver<KeyValuePair<string, object>>
#endif
{
/// <summary>
/// Gets a value indicating which listener this instance should be subscribed to
Expand Down

0 comments on commit b9302c6

Please sign in to comment.