diff --git a/Sitko.Core.sln b/Sitko.Core.sln
index 3066808f2..203ac7ab5 100644
--- a/Sitko.Core.sln
+++ b/Sitko.Core.sln
@@ -246,6 +246,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sitko.Core.Repository.Grpc"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sitko.Core.Repository.Grpc.Tests", "tests\Sitko.Core.Repository.Grpc.Tests\Sitko.Core.Repository.Grpc.Tests.csproj", "{5D54C212-07F4-46B6-B86D-EC9D7641ED19}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sitko.Core.Sentry", "src\Sitko.Core.Sentry\Sitko.Core.Sentry.csproj", "{5D438687-8576-425A-A8A9-A80B893DCE0C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1483,6 +1485,18 @@ Global
{5D54C212-07F4-46B6-B86D-EC9D7641ED19}.Release|x64.Build.0 = Release|Any CPU
{5D54C212-07F4-46B6-B86D-EC9D7641ED19}.Release|x86.ActiveCfg = Release|Any CPU
{5D54C212-07F4-46B6-B86D-EC9D7641ED19}.Release|x86.Build.0 = Release|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Debug|x64.Build.0 = Debug|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Debug|x86.Build.0 = Debug|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Release|x64.ActiveCfg = Release|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Release|x64.Build.0 = Release|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Release|x86.ActiveCfg = Release|Any CPU
+ {5D438687-8576-425A-A8A9-A80B893DCE0C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{6677865F-C349-4D25-9E19-3DEC43E92DD5} = {109B331E-71B9-483C-8FC1-13B10C92A7F1}
@@ -1588,5 +1602,6 @@ Global
{D310CECD-6BBF-4C7B-AC46-48BAD632B8B2} = {F626F7B7-70BB-4D3B-A803-68ADA8BA4234}
{910855FF-013F-4343-B4D1-27721CB65822} = {109B331E-71B9-483C-8FC1-13B10C92A7F1}
{5D54C212-07F4-46B6-B86D-EC9D7641ED19} = {10C46F0D-1B13-447E-AD22-F01DDB5A79FD}
+ {5D438687-8576-425A-A8A9-A80B893DCE0C} = {109B331E-71B9-483C-8FC1-13B10C92A7F1}
EndGlobalSection
EndGlobal
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 8e31e41a9..1e48e53c9 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -42,6 +42,7 @@
+
diff --git a/src/Sitko.Core.Sentry/ApplicationExtensions.cs b/src/Sitko.Core.Sentry/ApplicationExtensions.cs
new file mode 100644
index 000000000..5f7de8b50
--- /dev/null
+++ b/src/Sitko.Core.Sentry/ApplicationExtensions.cs
@@ -0,0 +1,14 @@
+using Sitko.Core.App;
+
+namespace Sitko.Core.Sentry;
+
+public static class ApplicationExtensions
+{
+ public static Application AddSentry(this Application application,
+ Action configure, string? optionsKey = null) =>
+ application.AddModule(configure, optionsKey);
+
+ public static Application AddSentry(this Application application,
+ Action? configure = null, string? optionsKey = null) =>
+ application.AddModule(configure, optionsKey);
+}
diff --git a/src/Sitko.Core.Sentry/SentryModule.cs b/src/Sitko.Core.Sentry/SentryModule.cs
new file mode 100644
index 000000000..86468e822
--- /dev/null
+++ b/src/Sitko.Core.Sentry/SentryModule.cs
@@ -0,0 +1,27 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
+using Sentry.AspNetCore;
+using Sitko.Core.App;
+
+namespace Sitko.Core.Sentry;
+
+public class SentryModule : BaseApplicationModule,
+ IHostBuilderModule
+{
+ public override string OptionsKey => "Sentry";
+
+ public void ConfigureHostBuilder(IApplicationContext context, IHostBuilder hostBuilder, SentryModuleOptions startupOptions) =>
+ hostBuilder.ConfigureWebHostDefaults(webHostBuilder =>
+ {
+ webHostBuilder.UseSentry(builder =>
+ {
+ startupOptions.ConfigureSentry?.Invoke(context, builder, startupOptions);
+ builder.AddSentryOptions(o =>
+ {
+ o.Dsn = startupOptions.Dsn;
+ o.Debug = startupOptions.EnableDebug;
+ o.TracesSampleRate = startupOptions.TracesSampleRate;
+ });
+ });
+ });
+}
diff --git a/src/Sitko.Core.Sentry/SentryModuleOptions.cs b/src/Sitko.Core.Sentry/SentryModuleOptions.cs
new file mode 100644
index 000000000..cb531126f
--- /dev/null
+++ b/src/Sitko.Core.Sentry/SentryModuleOptions.cs
@@ -0,0 +1,22 @@
+using FluentValidation;
+using Sentry.AspNetCore;
+using Sitko.Core.App;
+
+namespace Sitko.Core.Sentry;
+
+public class SentryModuleOptions : BaseModuleOptions
+{
+ public string Dsn { get; set; } = "";
+ public bool EnableDebug { get; set; }
+ public double TracesSampleRate { get; set; } = 1.0;
+ public Action? ConfigureSentry { get; set; }
+}
+
+public class SentryModuleOptionsValidator : AbstractValidator
+{
+ public SentryModuleOptionsValidator()
+ {
+ RuleFor(options => options.Dsn).NotEmpty().WithMessage("Provide Sentry DSN");
+ RuleFor(options => options.TracesSampleRate).GreaterThan(0).WithMessage("Traces Sample Rate should be greater than zero");
+ }
+}
diff --git a/src/Sitko.Core.Sentry/Sitko.Core.Sentry.csproj b/src/Sitko.Core.Sentry/Sitko.Core.Sentry.csproj
new file mode 100644
index 000000000..5ba6665d3
--- /dev/null
+++ b/src/Sitko.Core.Sentry/Sitko.Core.Sentry.csproj
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+