Skip to content

Commit

Permalink
Refactor code
Browse files Browse the repository at this point in the history
  • Loading branch information
saleem-mirza committed Jul 3, 2018
1 parent d68b8ec commit 6ea67f8
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 102 deletions.
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ deploy:
secure: 3ysm3o1yzrnGt77dtYnAwQGR+XPT4Kuyjh9MuB9IrhQ/s+TE30X6v9LhRD1f7PVr
skip_symbols: true
on:
branch: /^(master|dev)$/
branch: /^(master)$/
26 changes: 12 additions & 14 deletions src/Serilog.Sinks.SQLite/LoggerConfigurationSQLiteExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public static class LoggerConfigurationSQLiteExtensions
/// <param name="restrictedToMinimumLevel">The minimum log event level required in order to write an event to the sink.</param>
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
/// <param name="storeTimestampInUtc">Store timestamp in UTC format</param>
/// <param name="retentionPeriod">The maximum time that a log entry will be kept in the database, or null to disable automatic deletion of old log entries. Non-null values smaller than 1 minute will be replaced with 1 minute.</param>
/// <param name="retentionPeriod">The maximum time that a log entry will be kept in the database, or null to disable automatic deletion of old log entries. Non-null values smaller than 30 minute will be replaced with 30 minute.</param>
/// <param name="retentionCheckInterval">Time period to execute TTL process. Time span should be in 15 minutes increment</param>
/// <exception cref="ArgumentNullException">A required parameter is null.</exception>
public static LoggerConfiguration SQLite(
this LoggerSinkConfiguration loggerConfiguration,
Expand All @@ -48,32 +49,29 @@ public static LoggerConfiguration SQLite(
TimeSpan? retentionPeriod = null,
TimeSpan? retentionCheckInterval = null)
{
if (loggerConfiguration == null)
{
if (loggerConfiguration == null) {
SelfLog.WriteLine("Logger configuration is null");

throw new ArgumentNullException(nameof(loggerConfiguration));
}

if (string.IsNullOrEmpty(sqliteDbPath))
{
if (string.IsNullOrEmpty(sqliteDbPath)) {
SelfLog.WriteLine("Invalid sqliteDbPath");

throw new ArgumentNullException(nameof(sqliteDbPath));
}

Uri sqliteDbPathUri;
if (!Uri.TryCreate(sqliteDbPath, UriKind.RelativeOrAbsolute, out sqliteDbPathUri))
{
if (!Uri.TryCreate(sqliteDbPath, UriKind.RelativeOrAbsolute, out sqliteDbPathUri)) {
throw new ArgumentException($"Invalid path {nameof(sqliteDbPath)}");
}

if (!sqliteDbPathUri.IsAbsoluteUri)
{
if (!sqliteDbPathUri.IsAbsoluteUri) {
var basePath = System.Reflection.Assembly.GetEntryAssembly().Location;
sqliteDbPath = Path.Combine(Path.GetDirectoryName(basePath), sqliteDbPath);
}

try
{
try {
var sqliteDbFile = new FileInfo(sqliteDbPath);
sqliteDbFile.Directory?.Create();

Expand All @@ -87,11 +85,11 @@ public static LoggerConfiguration SQLite(
retentionCheckInterval),
restrictedToMinimumLevel);
}
catch (Exception ex)
{
catch (Exception ex) {
SelfLog.WriteLine(ex.Message);

throw;
}
}
}
}
}
64 changes: 28 additions & 36 deletions src/Serilog.Sinks.SQLite/Serilog.Sinks.SQLite.csproj
Original file line number Diff line number Diff line change
@@ -1,37 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<AssemblyTitle>Serilog.Sinks.SQLite</AssemblyTitle>
<Authors>Saleem Mirza</Authors>
<AssemblyName>Serilog.Sinks.SQLite</AssemblyName>
<Description>Serilog event sink that writes to SQLite database</Description>
<PackageId>Serilog.Sinks.SQLite</PackageId>
<PackageTags>serilog;logging;SQLite</PackageTags>
<PackageIconUrl>http://serilog.net/images/serilog-sink-nuget.png</PackageIconUrl>
<PackageProjectUrl>http://serilog.net</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<Copyright>Copyright © Zethian Inc. 2013-2017</Copyright>
<AssemblyVersion>3.9.1.0</AssemblyVersion>
<Version>3.9.1</Version>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>Serilog.snk</AssemblyOriginatorKeyFile>
<TargetFrameworks>netstandard2.0;net452</TargetFrameworks>
<FileVersion>3.9.1.0</FileVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(VersionSuffix)'!='' ">
<Version>$(Version)-$(VersionSuffix)</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Serilog" Version="2.7.1" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.108" />
</ItemGroup>

<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>

</Project>
<PropertyGroup>
<AssemblyTitle>Serilog.Sinks.SQLite</AssemblyTitle>
<Authors>Saleem Mirza</Authors>
<AssemblyName>Serilog.Sinks.SQLite</AssemblyName>
<Description>Serilog event sink that writes to SQLite database</Description>
<PackageId>Serilog.Sinks.SQLite</PackageId>
<PackageTags>serilog;logging;SQLite</PackageTags>
<PackageIconUrl>http://serilog.net/images/serilog-sink-nuget.png</PackageIconUrl>
<PackageProjectUrl>http://serilog.net</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<Copyright>Copyright © Zethian Inc. 2013-2017</Copyright>
<AssemblyVersion>4.0.0.0</AssemblyVersion>
<Version>4.0.0</Version>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>Serilog.snk</AssemblyOriginatorKeyFile>
<TargetFrameworks>netstandard2.0;net452</TargetFrameworks>
<FileVersion>4.0.0.0</FileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(VersionSuffix)'!='' ">
<Version>$(Version)-$(VersionSuffix)</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Serilog" Version="2.7.1" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.108" />
</ItemGroup>
</Project>
100 changes: 49 additions & 51 deletions src/Serilog.Sinks.SQLite/Sinks/SQLite/SQLiteSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using System.Linq;
using Serilog.Sinks.Extensions;
using System.Data.SQLite;
using System.Threading;

namespace Serilog.Sinks.SQLite
{
Expand All @@ -33,35 +34,46 @@ internal class SQLiteSink : BatchProvider, ILogEventSink
private readonly bool _storeTimestampInUtc;
private readonly string _tableName;
private readonly TimeSpan? _retentionPeriod;
private readonly Stopwatch _retentionWatch = new Stopwatch();
private readonly TimeSpan? _retentionCheckInterval;
private readonly Timer _retentionTimer;

public SQLiteSink(string sqlLiteDbPath,
public SQLiteSink(
string sqlLiteDbPath,
string tableName,
IFormatProvider formatProvider,
bool storeTimestampInUtc,
TimeSpan? retentionPeriod,
TimeSpan? retentionCheckInterval)
{
_connString = CreateConnectionString(sqlLiteDbPath);
_tableName = tableName;
_formatProvider = formatProvider;
_connString = CreateConnectionString(sqlLiteDbPath);
_tableName = tableName;
_formatProvider = formatProvider;
_storeTimestampInUtc = storeTimestampInUtc;

if (retentionPeriod.HasValue)
{
// impose a min retention period of 1 minute
_retentionPeriod = new[] { retentionPeriod.Value, TimeSpan.FromMinutes(1) }.Max();
if (retentionPeriod.HasValue) {
// impose a min retention period of 15 minute
var retentionCheckMinutes = 15;
if (retentionCheckInterval.HasValue) {
retentionCheckMinutes = Math.Max(retentionCheckMinutes, retentionCheckInterval.Value.Minutes);
}

// impose multiple of 15 minute interval
retentionCheckMinutes = (retentionCheckMinutes / 15) * 15;

_retentionPeriod = new[] {retentionPeriod, TimeSpan.FromMinutes(30)}.Max();

// check for retention at this interval - or use retentionPeriod if not specified
_retentionCheckInterval = retentionCheckInterval ?? _retentionPeriod.Value;
_retentionTimer = new Timer(
(x) => { ApplyRetentionPolicy(); },
null,
TimeSpan.FromMinutes(0),
TimeSpan.FromMinutes(retentionCheckMinutes));
}

InitializeDatabase();
}

private static string CreateConnectionString(string dbPath) =>
new SQLiteConnectionStringBuilder { DataSource = dbPath }.ConnectionString;
new SQLiteConnectionStringBuilder {DataSource = dbPath}.ConnectionString;

#region ILogEvent implementation

Expand All @@ -82,6 +94,7 @@ private SQLiteConnection GetSqLiteConnection()
{
var sqlConnection = new SQLiteConnection(_connString);
sqlConnection.Open();

return sqlConnection;
}

Expand All @@ -104,7 +117,7 @@ private SQLiteCommand CreateSqlInsertCommand(SQLiteConnection connection)
{
var sqlInsertText = "INSERT INTO {0} (Timestamp, Level, Exception, RenderedMessage, Properties)";
sqlInsertText += " VALUES (@timeStamp, @level, @exception, @renderedMessage, @properties)";
sqlInsertText = string.Format(sqlInsertText, _tableName);
sqlInsertText = string.Format(sqlInsertText, _tableName);

var sqlCommand = connection.CreateCommand();
sqlCommand.CommandText = sqlInsertText;
Expand All @@ -123,25 +136,20 @@ protected override void WriteLogEvent(ICollection<LogEvent> logEventsBatch)
{
if ((logEventsBatch == null) || (logEventsBatch.Count == 0))
return;
try
{
using (var sqlConnection = GetSqLiteConnection())
{
ApplyRetentionPolicy(sqlConnection);

using (var tr = sqlConnection.BeginTransaction())
{
using (var sqlCommand = CreateSqlInsertCommand(sqlConnection))
{
try {
using (var sqlConnection = GetSqLiteConnection()) {
using (var tr = sqlConnection.BeginTransaction()) {
using (var sqlCommand = CreateSqlInsertCommand(sqlConnection)) {
sqlCommand.Transaction = tr;

foreach (var logEvent in logEventsBatch)
{
foreach (var logEvent in logEventsBatch) {
sqlCommand.Parameters["@timeStamp"].Value = _storeTimestampInUtc
? logEvent.Timestamp.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss")
: logEvent.Timestamp.ToString("yyyy-MM-ddTHH:mm:ss");
sqlCommand.Parameters["@level"].Value = logEvent.Level.ToString();
sqlCommand.Parameters["@exception"].Value = logEvent.Exception?.ToString() ?? string.Empty;
sqlCommand.Parameters["@exception"].Value =
logEvent.Exception?.ToString() ?? string.Empty;
sqlCommand.Parameters["@renderedMessage"].Value = logEvent.MessageTemplate.ToString();

sqlCommand.Parameters["@properties"].Value = logEvent.Properties.Count > 0
Expand All @@ -151,51 +159,41 @@ protected override void WriteLogEvent(ICollection<LogEvent> logEventsBatch)
sqlCommand.ExecuteNonQuery();
}
}

tr.Commit();
}

sqlConnection.Close();
}
}
catch (Exception e)
{
catch (Exception e) {
SelfLog.WriteLine(e.Message);
}
}

private void ApplyRetentionPolicy(SQLiteConnection sqlConnection)
private void ApplyRetentionPolicy()
{
if (!_retentionPeriod.HasValue)
// there is no retention policy
return;

if (_retentionWatch.IsRunning && _retentionWatch.Elapsed < _retentionCheckInterval.Value)
// Besides deleting records older than X
// let's only delete records every X often
// because of the check whether the _retentionWatch is running,
// the first write operation during this application run
// will result in deleting old records
return;

var epoch = DateTimeOffset.Now.Subtract(_retentionPeriod.Value);
using (var cmd = CreateSqlDeleteCommand(sqlConnection, epoch))
{
SelfLog.WriteLine("Deleting log entries older than {0}", epoch);
cmd.ExecuteNonQuery();
using (var sqlConnection = GetSqLiteConnection()) {
using (var cmd = CreateSqlDeleteCommand(sqlConnection, epoch)) {
SelfLog.WriteLine("Deleting log entries older than {0}", epoch);
var ret = cmd.ExecuteNonQuery();
SelfLog.WriteLine($"{ret} records deleted");
}
}

_retentionWatch.Restart();
}

private SQLiteCommand CreateSqlDeleteCommand(SQLiteConnection sqlConnection, DateTimeOffset epoch)
{
var cmd = sqlConnection.CreateCommand();
cmd.CommandText = $"DELETE FROM {_tableName} WHERE Timestamp < @epoch";
cmd.Parameters.Add(new SQLiteParameter("@epoch", DbType.DateTime2)
{
Value = (_storeTimestampInUtc ? epoch.ToUniversalTime() : epoch).ToString("yyyy-MM-ddTHH:mm:ss")
});
cmd.Parameters.Add(
new SQLiteParameter("@epoch", DbType.DateTime2)
{
Value = (_storeTimestampInUtc ? epoch.ToUniversalTime() : epoch).ToString("yyyy-MM-ddTHH:mm:ss")
});

return cmd;
}
}
}
}

0 comments on commit 6ea67f8

Please sign in to comment.