Skip to content

Commit

Permalink
Merge pull request #19 from engineering87/develop
Browse files Browse the repository at this point in the history
Ensure Trace table creation | Async Dequeue
  • Loading branch information
engineering87 authored Oct 23, 2024
2 parents 717e633 + 7193da9 commit 79e26cf
Show file tree
Hide file tree
Showing 18 changed files with 109 additions and 94 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ The following is the table creation script:
```tsql
CREATE TABLE [dbo].[Trace](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[TransactionId] [nvarchar](36) NULL,
[TransactionId] [nvarchar](MAX) NULL,
[ServerId] [nvarchar](MAX) NULL,
[ClientId] [nvarchar](MAX) NULL,
[HttpMethod] [nvarchar](7) NULL,
Expand All @@ -114,6 +114,7 @@ CREATE TABLE [dbo].[Trace](
[ExecutionTime] [numeric] NULL,
) ON [PRIMARY]
```
From version 4.1.0 onwards, table creation is handled automatically, in case it is missing on the SQL instance.

Remember to populate the **TraceDb** key within the SQL connection strings config file:

Expand Down
5 changes: 3 additions & 2 deletions src/OpenSharpTrace.Test/SQL/TraceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;

namespace OpenSharpTrace.Test.SQL
{
Expand All @@ -34,7 +35,7 @@ public void Setup()
}

[Test]
public void CanAddManyTrace()
public async Task CanAddManyTrace()
{
var db = GetMemoryContext();
var traceFirst = new Trace
Expand Down Expand Up @@ -63,7 +64,7 @@ public void CanAddManyTrace()
};
var processor = new SqlTraceRepository(NullLoggerFactory.Instance, db);

Assert.DoesNotThrow(() => processor.InsertMany(new List<Trace> { traceFirst, traceSecond }));
Assert.DoesNotThrowAsync(() => processor.InsertManyAsync(new List<Trace> { traceFirst, traceSecond }));
}

public static TraceContext GetMemoryContext()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Microsoft.AspNetCore.Mvc;
// (c) 2022 Francesco Del Re <francesco.delre.87@gmail.com>
// This code is licensed under MIT license (see LICENSE.txt for details)
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using OpenSharpTrace.Controllers;
using OpenSharpTrace.Persistence.SQL.Entities;
using OpenSharpTrace.TraceQueue;
using OpenSharpTrace.TransactionQueue;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down
8 changes: 7 additions & 1 deletion src/OpenSharpTrace.TestApi/OpenSharpTrace.TestApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@

<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.8.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\OpenSharpTrace\OpenSharpTrace.csproj" />
</ItemGroup>

<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>

</Project>
8 changes: 2 additions & 6 deletions src/OpenSharpTrace.TestApi/Program.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
// (c) 2022 Francesco Del Re <francesco.delre.87@gmail.com>
// This code is licensed under MIT license (see LICENSE.txt for details)
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace OpenSharpTrace.TestApi
{
Expand Down
3 changes: 3 additions & 0 deletions src/OpenSharpTrace.TestApi/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// (c) 2022 Francesco Del Re <francesco.delre.87@gmail.com>
// This code is licensed under MIT license (see LICENSE.txt for details)
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
Expand Down Expand Up @@ -26,6 +28,7 @@ public void ConfigureServices(IServiceCollection services)
c.SwaggerDoc("v1", new OpenApiInfo { Title = "OpenSharpTrace.TestApi", Version = "v1" });
});

// Register the OpenSharpTrace
services.RegisterOpenSharpTrace();
}

Expand Down
2 changes: 2 additions & 0 deletions src/OpenSharpTrace.TestApi/WeatherForecast.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// (c) 2022 Francesco Del Re <francesco.delre.87@gmail.com>
// This code is licensed under MIT license (see LICENSE.txt for details)
using System;

namespace OpenSharpTrace.TestApi
Expand Down
4 changes: 3 additions & 1 deletion src/OpenSharpTrace.TestApi/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"ConnectionStrings": {
"TraceDb": "Server=(***;Database=***;Trusted_Connection=True;MultipleActiveResultSets=true"
//"TraceDb": "Server=(***;Database=***;Trusted_Connection=True;MultipleActiveResultSets=true"
"TraceDb": "Server=ccsint.database.windows.net,1433;Initial Catalog=DS05084_TIS_CIGO;User ID=almavivasa;Password=CIGDev2021!/*",
//"DefaultConnection": "Server=ccsint.database.windows.net,1433;Initial Catalog=DS05084_TIS_CIGO;User ID=almavivasa;Password=CIGDev2021!/*"
},
"Logging": {
"LogLevel": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
// This code is licensed under MIT license (see LICENSE.txt for details)
using OpenSharpTrace.Persistence.SQL.Entities;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace OpenSharpTrace.Abstractions.Persistence
{
public interface ISqlTraceRepository
{
void InsertMany(List<Trace> entity);
Task InsertManyAsync(List<Trace> entity);
}
}
2 changes: 1 addition & 1 deletion src/OpenSharpTrace/Controllers/OpenSharpTraceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using OpenSharpTrace.Persistence.SQL.Entities;
using OpenSharpTrace.TraceQueue;
using OpenSharpTrace.TransactionQueue;
using OpenSharpTrace.Utilities;
using System;
using System.Linq;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
using OpenSharpTrace.Abstractions.Persistence;
using OpenSharpTrace.Persistence.SQL;
using OpenSharpTrace.Persistence.SQL.Entities;
using OpenSharpTrace.TraceQueue;
using OpenSharpTrace.TransactionQueue;
using OpenSharpTrace.TransactionScheduler;
using System;
using System.IO;

namespace OpenSharpTrace.Middleware
Expand All @@ -22,19 +23,25 @@ public static void RegisterOpenSharpTrace(this IServiceCollection collection)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile("appsettings.json", false, true)
.AddEnvironmentVariables()
.Build();

collection.AddScoped<ISqlTraceRepository, SqlTraceRepository>();
var connectionString = configuration.GetConnectionString("TraceDb");
if (string.IsNullOrEmpty(connectionString))
{
throw new InvalidOperationException("The connection string 'TraceDb' is not configured.");
}

collection.AddDbContext<TraceContext>(options =>
{
options.UseSqlServer(configuration.GetConnectionString("TraceDb"),
options.UseSqlServer(connectionString,
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure();
});
});
collection.AddScoped<ISqlTraceRepository, SqlTraceRepository>();
collection.AddSingleton<ITraceQueue<Trace>, TraceQueue<Trace>>();
collection.AddSingleton<ServiceTransaction>();
collection.AddHostedService<ScheduledServiceTransaction>();
Expand All @@ -49,19 +56,25 @@ public static void RegisterOpenSharpTrace(this IServiceCollection collection, st
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile("appsettings.json", false, true)
.AddEnvironmentVariables()
.Build();

collection.AddScoped<ISqlTraceRepository, SqlTraceRepository>();
var connectionString = configuration.GetConnectionString(connectionKey);
if (string.IsNullOrEmpty(connectionString))
{
throw new InvalidOperationException($"The connection string '{connectionKey}' is not configured.");
}

collection.AddDbContext<TraceContext>(options =>
{
options.UseSqlServer(configuration.GetConnectionString(connectionKey),
options.UseSqlServer(connectionString,
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure();
});
});
collection.AddScoped<ISqlTraceRepository, SqlTraceRepository>();
collection.AddSingleton<ITraceQueue<Trace>, TraceQueue<Trace>>();
collection.AddSingleton<ServiceTransaction>();
collection.AddHostedService<ScheduledServiceTransaction>();
Expand All @@ -77,19 +90,25 @@ public static void RegisterOpenSharpTrace(this IServiceCollection collection, st
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(jsonFileName, true, true)
.AddJsonFile(jsonFileName, false, true)
.AddEnvironmentVariables()
.Build();

collection.AddScoped<ISqlTraceRepository, SqlTraceRepository>();
var connectionString = configuration.GetConnectionString(connectionKey);
if (string.IsNullOrEmpty(connectionString))
{
throw new InvalidOperationException($"The connection string '{connectionKey}' is not configured.");
}

collection.AddDbContext<TraceContext>(options =>
{
options.UseSqlServer(configuration.GetConnectionString(connectionKey),
options.UseSqlServer(connectionString,
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure();
});
});
collection.AddScoped<ISqlTraceRepository, SqlTraceRepository>();
collection.AddSingleton<ITraceQueue<Trace>, TraceQueue<Trace>>();
collection.AddSingleton<ServiceTransaction>();
collection.AddHostedService<ScheduledServiceTransaction>();
Expand Down
2 changes: 1 addition & 1 deletion src/OpenSharpTrace/Persistence/SQL/Scripts/CreateTable.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CREATE TABLE [dbo].[Trace](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[TransactionId] [nvarchar](36) NULL,
[TransactionId] [nvarchar](MAX) NULL,
[ServerId] [nvarchar](MAX) NULL,
[ClientId] [nvarchar](MAX) NULL,
[HttpMethod] [nvarchar](7) NULL,
Expand Down
27 changes: 17 additions & 10 deletions src/OpenSharpTrace/Persistence/SQL/SqlTraceRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using OpenSharpTrace.Persistence.SQL.Entities;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace OpenSharpTrace.Persistence.SQL
{
Expand All @@ -20,12 +21,12 @@ public SqlTraceRepository(ILoggerFactory loggerFactory, TraceContext context)
_context = context ?? throw new ArgumentNullException(nameof(context));
_logger = loggerFactory.CreateLogger(GetType().ToString());
}

/// <summary>
/// Write the current trace entities
/// </summary>
/// <param name="entities"></param>
public void InsertMany(List<Trace> entities)
public async Task InsertManyAsync(List<Trace> entities)
{
if (entities == null || entities.Count == 0)
{
Expand All @@ -36,22 +37,28 @@ public void InsertMany(List<Trace> entities)
{
var strategy = _context.Database.CreateExecutionStrategy();

strategy.Execute(() =>
await strategy.ExecuteAsync(async () =>
{
using (var transaction = _context.Database.BeginTransaction())
using (var transaction = await _context.Database.BeginTransactionAsync())
{
foreach (var entity in entities)
try
{
await _context.Trace.AddRangeAsync(entities);
await _context.SaveChangesAsync();
await transaction.CommitAsync();
}
catch (Exception ex)
{
_context.Trace.Add(entity);
_logger?.LogError(ex, "An error occurred while committing the transaction.");
await transaction.RollbackAsync();
throw;
}
_context.SaveChanges();
transaction.Commit();
}
}
});
}
catch (Exception ex)
{
_logger?.LogError(ex.Message);
_logger?.LogError(ex, "An error occurred while inserting trace entities.");
}
}
}
Expand Down
75 changes: 25 additions & 50 deletions src/OpenSharpTrace/Persistence/SQL/TraceContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ namespace OpenSharpTrace.Persistence.SQL
{
public class TraceContext : DbContext, IDisposable
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
}

public TraceContext(DbContextOptions options)
: base(options)
{
Expand All @@ -29,55 +25,34 @@ public TraceContext(DbContextOptions options)

public virtual DbSet<Trace> Trace { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}

private void EnsureTraceTableExists()
{
using (var connection = Database.GetDbConnection())
try
{
try
{
if (connection.State != System.Data.ConnectionState.Open)
{
connection.Open();
}

using (var command = connection.CreateCommand())
{
command.CommandText = @"
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Trace')
BEGIN
CREATE TABLE [dbo].[Trace](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[TransactionId] [nvarchar](36) NULL,
[ServerId] [nvarchar](MAX) NULL,
[ClientId] [nvarchar](MAX) NULL,
[HttpMethod] [nvarchar](7) NULL,
[HttpPath] [nvarchar](MAX) NULL,
[HttpStatusCode] [int] NULL,
[ActionDescriptor] [nvarchar](MAX) NULL,
[RemoteAddress] [nvarchar](MAX) NULL,
[JsonRequest] [nvarchar](MAX) NULL,
[JsonResponse] [nvarchar](MAX) NULL,
[TimeStamp] [datetime2](7) NULL,
[Exception] [nvarchar](MAX) NULL,
[ExecutionTime] [numeric] NULL,
) ON [PRIMARY];
END";
command.ExecuteNonQuery();
}
}
catch
{
// database is not ready or the connectionstring is wrong
}
finally
{
connection.Close();
}
Database.ExecuteSqlRaw(@"
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Trace')
BEGIN
CREATE TABLE [dbo].[Trace](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[TransactionId] [nvarchar](MAX) NULL,
[ServerId] [nvarchar](MAX) NULL,
[ClientId] [nvarchar](MAX) NULL,
[HttpMethod] [nvarchar](7) NULL,
[HttpPath] [nvarchar](MAX) NULL,
[HttpStatusCode] [int] NULL,
[ActionDescriptor] [nvarchar](MAX) NULL,
[RemoteAddress] [nvarchar](MAX) NULL,
[JsonRequest] [nvarchar](MAX) NULL,
[JsonResponse] [nvarchar](MAX) NULL,
[TimeStamp] [datetime2](7) NULL,
[Exception] [nvarchar](MAX) NULL,
[ExecutionTime] [numeric] NULL,
) ON [PRIMARY];
END");
}
catch
{
// database is not ready or the connectionstring is wrong
}
}
}
Expand Down
Loading

0 comments on commit 79e26cf

Please sign in to comment.