diff --git a/Sentry-CI-Build-macOS.slnf b/Sentry-CI-Build-macOS.slnf index e654c81e63..ae938b72d0 100644 --- a/Sentry-CI-Build-macOS.slnf +++ b/Sentry-CI-Build-macOS.slnf @@ -36,12 +36,13 @@ "samples\\Sentry.Samples.OpenTelemetry.AspNetCore\\Sentry.Samples.OpenTelemetry.AspNetCore.csproj", "samples\\Sentry.Samples.OpenTelemetry.Console\\Sentry.Samples.OpenTelemetry.Console.csproj", "samples\\Sentry.Samples.Serilog\\Sentry.Samples.Serilog.csproj", + "samples\\Sentry.Samples.Sqlite\\Sentry.Samples.Sqlite.csproj", "src\\Sentry.Analyzers\\Sentry.Analyzers.csproj", "src\\Sentry.Android.AssemblyReader\\Sentry.Android.AssemblyReader.csproj", - "src\\Sentry.AspNet\\Sentry.AspNet.csproj", "src\\Sentry.AspNetCore.Blazor.WebAssembly\\Sentry.AspNetCore.Blazor.WebAssembly.csproj", "src\\Sentry.AspNetCore.Grpc\\Sentry.AspNetCore.Grpc.csproj", "src\\Sentry.AspNetCore\\Sentry.AspNetCore.csproj", + "src\\Sentry.AspNet\\Sentry.AspNet.csproj", "src\\Sentry.Azure.Functions.Worker\\Sentry.Azure.Functions.Worker.csproj", "src\\Sentry.Bindings.Android\\Sentry.Bindings.Android.csproj", "src\\Sentry.Bindings.Cocoa\\Sentry.Bindings.Cocoa.csproj", @@ -58,6 +59,7 @@ "src\\Sentry.Profiling\\Sentry.Profiling.csproj", "src\\Sentry.Serilog\\Sentry.Serilog.csproj", "src\\Sentry.SourceGenerators\\Sentry.SourceGenerators.csproj", + "src\\Sentry.Sqlite\\Sentry.Sqlite.csproj", "src\\Sentry\\Sentry.csproj", "test\\Sentry.Analyzers.Tests\\Sentry.Analyzers.Tests.csproj", "test\\Sentry.Android.AssemblyReader.Tests\\Sentry.Android.AssemblyReader.Tests.csproj", @@ -87,4 +89,4 @@ "test\\SingleFileTestApp\\SingleFileTestApp.csproj" ] } -} +} \ No newline at end of file diff --git a/Sentry.sln b/Sentry.sln index 3730377a46..fa8e6cac7d 100644 --- a/Sentry.sln +++ b/Sentry.sln @@ -209,6 +209,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.SourceGenerators.Tes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Maui.CommunityToolkit.Mvvm.Tests", "test\Sentry.Maui.CommunityToolkit.Mvvm.Tests\Sentry.Maui.CommunityToolkit.Mvvm.Tests.csproj", "{ADC91A84-6054-42EC-8241-0D717E4C7194}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Sqlite", "src\Sentry.Sqlite\Sentry.Sqlite.csproj", "{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.Sqlite", "samples\Sentry.Samples.Sqlite\Sentry.Samples.Sqlite.csproj", "{BB4FF3AE-C835-41AB-8F75-1611977BCF71}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1252,6 +1256,30 @@ Global {ADC91A84-6054-42EC-8241-0D717E4C7194}.Release|x64.Build.0 = Release|Any CPU {ADC91A84-6054-42EC-8241-0D717E4C7194}.Release|x86.ActiveCfg = Release|Any CPU {ADC91A84-6054-42EC-8241-0D717E4C7194}.Release|x86.Build.0 = Release|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|x64.ActiveCfg = Debug|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|x64.Build.0 = Debug|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|x86.ActiveCfg = Debug|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|x86.Build.0 = Debug|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|Any CPU.Build.0 = Release|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|x64.ActiveCfg = Release|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|x64.Build.0 = Release|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|x86.ActiveCfg = Release|Any CPU + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|x86.Build.0 = Release|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|x64.ActiveCfg = Debug|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|x64.Build.0 = Debug|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|x86.ActiveCfg = Debug|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|x86.Build.0 = Debug|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|Any CPU.Build.0 = Release|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|x64.ActiveCfg = Release|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|x64.Build.0 = Release|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|x86.ActiveCfg = Release|Any CPU + {BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1343,5 +1371,7 @@ Global {C3CDF61C-3E28-441C-A9CE-011C89D11719} = {230B9384-90FD-4551-A5DE-1A5C197F25B6} {3A76FF7D-2F32-4EA5-8999-2FFE3C7CB893} = {6987A1CC-608E-4868-A02C-09D30C8B7B2D} {ADC91A84-6054-42EC-8241-0D717E4C7194} = {6987A1CC-608E-4868-A02C-09D30C8B7B2D} + {CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912} = {230B9384-90FD-4551-A5DE-1A5C197F25B6} + {BB4FF3AE-C835-41AB-8F75-1611977BCF71} = {21B42F60-5802-404E-90F0-AEBCC56760C0} EndGlobalSection EndGlobal diff --git a/samples/Sentry.Samples.Sqlite/Program.cs b/samples/Sentry.Samples.Sqlite/Program.cs new file mode 100644 index 0000000000..d28bf95db6 --- /dev/null +++ b/samples/Sentry.Samples.Sqlite/Program.cs @@ -0,0 +1,89 @@ +using System; +using System.IO; +using Microsoft.Data.Sqlite; +using Sentry.Sqlite; + +SentrySdk.Init(options => +{ +#if !SENTRY_DSN_DEFINED_IN_ENV + // A DSN is required. You can set here in code, or you can set it in the SENTRY_DSN environment variable. + // See https://docs.sentry.io/product/sentry-basics/dsn-explainer/ + options.Dsn = SamplesShared.Dsn; +#endif + options.Debug = false; + options.TracesSampleRate = 1.0; +}); + +using (var connection = new SentrySqliteConnection("Data Source=hello.db")) +{ + connection.Open(); + + var command = connection.CreateCommand(); + command.CommandText = + @" + CREATE TABLE user ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL + ); + + INSERT INTO user + VALUES (1, 'Brice'), + (2, 'Alexander'), + (3, 'Nate'); + "; + command.ExecuteNonQuery(); + + Console.Write("Name: "); + var name = Console.ReadLine(); + + #region snippet_Parameter + command.CommandText = + @" + INSERT INTO user (name) + VALUES ($name) + "; + command.Parameters.AddWithValue("$name", name); + #endregion + command.ExecuteNonQuery(); + + command.CommandText = + @" + SELECT last_insert_rowid() + "; + var newId = (long)command.ExecuteScalar()!; + + Console.WriteLine($"Your new user ID is {newId}."); +} + +Console.Write("User ID: "); +var id = int.Parse(Console.ReadLine()!); + +#region snippet_HelloWorld +using (var connection = new SqliteConnection("Data Source=hello.db")) +{ + connection.Open(); + + var command = connection.CreateCommand(); + command.CommandText = + @" + SELECT name + FROM user + WHERE id = $id + "; + command.Parameters.AddWithValue("$id", id); + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + var name = reader.GetString(0); + + Console.WriteLine($"Hello, {name}!"); + } + } +} +#endregion + +// Clean up +SqliteConnection.ClearAllPools(); +File.Delete("hello.db"); diff --git a/samples/Sentry.Samples.Sqlite/Sentry.Samples.Sqlite.csproj b/samples/Sentry.Samples.Sqlite/Sentry.Samples.Sqlite.csproj new file mode 100644 index 0000000000..89a257e5cd --- /dev/null +++ b/samples/Sentry.Samples.Sqlite/Sentry.Samples.Sqlite.csproj @@ -0,0 +1,19 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + + + + diff --git a/src/Sentry.Sqlite/Sentry.Sqlite.csproj b/src/Sentry.Sqlite/Sentry.Sqlite.csproj new file mode 100644 index 0000000000..abebe72060 --- /dev/null +++ b/src/Sentry.Sqlite/Sentry.Sqlite.csproj @@ -0,0 +1,20 @@ + + + + net9.0 + enable + enable + Experimental Microsoft.Data.Sqlite integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. + $(PackageTags);Sqlite + + + + + + + + + + + + diff --git a/src/Sentry.Sqlite/SentrySqliteCommand.cs b/src/Sentry.Sqlite/SentrySqliteCommand.cs new file mode 100644 index 0000000000..dc2b03f521 --- /dev/null +++ b/src/Sentry.Sqlite/SentrySqliteCommand.cs @@ -0,0 +1,37 @@ +using Microsoft.Data.Sqlite; + +namespace Sentry.Sqlite; + +/// +public class SentrySqliteCommand : SqliteCommand +{ + internal ITransactionTracer? TransactionTracer { get; set; } = null; + + /// + public override int ExecuteNonQuery() + { + var span = TransactionTracer?.StartChild("db.query", CommandText); + try + { + return base.ExecuteNonQuery(); + } + finally + { + span?.Finish(); + } + } + + /// + public override object? ExecuteScalar() + { + var span = TransactionTracer?.StartChild("db.query", CommandText); + try + { + return base.ExecuteScalar(); + } + finally + { + span?.Finish(); + } + } +} diff --git a/src/Sentry.Sqlite/SentrySqliteConnection.cs b/src/Sentry.Sqlite/SentrySqliteConnection.cs new file mode 100644 index 0000000000..19d0904eab --- /dev/null +++ b/src/Sentry.Sqlite/SentrySqliteConnection.cs @@ -0,0 +1,52 @@ +using System.Data.Common; +using Microsoft.Data.Sqlite; + +namespace Sentry.Sqlite; + +/// +public class SentrySqliteConnection : SqliteConnection +{ + private ITransactionTracer? TransactionTracer { get; set; } = null; + + /// + /// Initializes a new instance of the class. + /// + /// The string used to open the connection. + /// Connection Strings + /// + public SentrySqliteConnection(string? connectionString) : base(connectionString) + { + } + + /// + public override void Open() + { + TransactionTracer = SentrySdk.StartTransaction( + "Open SQLite Connection", + "db.sqlite.open" + ); + base.Open(); + } + + /// + public new virtual SentrySqliteCommand CreateCommand() + => new() + { + Connection = this, + CommandTimeout = DefaultTimeout, + Transaction = Transaction, + TransactionTracer = TransactionTracer + }; + + /// + protected override DbCommand CreateDbCommand() + => CreateCommand(); + + /// + public override void Close() + { + base.Close(); + TransactionTracer?.Finish(); + TransactionTracer = null; + } +}