Skip to content

Commit

Permalink
Merge pull request #66 from adamchester/configurable-locking
Browse files Browse the repository at this point in the history
User-configurable synchronized writes
  • Loading branch information
nblumhardt authored Nov 22, 2019
2 parents 70d892b + dc2c98e commit e83f2f3
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 13 deletions.
25 changes: 18 additions & 7 deletions Build.ps1
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
echo "build: Build started"
Write-Host "build: Build started"

Push-Location $PSScriptRoot

if(Test-Path .\artifacts) {
echo "build: Cleaning .\artifacts"
Write-Host "build: Cleaning .\artifacts"
Remove-Item .\artifacts -Force -Recurse
}

Expand All @@ -15,13 +15,13 @@ $suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch
$commitHash = $(git rev-parse --short HEAD)
$buildSuffix = @{ $true = "$($suffix)-$($commitHash)"; $false = "$($branch)-$($commitHash)" }[$suffix -ne ""]

echo "build: Package version suffix is $suffix"
echo "build: Build version suffix is $buildSuffix"
Write-Host "build: Package version suffix is $suffix"
Write-Host "build: Build version suffix is $buildSuffix"

foreach ($src in ls src/*) {
foreach ($src in Get-ChildItem src/*) {
Push-Location $src

echo "build: Packaging project in $src"
Write-Host "build: Packaging project in $src"

& dotnet build -c Release --version-suffix=$buildSuffix
if ($suffix) {
Expand All @@ -34,10 +34,21 @@ foreach ($src in ls src/*) {
Pop-Location
}

foreach ($sample in Get-ChildItem sample/*) {
Push-Location $sample

Write-Host "build: Testing project in $sample"

& dotnet build -c Release --version-suffix=$buildSuffix
if($LASTEXITCODE -ne 0) { exit 3 }

Pop-Location
}

foreach ($test in ls test/*.Tests) {
Push-Location $test

echo "build: Testing project in $test"
Write-Host "build: Testing project in $test"

& dotnet test -c Release
if($LASTEXITCODE -ne 0) { exit 3 }
Expand Down
57 changes: 57 additions & 0 deletions sample/SyncWritesDemo/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Serilog;
using Serilog.Sinks.SystemConsole.Themes;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace SyncWritesDemo
{
public static class Program
{
public static void Main(string[] args)
{
Console.WriteLine("A sample of how to sync writes to the console sink.");

if (args != null && args.Length == 1)
{
switch (args[0])
{
case "--sync-root-default":
SystemConsoleSyncTest(syncRootForLogger1: null, syncRootForLogger2: null);
return;
case "--sync-root-separate":
SystemConsoleSyncTest(syncRootForLogger1: new object(), syncRootForLogger2: new object());
return;
case "--sync-root-same":
var sameSyncRoot = new object();
SystemConsoleSyncTest(syncRootForLogger1: sameSyncRoot, syncRootForLogger2: sameSyncRoot);
return;
}
}

Console.WriteLine("Expecting one of the following arguments:{0}--sync-root-default{0}--sync-root-separate{0}--sync-root-same", Environment.NewLine);
}

static void SystemConsoleSyncTest(object syncRootForLogger1, object syncRootForLogger2)
{
var logger1 = new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.WithProperty("Logger", "logger1")
.WriteTo.Console(theme: SystemConsoleTheme.Literate, syncRoot: syncRootForLogger1)
.CreateLogger();

var logger2 = new LoggerConfiguration()
.MinimumLevel.Verbose()
.Enrich.WithProperty("Logger", "logger2")
.WriteTo.Console(theme: SystemConsoleTheme.Literate, syncRoot: syncRootForLogger2)
.CreateLogger();

var options = new ParallelOptions { MaxDegreeOfParallelism = 8 };
System.Threading.Tasks.Parallel.For(0, 1000, options, (i, loopState) =>
{
var logger = (i % 2 == 0) ? logger1 : logger2;
logger.Information("Event {Iteration} generated by {ThreadId}", i, Thread.CurrentThread.ManagedThreadId);
});
}
}
}
12 changes: 12 additions & 0 deletions sample/SyncWritesDemo/SyncWritesDemo.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Serilog.Sinks.Console\Serilog.Sinks.Console.csproj" />
</ItemGroup>

</Project>
7 changes: 7 additions & 0 deletions serilog-sinks-console.sln
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{CF8176
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleDemo", "sample\ConsoleDemo\ConsoleDemo.csproj", "{DBF4907A-63A2-4895-8DEF-59F90C20380B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyncWritesDemo", "sample\SyncWritesDemo\SyncWritesDemo.csproj", "{633AE0AD-C9D4-440D-874A-C0F4632DB75F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -45,6 +47,10 @@ Global
{DBF4907A-63A2-4895-8DEF-59F90C20380B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DBF4907A-63A2-4895-8DEF-59F90C20380B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DBF4907A-63A2-4895-8DEF-59F90C20380B}.Release|Any CPU.Build.0 = Release|Any CPU
{633AE0AD-C9D4-440D-874A-C0F4632DB75F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{633AE0AD-C9D4-440D-874A-C0F4632DB75F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{633AE0AD-C9D4-440D-874A-C0F4632DB75F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{633AE0AD-C9D4-440D-874A-C0F4632DB75F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -53,6 +59,7 @@ Global
{866A028E-27DB-49A0-AC78-E5FEF247C099} = {037440DE-440B-4129-9F7A-09B42D00397E}
{1D56534C-4009-42C2-A573-789CAE6B8AA9} = {7D0692CD-F95D-4BF9-8C63-B4A1C078DF23}
{DBF4907A-63A2-4895-8DEF-59F90C20380B} = {CF817664-4CEC-4B6A-9C57-A0D687757D82}
{633AE0AD-C9D4-440D-874A-C0F4632DB75F} = {CF817664-4CEC-4B6A-9C57-A0D687757D82}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {43C32ED4-D39A-4E27-AE99-7BB8C883833C}
Expand Down
20 changes: 16 additions & 4 deletions src/Serilog.Sinks.Console/ConsoleLoggerConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Serilog
/// </summary>
public static class ConsoleLoggerConfigurationExtensions
{
static object DefaultSyncRoot = new object();
const string DefaultConsoleOutputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}";

/// <summary>
Expand All @@ -38,6 +39,9 @@ public static class ConsoleLoggerConfigurationExtensions
/// events passed through the sink. Ignored when <paramref name="levelSwitch"/> is specified.</param>
/// <param name="outputTemplate">A message template describing the format used to write to the sink.
/// The default is <code>"[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"</code>.</param>
/// <param name="syncRoot">An object that will be used to `lock` (sync) access to the console output. If you specify this, you
/// will have the ability to lock on this object, and guarantee that the console sink will not be about to output anything while
/// the lock is held.</param>
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
/// <param name="levelSwitch">A switch allowing the pass-through minimum level
/// to be changed at runtime.</param>
Expand All @@ -52,7 +56,8 @@ public static LoggerConfiguration Console(
IFormatProvider formatProvider = null,
LoggingLevelSwitch levelSwitch = null,
LogEventLevel? standardErrorFromLevel = null,
ConsoleTheme theme = null)
ConsoleTheme theme = null,
object syncRoot = null)
{
if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration));
if (outputTemplate == null) throw new ArgumentNullException(nameof(outputTemplate));
Expand All @@ -61,8 +66,10 @@ public static LoggerConfiguration Console(
ConsoleTheme.None :
theme ?? SystemConsoleThemes.Literate;

syncRoot = syncRoot ?? DefaultSyncRoot;

var formatter = new OutputTemplateRenderer(appliedTheme, outputTemplate, formatProvider);
return sinkConfiguration.Sink(new ConsoleSink(appliedTheme, formatter, standardErrorFromLevel), restrictedToMinimumLevel, levelSwitch);
return sinkConfiguration.Sink(new ConsoleSink(appliedTheme, formatter, standardErrorFromLevel, syncRoot), restrictedToMinimumLevel, levelSwitch);
}

/// <summary>
Expand All @@ -71,6 +78,9 @@ public static LoggerConfiguration Console(
/// <param name="sinkConfiguration">Logger sink configuration.</param>
/// <param name="formatter">Controls the rendering of log events into text, for example to log JSON. To
/// control plain text formatting, use the overload that accepts an output template.</param>
/// <param name="syncRoot">An object that will be used to `lock` (sync) access to the console output. If you specify this, you
/// will have the ability to lock on this object, and guarantee that the console sink will not be about to output anything while
/// the lock is held.</param>
/// <param name="restrictedToMinimumLevel">The minimum level for
/// events passed through the sink. Ignored when <paramref name="levelSwitch"/> is specified.</param>
/// <param name="levelSwitch">A switch allowing the pass-through minimum level
Expand All @@ -82,12 +92,14 @@ public static LoggerConfiguration Console(
ITextFormatter formatter,
LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
LoggingLevelSwitch levelSwitch = null,
LogEventLevel? standardErrorFromLevel = null)
LogEventLevel? standardErrorFromLevel = null,
object syncRoot = null)
{
if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration));
if (formatter == null) throw new ArgumentNullException(nameof(formatter));

return sinkConfiguration.Sink(new ConsoleSink(ConsoleTheme.None, formatter, standardErrorFromLevel), restrictedToMinimumLevel, levelSwitch);
syncRoot = syncRoot ?? DefaultSyncRoot;
return sinkConfiguration.Sink(new ConsoleSink(ConsoleTheme.None, formatter, standardErrorFromLevel, syncRoot), restrictedToMinimumLevel, levelSwitch);
}
}
}
6 changes: 4 additions & 2 deletions src/Serilog.Sinks.Console/Sinks/SystemConsole/ConsoleSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class ConsoleSink : ILogEventSink
readonly LogEventLevel? _standardErrorFromLevel;
readonly ConsoleTheme _theme;
readonly ITextFormatter _formatter;
static readonly object _syncRoot = new object();
readonly object _syncRoot;

const int DefaultWriteBufferCapacity = 256;

Expand All @@ -40,11 +40,13 @@ static ConsoleSink()
public ConsoleSink(
ConsoleTheme theme,
ITextFormatter formatter,
LogEventLevel? standardErrorFromLevel)
LogEventLevel? standardErrorFromLevel,
object syncRoot)
{
_standardErrorFromLevel = standardErrorFromLevel;
_theme = theme ?? throw new ArgumentNullException(nameof(theme));
_formatter = formatter;
_syncRoot = syncRoot ?? throw new ArgumentNullException(nameof(syncRoot));
}

public void Emit(LogEvent logEvent)
Expand Down

0 comments on commit e83f2f3

Please sign in to comment.