Files
velopack/test/Divergic.Logging.Xunit/ScopeWriter.cs

129 lines
4.0 KiB
C#

namespace Divergic.Logging.Xunit
{
using System;
using System.Diagnostics;
using System.Globalization;
using System.Text.Json;
using global::Xunit.Abstractions;
using Microsoft.Extensions.Logging;
internal class ScopeWriter : IDisposable
{
private readonly string _category;
private readonly LoggingConfig _config;
private readonly int _depth;
private readonly Action _onScopeEnd;
private readonly ITestOutputHelper _output;
private readonly object? _state;
private string _scopeMessage = string.Empty;
private string _structuredStateData = string.Empty;
public ScopeWriter(
ITestOutputHelper output,
object? state,
int depth,
string category,
Action onScopeEnd,
LoggingConfig config)
{
_output = output;
_state = state;
_depth = depth;
_category = category;
_onScopeEnd = onScopeEnd;
_config = config;
DetermineScopeStateMessage();
var scopeStartMessage = BuildScopeStateMessage(false);
WriteLog(_depth, scopeStartMessage);
if (string.IsNullOrWhiteSpace(_structuredStateData) == false)
{
// Add the padding to the structured data
var structuredLines =
_structuredStateData.Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
WriteLog(_depth + 1, "Scope data: ");
foreach (var structuredLine in structuredLines)
{
WriteLog(_depth + 1, structuredLine);
}
}
}
private void WriteLog(int depth, string message)
{
var formattedMessage = _config.ScopeFormatter.Format(depth, _category, LogLevel.Information, 0, message, null);
_output.WriteLine(formattedMessage);
// Write the message to the output window
Trace.WriteLine(formattedMessage);
}
public void Dispose()
{
var scopeStartMessage = BuildScopeStateMessage(true);
_output.WriteLine(scopeStartMessage);
_onScopeEnd.Invoke();
}
private string BuildScopeStateMessage(bool isScopeEnd)
{
var endScopeMarker = isScopeEnd ? "/" : string.Empty;
const string format = "<{0}{1}>";
var message = string.Format(CultureInfo.InvariantCulture, format, endScopeMarker, _scopeMessage);
var formattedMessage =
_config.ScopeFormatter.Format(_depth, _category, LogLevel.Information, 0, message, null);
return formattedMessage;
}
private void DetermineScopeStateMessage()
{
const string scopeMarker = "Scope: ";
var defaultScopeMessage = "Scope " + (_depth + 1);
if (_state == null)
{
_scopeMessage = defaultScopeMessage;
}
else if (_state is string state)
{
if (string.IsNullOrWhiteSpace(state))
{
_scopeMessage = defaultScopeMessage;
}
else
{
_scopeMessage = scopeMarker + state;
}
}
else if (_state.GetType().IsValueType)
{
_scopeMessage = scopeMarker + _state;
}
else
{
try
{
// The data is probably a complex object or a structured log entry
_structuredStateData = JsonSerializer.Serialize(_state, SerializerSettings.Default);
}
catch (JsonException ex)
{
_structuredStateData = ex.ToString();
}
_scopeMessage = defaultScopeMessage;
}
}
}
}