Skip to content

Commit cc22c0f

Browse files
Experimental SqlLite integration
Relates to #1837: - #1837 This is just mucking around for a couple of hours to see how such an integration might be pieced together. If we want to proceed, there is some complexity around the `SqliteDataReader`. This only has an internal constructor, so we'd have to wrap it via a proxy class rather than inheritance.... which would doubtless involve a bunch of boilerplate grunt work. We'd also have to make decisions about what the hang the spans off. Ideally these DB spans would be children of any active transaction (e.g. the transactions created by the Mvvm integration)... which means storing/retrieving those transaction on the Scope - and as @bruno-garcia recently discovered in the SymbolCollector project, that's fiddly business in GlobalMode (particularly for DB stuff that is likely to be running on a background thread).
1 parent 05a4466 commit cc22c0f

File tree

7 files changed

+251
-2
lines changed

7 files changed

+251
-2
lines changed

Sentry-CI-Build-macOS.slnf

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@
3636
"samples\\Sentry.Samples.OpenTelemetry.AspNetCore\\Sentry.Samples.OpenTelemetry.AspNetCore.csproj",
3737
"samples\\Sentry.Samples.OpenTelemetry.Console\\Sentry.Samples.OpenTelemetry.Console.csproj",
3838
"samples\\Sentry.Samples.Serilog\\Sentry.Samples.Serilog.csproj",
39+
"samples\\Sentry.Samples.Sqlite\\Sentry.Samples.Sqlite.csproj",
3940
"src\\Sentry.Analyzers\\Sentry.Analyzers.csproj",
4041
"src\\Sentry.Android.AssemblyReader\\Sentry.Android.AssemblyReader.csproj",
41-
"src\\Sentry.AspNet\\Sentry.AspNet.csproj",
4242
"src\\Sentry.AspNetCore.Blazor.WebAssembly\\Sentry.AspNetCore.Blazor.WebAssembly.csproj",
4343
"src\\Sentry.AspNetCore.Grpc\\Sentry.AspNetCore.Grpc.csproj",
4444
"src\\Sentry.AspNetCore\\Sentry.AspNetCore.csproj",
45+
"src\\Sentry.AspNet\\Sentry.AspNet.csproj",
4546
"src\\Sentry.Azure.Functions.Worker\\Sentry.Azure.Functions.Worker.csproj",
4647
"src\\Sentry.Bindings.Android\\Sentry.Bindings.Android.csproj",
4748
"src\\Sentry.Bindings.Cocoa\\Sentry.Bindings.Cocoa.csproj",
@@ -58,6 +59,7 @@
5859
"src\\Sentry.Profiling\\Sentry.Profiling.csproj",
5960
"src\\Sentry.Serilog\\Sentry.Serilog.csproj",
6061
"src\\Sentry.SourceGenerators\\Sentry.SourceGenerators.csproj",
62+
"src\\Sentry.Sqlite\\Sentry.Sqlite.csproj",
6163
"src\\Sentry\\Sentry.csproj",
6264
"test\\Sentry.Analyzers.Tests\\Sentry.Analyzers.Tests.csproj",
6365
"test\\Sentry.Android.AssemblyReader.Tests\\Sentry.Android.AssemblyReader.Tests.csproj",
@@ -87,4 +89,4 @@
8789
"test\\SingleFileTestApp\\SingleFileTestApp.csproj"
8890
]
8991
}
90-
}
92+
}

Sentry.sln

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.SourceGenerators.Tes
209209
EndProject
210210
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}"
211211
EndProject
212+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Sqlite", "src\Sentry.Sqlite\Sentry.Sqlite.csproj", "{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}"
213+
EndProject
214+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sentry.Samples.Sqlite", "samples\Sentry.Samples.Sqlite\Sentry.Samples.Sqlite.csproj", "{BB4FF3AE-C835-41AB-8F75-1611977BCF71}"
215+
EndProject
212216
Global
213217
GlobalSection(SolutionConfigurationPlatforms) = preSolution
214218
Debug|Any CPU = Debug|Any CPU
@@ -1252,6 +1256,30 @@ Global
12521256
{ADC91A84-6054-42EC-8241-0D717E4C7194}.Release|x64.Build.0 = Release|Any CPU
12531257
{ADC91A84-6054-42EC-8241-0D717E4C7194}.Release|x86.ActiveCfg = Release|Any CPU
12541258
{ADC91A84-6054-42EC-8241-0D717E4C7194}.Release|x86.Build.0 = Release|Any CPU
1259+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1260+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|Any CPU.Build.0 = Debug|Any CPU
1261+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|x64.ActiveCfg = Debug|Any CPU
1262+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|x64.Build.0 = Debug|Any CPU
1263+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|x86.ActiveCfg = Debug|Any CPU
1264+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Debug|x86.Build.0 = Debug|Any CPU
1265+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|Any CPU.ActiveCfg = Release|Any CPU
1266+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|Any CPU.Build.0 = Release|Any CPU
1267+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|x64.ActiveCfg = Release|Any CPU
1268+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|x64.Build.0 = Release|Any CPU
1269+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|x86.ActiveCfg = Release|Any CPU
1270+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912}.Release|x86.Build.0 = Release|Any CPU
1271+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1272+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|Any CPU.Build.0 = Debug|Any CPU
1273+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|x64.ActiveCfg = Debug|Any CPU
1274+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|x64.Build.0 = Debug|Any CPU
1275+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|x86.ActiveCfg = Debug|Any CPU
1276+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Debug|x86.Build.0 = Debug|Any CPU
1277+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|Any CPU.ActiveCfg = Release|Any CPU
1278+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|Any CPU.Build.0 = Release|Any CPU
1279+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|x64.ActiveCfg = Release|Any CPU
1280+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|x64.Build.0 = Release|Any CPU
1281+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|x86.ActiveCfg = Release|Any CPU
1282+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71}.Release|x86.Build.0 = Release|Any CPU
12551283
EndGlobalSection
12561284
GlobalSection(SolutionProperties) = preSolution
12571285
HideSolutionNode = FALSE
@@ -1343,5 +1371,7 @@ Global
13431371
{C3CDF61C-3E28-441C-A9CE-011C89D11719} = {230B9384-90FD-4551-A5DE-1A5C197F25B6}
13441372
{3A76FF7D-2F32-4EA5-8999-2FFE3C7CB893} = {6987A1CC-608E-4868-A02C-09D30C8B7B2D}
13451373
{ADC91A84-6054-42EC-8241-0D717E4C7194} = {6987A1CC-608E-4868-A02C-09D30C8B7B2D}
1374+
{CDCCB2EC-9DA8-4CBE-94D6-00EAB990D912} = {230B9384-90FD-4551-A5DE-1A5C197F25B6}
1375+
{BB4FF3AE-C835-41AB-8F75-1611977BCF71} = {21B42F60-5802-404E-90F0-AEBCC56760C0}
13461376
EndGlobalSection
13471377
EndGlobal
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.IO;
3+
using Microsoft.Data.Sqlite;
4+
using Sentry.Sqlite;
5+
6+
SentrySdk.Init(options =>
7+
{
8+
#if !SENTRY_DSN_DEFINED_IN_ENV
9+
// A DSN is required. You can set here in code, or you can set it in the SENTRY_DSN environment variable.
10+
// See https://docs.sentry.io/product/sentry-basics/dsn-explainer/
11+
options.Dsn = SamplesShared.Dsn;
12+
#endif
13+
options.Debug = false;
14+
options.TracesSampleRate = 1.0;
15+
});
16+
17+
using (var connection = new SentrySqliteConnection("Data Source=hello.db"))
18+
{
19+
connection.Open();
20+
21+
var command = connection.CreateCommand();
22+
command.CommandText =
23+
@"
24+
CREATE TABLE user (
25+
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
26+
name TEXT NOT NULL
27+
);
28+
29+
INSERT INTO user
30+
VALUES (1, 'Brice'),
31+
(2, 'Alexander'),
32+
(3, 'Nate');
33+
";
34+
command.ExecuteNonQuery();
35+
36+
Console.Write("Name: ");
37+
var name = Console.ReadLine();
38+
39+
#region snippet_Parameter
40+
command.CommandText =
41+
@"
42+
INSERT INTO user (name)
43+
VALUES ($name)
44+
";
45+
command.Parameters.AddWithValue("$name", name);
46+
#endregion
47+
command.ExecuteNonQuery();
48+
49+
command.CommandText =
50+
@"
51+
SELECT last_insert_rowid()
52+
";
53+
var newId = (long)command.ExecuteScalar()!;
54+
55+
Console.WriteLine($"Your new user ID is {newId}.");
56+
}
57+
58+
Console.Write("User ID: ");
59+
var id = int.Parse(Console.ReadLine()!);
60+
61+
#region snippet_HelloWorld
62+
using (var connection = new SqliteConnection("Data Source=hello.db"))
63+
{
64+
connection.Open();
65+
66+
var command = connection.CreateCommand();
67+
command.CommandText =
68+
@"
69+
SELECT name
70+
FROM user
71+
WHERE id = $id
72+
";
73+
command.Parameters.AddWithValue("$id", id);
74+
75+
using (var reader = command.ExecuteReader())
76+
{
77+
while (reader.Read())
78+
{
79+
var name = reader.GetString(0);
80+
81+
Console.WriteLine($"Hello, {name}!");
82+
}
83+
}
84+
}
85+
#endregion
86+
87+
// Clean up
88+
SqliteConnection.ClearAllPools();
89+
File.Delete("hello.db");
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.6" />
12+
<PackageReference Include="SQLitePCLRaw.core" Version="2.1.11" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\..\src\Sentry.Sqlite\Sentry.Sqlite.csproj" />
17+
</ItemGroup>
18+
19+
</Project>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<Description>Experimental Microsoft.Data.Sqlite integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time.</Description>
8+
<PackageTags>$(PackageTags);Sqlite</PackageTags>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<ProjectReference Include="..\Sentry\Sentry.csproj" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.6" />
17+
<PackageReference Include="SQLitePCLRaw.core" Version="2.1.11" />
18+
</ItemGroup>
19+
20+
</Project>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Microsoft.Data.Sqlite;
2+
3+
namespace Sentry.Sqlite;
4+
5+
/// <inheritdoc cref="SqliteCommand"/>
6+
public class SentrySqliteCommand : SqliteCommand
7+
{
8+
internal ITransactionTracer? TransactionTracer { get; set; } = null;
9+
10+
/// <inheritdoc cref="SqliteCommand.ExecuteNonQuery"/>
11+
public override int ExecuteNonQuery()
12+
{
13+
var span = TransactionTracer?.StartChild("db.query", this.CommandText);
14+
try
15+
{
16+
return base.ExecuteNonQuery();
17+
}
18+
finally
19+
{
20+
span?.Finish();
21+
}
22+
}
23+
24+
/// <inheritdoc cref="SqliteCommand.ExecuteScalar"/>
25+
public override object? ExecuteScalar()
26+
{
27+
var span = TransactionTracer?.StartChild("db.query", this.CommandText);
28+
try
29+
{
30+
return base.ExecuteScalar();
31+
}
32+
finally
33+
{
34+
span?.Finish();
35+
}
36+
}
37+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System.Data.Common;
2+
using Microsoft.Data.Sqlite;
3+
4+
namespace Sentry.Sqlite;
5+
6+
/// <inheritdoc cref="SqliteConnection"/>
7+
public class SentrySqliteConnection : SqliteConnection
8+
{
9+
private ITransactionTracer? TransactionTracer { get; set; } = null;
10+
11+
/// <summary>
12+
/// Initializes a new instance of the <see cref="SentrySqliteConnection" /> class.
13+
/// </summary>
14+
/// <param name="connectionString">The string used to open the connection.</param>
15+
/// <seealso href="https://docs.microsoft.com/dotnet/standard/data/sqlite/connection-strings">Connection Strings</seealso>
16+
/// <seealso cref="SqliteConnectionStringBuilder" />
17+
public SentrySqliteConnection(string? connectionString) : base(connectionString)
18+
{
19+
}
20+
21+
/// <inheritdoc cref="SqliteConnection.Open"/>
22+
public override void Open()
23+
{
24+
TransactionTracer = SentrySdk.StartTransaction(
25+
"Open SQLite Connection",
26+
"db.sqlite.open"
27+
);
28+
base.Open();
29+
}
30+
31+
/// <inheritdoc cref="SqliteConnection.CreateCommand"/>
32+
public new virtual SentrySqliteCommand CreateCommand()
33+
=> new()
34+
{
35+
Connection = this,
36+
CommandTimeout = DefaultTimeout,
37+
Transaction = Transaction,
38+
TransactionTracer = TransactionTracer
39+
};
40+
41+
/// <inheritdoc cref="SqliteConnection.CreateDbCommand"/>
42+
protected override DbCommand CreateDbCommand()
43+
=> CreateCommand();
44+
45+
/// <inheritdoc cref="SqliteConnection.Close"/>
46+
public override void Close()
47+
{
48+
base.Close();
49+
TransactionTracer?.Finish();
50+
TransactionTracer = null;
51+
}
52+
}

0 commit comments

Comments
 (0)