mirror of
https://github.com/hanskokx/arcane_framework.git
synced 2026-08-12 06:10:55 +02:00
v2.0.3: Enhance LogEvent serialization and refactor LogInterceptor to support callback-based usage
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
part of "logging_service.dart";
|
||||
|
||||
/// Immutable payload representing a single log entry.
|
||||
///
|
||||
/// This model is used internally by the logging pipeline and supports
|
||||
/// JSON round-tripping for persisted or forwarded log events.
|
||||
class LogEvent {
|
||||
static const Object _sentinel = Object();
|
||||
|
||||
@@ -11,12 +15,69 @@ class LogEvent {
|
||||
this.extra,
|
||||
});
|
||||
|
||||
/// Human-readable log message.
|
||||
final String message;
|
||||
|
||||
/// Optional structured context for the log event.
|
||||
///
|
||||
/// Values may contain nested maps/lists and are serialized recursively.
|
||||
final Map<String, Object?>? metadata;
|
||||
|
||||
/// Optional log level override for this event.
|
||||
final Level? level;
|
||||
|
||||
/// Optional captured stack trace associated with the event.
|
||||
final StackTrace? stackTrace;
|
||||
|
||||
/// Optional additional payload attached to the event.
|
||||
///
|
||||
/// This may be any value and is serialized recursively where possible.
|
||||
final Object? extra;
|
||||
|
||||
/// Deserializes a [LogEvent] from a JSON map.
|
||||
///
|
||||
/// Nested maps and lists in `metadata` and `extra` are decoded recursively.
|
||||
/// `level` is matched by enum name. `stackTrace` is restored as a
|
||||
/// string-backed [StackTrace] whose [toString] returns the original text.
|
||||
factory LogEvent.fromJson(Map<String, Object?> json) {
|
||||
final rawStackTrace = json["stackTrace"];
|
||||
final rawLevel = json["level"];
|
||||
|
||||
return LogEvent(
|
||||
message: json["message"] as String,
|
||||
metadata: json["metadata"].fromJsonMap(),
|
||||
level: rawLevel != null
|
||||
? Level.values.firstWhere(
|
||||
(l) => l.name == rawLevel,
|
||||
orElse: () => Level.debug,
|
||||
)
|
||||
: null,
|
||||
stackTrace: rawStackTrace != null
|
||||
? _StringStackTrace(rawStackTrace as String)
|
||||
: null,
|
||||
extra: json["extra"].fromJsonValue(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Serializes this [LogEvent] to a JSON-compatible map.
|
||||
///
|
||||
/// `metadata` and `extra` are encoded recursively so nested maps and lists
|
||||
/// are preserved. Non-encodable leaf values fall back to [toString].
|
||||
/// `level` is stored as its enum name; `stackTrace` as its string form.
|
||||
Map<String, Object?> toJson() {
|
||||
return {
|
||||
"message": message,
|
||||
if (metadata != null) "metadata": metadata!.toJsonMap(),
|
||||
if (level != null) "level": level!.name,
|
||||
if (stackTrace != null) "stackTrace": stackTrace!.toString(),
|
||||
if (extra != null) "extra": extra.toJsonValue(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns a copy of this event with selected fields replaced.
|
||||
///
|
||||
/// Nullable fields use sentinel values to distinguish "keep existing value"
|
||||
/// from "explicitly set to null".
|
||||
LogEvent copyWith({
|
||||
String? message,
|
||||
Object? metadata = _sentinel,
|
||||
@@ -37,3 +98,14 @@ class LogEvent {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A [StackTrace] backed by a plain string, used to round-trip stack trace
|
||||
/// text through JSON without losing the original content.
|
||||
class _StringStackTrace implements StackTrace {
|
||||
const _StringStackTrace(this._trace);
|
||||
|
||||
final String _trace;
|
||||
|
||||
@override
|
||||
String toString() => _trace;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ final class LogInterceptorContext {
|
||||
///
|
||||
/// Example usage:
|
||||
/// ```dart
|
||||
/// final interceptor = LogInterceptor((event, context) {
|
||||
/// final interceptor = CallbackLogInterceptor((event, context) {
|
||||
/// // Filter out debug-level logs
|
||||
/// if (event.level == Level.debug) return null;
|
||||
/// return event;
|
||||
@@ -49,26 +49,37 @@ final class LogInterceptorContext {
|
||||
/// See also:
|
||||
/// - [LogEvent], which represents a log entry.
|
||||
/// - [LogInterceptorContext], which provides context for the interception.
|
||||
class LogInterceptor {
|
||||
/// Creates a [LogInterceptor] with the given callback.
|
||||
abstract class LogInterceptor {
|
||||
/// Creates a callback-backed [LogInterceptor].
|
||||
///
|
||||
/// The [_callback] function will be invoked for each log event, with the
|
||||
/// event and its context. Return a [LogEvent] to continue processing, or
|
||||
/// `null` to suppress the event.
|
||||
const LogInterceptor(this._callback);
|
||||
|
||||
/// The callback function that processes each log event.
|
||||
///
|
||||
/// The function receives the [event] and its [context], and should return
|
||||
/// either a (possibly modified) [LogEvent], or `null` to suppress the event.
|
||||
final LogEvent? Function(
|
||||
LogEvent event,
|
||||
LogInterceptorContext context,
|
||||
) _callback;
|
||||
/// This keeps inline interceptor usage ergonomic.
|
||||
const factory LogInterceptor(
|
||||
LogEvent? Function(
|
||||
LogEvent event,
|
||||
LogInterceptorContext context,
|
||||
) callback,
|
||||
) = CallbackLogInterceptor;
|
||||
|
||||
/// Invokes the interceptor on the given [event] and [context].
|
||||
///
|
||||
/// Returns the (possibly modified) [LogEvent], or `null` to suppress the event.
|
||||
LogEvent? call(
|
||||
LogEvent event, {
|
||||
required LogInterceptorContext context,
|
||||
});
|
||||
}
|
||||
|
||||
/// A callback-backed implementation of [LogInterceptor].
|
||||
final class CallbackLogInterceptor implements LogInterceptor {
|
||||
/// Creates a callback-backed interceptor.
|
||||
const CallbackLogInterceptor(this._callback);
|
||||
|
||||
final LogEvent? Function(
|
||||
LogEvent event,
|
||||
LogInterceptorContext context,
|
||||
) _callback;
|
||||
|
||||
@override
|
||||
LogEvent? call(
|
||||
LogEvent event, {
|
||||
required LogInterceptorContext context,
|
||||
|
||||
Reference in New Issue
Block a user