169 lines
4.9 KiB
C#
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
|
|
};
|
|
}
|
|
} |