Skip to content

Commit 0933da7

Browse files
author
Bart Koelman
committed
Instrumented library and example project
1 parent 91bbcdb commit 0933da7

31 files changed

+327
-143
lines changed

JsonApiDotNetCore.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ $left$ = $right$;</s:String>
620620
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=B3D9EE6B4EC62A4F961EB15F9ADEC2C6/ReplacePattern/@EntryValue">$collection$.IsNullOrEmpty()</s:String>
621621
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=B3D9EE6B4EC62A4F961EB15F9ADEC2C6/SearchPattern/@EntryValue">$collection$ == null || !$collection$.Any()</s:String>
622622
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=B3D9EE6B4EC62A4F961EB15F9ADEC2C6/Severity/@EntryValue">WARNING</s:String>
623+
<s:Boolean x:Key="/Default/UserDictionary/Words/=appsettings/@EntryIndexedValue">True</s:Boolean>
623624
<s:Boolean x:Key="/Default/UserDictionary/Words/=Assignee/@EntryIndexedValue">True</s:Boolean>
624625
<s:Boolean x:Key="/Default/UserDictionary/Words/=Injectables/@EntryIndexedValue">True</s:Boolean>
625626
<s:Boolean x:Key="/Default/UserDictionary/Words/=linebreaks/@EntryIndexedValue">True</s:Boolean>

src/Examples/JsonApiDotNetCoreExample/Startups/EmptyStartup.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Microsoft.AspNetCore.Builder;
22
using Microsoft.AspNetCore.Hosting;
33
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Logging;
45

56
namespace JsonApiDotNetCoreExample.Startups
67
{
@@ -14,7 +15,7 @@ public virtual void ConfigureServices(IServiceCollection services)
1415
{
1516
}
1617

17-
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment environment)
18+
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment environment, ILoggerFactory loggerFactory)
1819
{
1920
}
2021
}
Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,97 @@
11
using System;
22
using JsonApiDotNetCore.Configuration;
3+
using JsonApiDotNetCore.Diagnostics;
34
using JsonApiDotNetCoreExample.Data;
45
using Microsoft.AspNetCore.Authentication;
56
using Microsoft.AspNetCore.Builder;
67
using Microsoft.AspNetCore.Hosting;
78
using Microsoft.EntityFrameworkCore;
89
using Microsoft.Extensions.Configuration;
910
using Microsoft.Extensions.DependencyInjection;
11+
using Microsoft.Extensions.Logging;
1012
using Newtonsoft.Json;
1113
using Newtonsoft.Json.Converters;
1214

1315
namespace JsonApiDotNetCoreExample.Startups
1416
{
1517
public sealed class Startup : EmptyStartup
1618
{
19+
private readonly ICodeTimerSession _codeTimingSession;
1720
private readonly string _connectionString;
1821

1922
public Startup(IConfiguration configuration)
2023
{
24+
_codeTimingSession = new DefaultCodeTimerSession();
25+
CodeTimingSessionManager.Capture(_codeTimingSession);
26+
2127
string postgresPassword = Environment.GetEnvironmentVariable("PGPASSWORD") ?? "postgres";
2228
_connectionString = configuration["Data:DefaultConnection"].Replace("###", postgresPassword);
2329
}
2430

2531
// This method gets called by the runtime. Use this method to add services to the container.
2632
public override void ConfigureServices(IServiceCollection services)
2733
{
28-
services.AddSingleton<ISystemClock, SystemClock>();
29-
30-
services.AddDbContext<AppDbContext>(options =>
34+
using (CodeTimingSessionManager.Current.Measure("Configure other (startup)"))
3135
{
32-
options.UseNpgsql(_connectionString);
36+
services.AddSingleton<ISystemClock, SystemClock>();
37+
38+
services.AddDbContext<AppDbContext>(options =>
39+
{
40+
options.UseNpgsql(_connectionString);
3341
#if DEBUG
34-
options.EnableSensitiveDataLogging();
35-
options.EnableDetailedErrors();
42+
options.EnableSensitiveDataLogging();
43+
options.EnableDetailedErrors();
3644
#endif
37-
});
45+
});
3846

39-
services.AddJsonApi<AppDbContext>(options =>
40-
{
41-
options.Namespace = "api/v1";
42-
options.UseRelativeLinks = true;
43-
options.ValidateModelState = true;
44-
options.IncludeTotalResourceCount = true;
45-
options.SerializerSettings.Formatting = Formatting.Indented;
46-
options.SerializerSettings.Converters.Add(new StringEnumConverter());
47+
using (CodeTimingSessionManager.Current.Measure("Configure JSON:API (startup)"))
48+
{
49+
services.AddJsonApi<AppDbContext>(options =>
50+
{
51+
options.Namespace = "api/v1";
52+
options.UseRelativeLinks = true;
53+
options.ValidateModelState = true;
54+
options.IncludeTotalResourceCount = true;
55+
options.SerializerSettings.Formatting = Formatting.Indented;
56+
options.SerializerSettings.Converters.Add(new StringEnumConverter());
4757
#if DEBUG
48-
options.IncludeExceptionStackTraceInErrors = true;
58+
options.IncludeExceptionStackTraceInErrors = true;
4959
#endif
50-
}, discovery => discovery.AddCurrentAssembly());
60+
}, discovery => discovery.AddCurrentAssembly());
61+
}
62+
}
5163
}
5264

5365
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
54-
public override void Configure(IApplicationBuilder app, IWebHostEnvironment environment)
66+
public override void Configure(IApplicationBuilder app, IWebHostEnvironment environment, ILoggerFactory loggerFactory)
5567
{
56-
using (IServiceScope scope = app.ApplicationServices.CreateScope())
68+
ILogger<Startup> logger = loggerFactory.CreateLogger<Startup>();
69+
70+
using (CodeTimingSessionManager.Current.Measure("Initialize other (startup)"))
71+
{
72+
using (IServiceScope scope = app.ApplicationServices.CreateScope())
73+
{
74+
var appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
75+
appDbContext.Database.EnsureCreated();
76+
}
77+
78+
app.UseRouting();
79+
80+
using (CodeTimingSessionManager.Current.Measure("Initialize JSON:API (startup)"))
81+
{
82+
app.UseJsonApi();
83+
}
84+
85+
app.UseEndpoints(endpoints => endpoints.MapControllers());
86+
}
87+
88+
if (CodeTimingSessionManager.IsEnabled)
5789
{
58-
var appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
59-
appDbContext.Database.EnsureCreated();
90+
string timingResults = CodeTimingSessionManager.Current.GetResults();
91+
logger.LogInformation($"Measurement results for application startup:{Environment.NewLine}{timingResults}");
6092
}
6193

62-
app.UseRouting();
63-
app.UseJsonApi();
64-
app.UseEndpoints(endpoints => endpoints.MapControllers());
94+
_codeTimingSession.Dispose();
6595
}
6696
}
6797
}

src/Examples/JsonApiDotNetCoreExample/appsettings.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
"Default": "Warning",
88
"Microsoft.Hosting.Lifetime": "Warning",
99
"Microsoft.EntityFrameworkCore.Update": "Critical",
10-
"Microsoft.EntityFrameworkCore.Database.Command": "Critical"
10+
"Microsoft.EntityFrameworkCore.Database.Command": "Critical",
11+
"JsonApiDotNetCore": "Information",
12+
"JsonApiDotNetCoreExample": "Information"
1113
}
1214
},
1315
"AllowedHosts": "*"

src/JsonApiDotNetCore/Diagnostics/AspNetCodeTimerSession.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using JetBrains.Annotations;
23
using Microsoft.AspNetCore.Http;
34

45
namespace JsonApiDotNetCore.Diagnostics
@@ -8,7 +9,8 @@ namespace JsonApiDotNetCore.Diagnostics
89
/// Can be used with async/wait, but it cannot distinguish between concurrently running threads within a single HTTP request, so you'll need to pass an
910
/// <see cref="CascadingCodeTimer" /> instance through the entire call chain in that case.
1011
/// </summary>
11-
internal sealed class AspNetCodeTimerSession : ICodeTimerSession
12+
[PublicAPI]
13+
public sealed class AspNetCodeTimerSession : ICodeTimerSession
1214
{
1315
private const string HttpContextItemKey = "CascadingCodeTimer:Session";
1416

src/JsonApiDotNetCore/Diagnostics/CascadingCodeTimer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ private void Close(MeasureScope scope)
6969
}
7070

7171
/// <inheritdoc />
72-
public string GetResult()
72+
public string GetResults()
7373
{
7474
int paddingLength = GetPaddingLength();
7575

src/JsonApiDotNetCore/Diagnostics/CodeTimingSessionManager.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ namespace JsonApiDotNetCore.Diagnostics
99
/// Provides access to the "current" measurement, which removes the need to pass along a <see cref="CascadingCodeTimer" /> instance through the entire
1010
/// call chain.
1111
/// </summary>
12-
internal static class CodeTimingSessionManager
12+
public static class CodeTimingSessionManager
1313
{
14-
private static readonly bool IsEnabled;
14+
public static readonly bool IsEnabled;
1515
private static ICodeTimerSession _session;
1616

1717
public static ICodeTimer Current
@@ -38,6 +38,7 @@ static CodeTimingSessionManager()
3838
#endif
3939
}
4040

41+
// ReSharper disable once UnusedMember.Local
4142
private static bool IsRunningInTest()
4243
{
4344
const string testAssemblyName = "xunit.core";

src/JsonApiDotNetCore/Diagnostics/DefaultCodeTimerSession.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace JsonApiDotNetCore.Diagnostics
77
/// General code timing session management. Can be used with async/wait, but it cannot distinguish between concurrently running threads, so you'll need
88
/// to pass an <see cref="CascadingCodeTimer" /> instance through the entire call chain in that case.
99
/// </summary>
10-
internal sealed class DefaultCodeTimerSession : ICodeTimerSession
10+
public sealed class DefaultCodeTimerSession : ICodeTimerSession
1111
{
1212
private readonly AsyncLocal<ICodeTimer> _codeTimerInContext = new();
1313

src/JsonApiDotNetCore/Diagnostics/DisabledCodeTimer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public IDisposable Measure(string name, bool excludeInRelativeCost = false)
1818
return this;
1919
}
2020

21-
public string GetResult()
21+
public string GetResults()
2222
{
2323
return string.Empty;
2424
}

src/JsonApiDotNetCore/Diagnostics/ICodeTimer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace JsonApiDotNetCore.Diagnostics
55
/// <summary>
66
/// Records execution times for code blocks.
77
/// </summary>
8-
internal interface ICodeTimer : IDisposable
8+
public interface ICodeTimer : IDisposable
99
{
1010
/// <summary>
1111
/// Starts recording the duration of a code block. Wrap this call in a <c>using</c> statement, so the recording stops when the return value goes out of
@@ -22,6 +22,6 @@ internal interface ICodeTimer : IDisposable
2222
/// <summary>
2323
/// Returns intermediate or final results.
2424
/// </summary>
25-
string GetResult();
25+
string GetResults();
2626
}
2727
}

0 commit comments

Comments
 (0)