Skip to content

Commit

Permalink
fix: parsing error with sql logs
Browse files Browse the repository at this point in the history
  • Loading branch information
Joshua Searles committed Jan 13, 2024
1 parent 82507fc commit de8ac06
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 22 deletions.
50 changes: 33 additions & 17 deletions src/Elmah.AspNetCore.MsSql/SqlErrorLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace Elmah.AspNetCore.MsSql;
public class SqlErrorLog : ErrorLog
{
private const int MaxAppNameLength = 60;
private volatile bool _tableCreationChecked = false;

/// <summary>
/// Initializes a new instance of the <see cref="SqlErrorLog" /> class
Expand Down Expand Up @@ -52,10 +53,7 @@ public SqlErrorLog(string connectionString, string? schemaName, string? tableNam
DatabaseSchemaName = !string.IsNullOrWhiteSpace(schemaName) ? schemaName! : "dbo";
DatabaseTableName = !string.IsNullOrWhiteSpace(tableName) ? tableName! : "ELMAH_Error";

if (createTablesIfNotExist)
{
CreateTableIfNotExists();
}
_tableCreationChecked = !createTablesIfNotExist;
}

/// <summary>
Expand Down Expand Up @@ -83,6 +81,8 @@ public override async Task LogAsync(Error error, CancellationToken cancellationT
{
try
{
await this.EnsureTablesExistAsync(cancellationToken);

var errorXml = ErrorXml.EncodeString(error);

using var connection = new SqlConnection(ConnectionString);
Expand All @@ -101,14 +101,16 @@ public override async Task LogAsync(Error error, CancellationToken cancellationT

public override async Task<ErrorLogEntry?> GetErrorAsync(Guid id, CancellationToken cancellationToken)
{
await this.EnsureTablesExistAsync(cancellationToken);

string? errorXml;

using (var connection = new SqlConnection(ConnectionString))
using (var command = Commands.GetErrorXml(ApplicationName, id, DatabaseSchemaName, DatabaseTableName))
{
command.Connection = connection;
await connection.OpenAsync(cancellationToken);
errorXml = (string?)await command.ExecuteScalarAsync();
errorXml = (string?)await command.ExecuteScalarAsync(cancellationToken);
}

if (errorXml == null)
Expand All @@ -121,7 +123,7 @@ public override async Task LogAsync(Error error, CancellationToken cancellationT
}

public override async Task<int> GetErrorsAsync(ErrorLogFilterCollection filters, int errorIndex, int pageSize,
ICollection<ErrorLogEntry> errorEntryList, CancellationToken cancellation)
ICollection<ErrorLogEntry> errorEntryList, CancellationToken cancellationToken)
{
if (errorIndex < 0)
{
Expand All @@ -134,14 +136,14 @@ public override async Task<int> GetErrorsAsync(ErrorLogFilterCollection filters,
}

using var connection = new SqlConnection(ConnectionString);
await connection.OpenAsync();
await connection.OpenAsync(cancellationToken);

using (var command = Commands.GetErrorsXml(ApplicationName, errorIndex, pageSize, DatabaseSchemaName, DatabaseTableName))
{
command.Connection = connection;

using var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
using var reader = await command.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
var id = reader.GetGuid(0);
var xml = reader.GetString(1);
Expand All @@ -153,30 +155,37 @@ public override async Task<int> GetErrorsAsync(ErrorLogFilterCollection filters,
using (var command = Commands.GetErrorsXmlTotal(ApplicationName, DatabaseSchemaName, DatabaseTableName))
{
command.Connection = connection;
return (int)(await command.ExecuteScalarAsync())!;
return (int)(await command.ExecuteScalarAsync(cancellationToken))!;
}
}

/// <summary>
/// Creates the necessary tables and sequences used by this implementation
/// </summary>
private void CreateTableIfNotExists()
private async Task EnsureTablesExistAsync(CancellationToken cancellationToken)
{
if (_tableCreationChecked)
{
return;
}

_tableCreationChecked = true;

using var connection = new SqlConnection(ConnectionString);
connection.Open();
await connection.OpenAsync(cancellationToken);

using var cmdCheck = Commands.CheckTable(DatabaseSchemaName, DatabaseTableName);
cmdCheck.Connection = connection;

// ReSharper disable once PossibleNullReferenceException
var exists = (int?)cmdCheck.ExecuteScalar();
var exists = (int?)(await cmdCheck.ExecuteScalarAsync(cancellationToken));
if (!exists.HasValue)
{
ExecuteBatchNonQuery(Commands.CreateTableSql(DatabaseSchemaName, DatabaseTableName), connection);
await ExecuteBatchNonQueryAsync(Commands.CreateTableSql(DatabaseSchemaName, DatabaseTableName), connection, cancellationToken);
}
}

private void ExecuteBatchNonQuery(string sql, SqlConnection conn)
private async Task ExecuteBatchNonQueryAsync(string sql, SqlConnection conn, CancellationToken cancellationToken)
{
var sqlBatch = string.Empty;
using var cmd = new SqlCommand(string.Empty, conn);
Expand All @@ -187,7 +196,7 @@ private void ExecuteBatchNonQuery(string sql, SqlConnection conn)
if (line.ToUpperInvariant().Trim() == "GO")
{
cmd.CommandText = sqlBatch;
cmd.ExecuteNonQuery();
await cmd.ExecuteNonQueryAsync(cancellationToken);
sqlBatch = string.Empty;
}
else
Expand All @@ -203,6 +212,7 @@ public static string CreateTableSql(string schemaName, string tableName)
{
return
$@"
/* elmah */
CREATE TABLE [{schemaName}].[{tableName}]
(
[ErrorId] UNIQUEIDENTIFIER NOT NULL,
Expand All @@ -219,14 +229,17 @@ [AllXml] NVARCHAR(MAX) NOT NULL
)
GO
/* elmah */
ALTER TABLE [{schemaName}].[{tableName}] WITH NOCHECK ADD
CONSTRAINT [PK_{tableName}] PRIMARY KEY NONCLUSTERED ([ErrorId]) ON [PRIMARY]
GO
/* elmah */
ALTER TABLE [{schemaName}].[{tableName}] ADD
CONSTRAINT [DF_{tableName}_ErrorId] DEFAULT (NEWID()) FOR [ErrorId]
GO
/* elmah */
CREATE NONCLUSTERED INDEX [IX_{tableName}_App_Time_Seq] ON [{schemaName}].[{tableName}]
(
[Application] ASC,
Expand All @@ -241,6 +254,7 @@ public static SqlCommand CheckTable(string schemaName, string tableName)
var command = new SqlCommand
{
CommandText = $@"
/* elmah */
SELECT 1
WHERE EXISTS (
SELECT 1
Expand Down Expand Up @@ -298,6 +312,7 @@ public static SqlCommand GetErrorXml(
var command = new SqlCommand
{
CommandText = $@"
/* elmah */
SELECT AllXml FROM [{schemaName}].[{tableName}]
WHERE
Application = @Application
Expand All @@ -321,6 +336,7 @@ public static SqlCommand GetErrorsXml(
var command = new SqlCommand
{
CommandText = $@"
/* elmah */
SELECT ErrorId, AllXml FROM [{schemaName}].[{tableName}]
WHERE
Application = @Application
Expand All @@ -343,7 +359,7 @@ public static SqlCommand GetErrorsXmlTotal(string appName,
{
var command = new SqlCommand
{
CommandText = $"SELECT COUNT(*) FROM [{schemaName}].[{tableName}] WHERE Application = @Application"
CommandText = $"/* elmah */ SELECT COUNT(*) FROM [{schemaName}].[{tableName}] WHERE Application = @Application"
};
command.Parameters.Add("@Application", SqlDbType.NVarChar, MaxAppNameLength).Value = appName;
return command;
Expand Down
8 changes: 4 additions & 4 deletions src/Elmah.AspNetCore/ElmahSqlDiagnosticObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ public void OnNext(DiagnosticListener value)

private void OnCommandStart(Guid id, DbCommand cmd)
{
var context = this.GetElmahContext();
if (context is null)
string query = cmd.CommandText;
if (query.Contains("/* elmah */"))
{
return;
}

string query = cmd.CommandText;
if (query.Contains("/* elmah */"))
var context = this.GetElmahContext();
if (context is null)
{
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Elmah.Common/Xml/ErrorXml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ private static void UpcodeToSqlLog(XmlReader reader, ICollection<ElmahLogSqlEntr
CommandType = reader.GetAttribute("command-type"),
SqlText = reader.GetAttribute("sql-text"),
TimeStamp = LoadTime(reader.GetAttribute("time-stamp") ?? string.Empty),
DurationMs = int.Parse(reader.GetAttribute("duration") ?? "0")
DurationMs = double.Parse(reader.GetAttribute("duration") ?? "0")
};

log.Add(entry);
Expand Down

0 comments on commit de8ac06

Please sign in to comment.