Files
EonaCat.LogStack/EonaCat.LogStack/EonaCatLoggerCore/LogEvent.cs
2026-02-27 21:12:55 +01:00

169 lines
4.9 KiB
C#

using EonaCat.LogStack.Extensions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace EonaCat.LogStack.Core;
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.
/// <summary>
/// Represents a single log event with efficient memory management through pooling.
/// This struct is designed to minimize allocations and support high-throughput logging.
/// </summary>
public struct LogEvent
{
public long Timestamp { get; set; }
public LogLevel Level { get; set; }
public string Category { get; set; }
public ReadOnlyMemory<char> Message { get; set; }
public Exception? Exception { get; set; }
public Dictionary<string, object?> Properties { get; set; }
public string CustomData { get; set; }
public int ThreadId { get; set; }
public ActivityTraceId TraceId { get; set; }
public ActivitySpanId SpanId { get; set; }
/// <summary>
/// Estimated memory size in bytes for backpressure calculations
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int EstimateSize()
{
// Base overhead
int size = 64;
// Message size
size += Message.Length * 2;
// Category size
size += (Category?.Length ?? 0) * 2;
// Exception size (estimated)
if (Exception != null)
{
size += 512;
}
// Properties size
size += Properties.Count * 32;
return size;
}
/// <summary>
/// Creates a timestamp value from DateTime
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long CreateTimestamp(DateTime dateTime) => dateTime.Ticks;
/// <summary>
/// Converts timestamp back to DateTime
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static DateTime GetDateTime(long timestamp) => new(timestamp);
public bool HasProperties => Properties != null && Properties.Count > 0;
public bool HasCustomData => CustomData != null && CustomData.Length > 0;
public bool HasException => Exception != null;
public bool HasCategory => Category != null;
}
/// <summary>
/// Builder for creating LogEvent instances with minimal allocations
/// </summary>
public struct LogEventBuilder
{
private long _timestamp;
private LogLevel _level;
private string? _category;
private ReadOnlyMemory<char> _message;
private Exception? _exception;
private Dictionary<string, object>? _properties;
private int _threadId;
private ActivityTraceId _traceId;
private ActivitySpanId _spanId;
public LogEventBuilder()
{
_timestamp = DateTime.UtcNow.Ticks;
_level = LogLevel.Information;
_threadId = Environment.CurrentManagedThreadId;
var activity = Activity.Current;
_traceId = activity?.TraceId ?? default;
_spanId = activity?.SpanId ?? default;
}
public string? Category => _category;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LogEventBuilder WithTimestamp(long timestamp)
{
_timestamp = timestamp;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LogEventBuilder WithLevel(LogLevel level)
{
_level = level;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LogEventBuilder WithCategory(string category)
{
_category = category;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LogEventBuilder WithMessage(ReadOnlyMemory<char> message)
{
_message = message;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LogEventBuilder WithMessage(string message)
{
_message = message.AsMemory();
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LogEventBuilder WithException(Exception? exception)
{
_exception = exception;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LogEventBuilder WithProperty(string key, object? value)
{
_properties ??= new Dictionary<string, object>(4);
_properties.TryAdd(key, value);
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public LogEvent Build()
{
return new LogEvent
{
Timestamp = _timestamp,
Level = _level,
Category = _category ?? string.Empty,
Message = _message,
Exception = _exception,
Properties = _properties ?? new Dictionary<string, object>(),
ThreadId = _threadId,
TraceId = _traceId,
SpanId = _spanId
};
}
}