From d6e47d4bb8a0facda820cfc6b30365051746afa2 Mon Sep 17 00:00:00 2001 From: Nanaloveyuki Date: Wed, 20 May 2026 08:15:31 +0800 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Extract=20core=20and=20uti?= =?UTF-8?q?ls=20subpackages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/level.mbt | 31 +++++++++++++++++ src/core/moon.pkg | 2 ++ src/core/record.mbt | 76 ++++++++++++++++++++++++++++++++++++++++++ src/filters.mbt | 58 ++++++-------------------------- src/level.mbt | 32 +----------------- src/moon.pkg | 2 ++ src/patchers.mbt | 56 +++++-------------------------- src/record.mbt | 31 +++-------------- src/sinks.mbt | 4 +-- src/utils/filters.mbt | 75 +++++++++++++++++++++++++++++++++++++++++ src/utils/moon.pkg | 3 ++ src/utils/patchers.mbt | 63 ++++++++++++++++++++++++++++++++++ 12 files changed, 278 insertions(+), 155 deletions(-) create mode 100644 src/core/level.mbt create mode 100644 src/core/moon.pkg create mode 100644 src/core/record.mbt create mode 100644 src/utils/filters.mbt create mode 100644 src/utils/moon.pkg create mode 100644 src/utils/patchers.mbt diff --git a/src/core/level.mbt b/src/core/level.mbt new file mode 100644 index 0000000..e81ea30 --- /dev/null +++ b/src/core/level.mbt @@ -0,0 +1,31 @@ +pub(all) enum Level { + Trace + Debug + Info + Warn + Error +} + +pub fn Level::priority(self : Level) -> Int { + match self { + Level::Trace => 10 + Level::Debug => 20 + Level::Info => 30 + Level::Warn => 40 + Level::Error => 50 + } +} + +pub fn Level::label(self : Level) -> String { + match self { + Level::Trace => "TRACE" + Level::Debug => "DEBUG" + Level::Info => "INFO" + Level::Warn => "WARN" + Level::Error => "ERROR" + } +} + +pub fn Level::enabled(self : Level, min_level : Level) -> Bool { + self.priority() >= min_level.priority() +} diff --git a/src/core/moon.pkg b/src/core/moon.pkg new file mode 100644 index 0000000..07e38af --- /dev/null +++ b/src/core/moon.pkg @@ -0,0 +1,2 @@ +import { +} diff --git a/src/core/record.mbt b/src/core/record.mbt new file mode 100644 index 0000000..5d7ebc1 --- /dev/null +++ b/src/core/record.mbt @@ -0,0 +1,76 @@ +pub struct Field { + key : String + value : String +} + +pub fn field(key : String, value : String) -> Field { + { key, value } +} + +pub fn fields(entries : Array[(String, String)]) -> Array[Field] { + entries.map(fn(entry) { + field(entry.0, entry.1) + }) +} + +pub struct Record { + level : Level + timestamp_ms : UInt64 + target : String + message : String + fields : Array[Field] +} + +pub fn Record::new( + level : Level, + message : String, + timestamp_ms~ : UInt64 = 0UL, + target~ : String = "", + fields~ : Array[Field] = [], +) -> Record { + { level, timestamp_ms, target, message, fields } +} + +pub fn Field::with_value(self : Field, value : String) -> Field { + field(self.key, value) +} + +pub fn Record::with_target(self : Record, target : String) -> Record { + Record::new( + self.level, + self.message, + timestamp_ms=self.timestamp_ms, + target=target, + fields=self.fields, + ) +} + +pub fn Record::with_message(self : Record, message : String) -> Record { + Record::new( + self.level, + message, + timestamp_ms=self.timestamp_ms, + target=self.target, + fields=self.fields, + ) +} + +pub fn Record::with_fields(self : Record, fields : Array[Field]) -> Record { + Record::new( + self.level, + self.message, + timestamp_ms=self.timestamp_ms, + target=self.target, + fields=fields, + ) +} + +pub fn Record::copy(self : Record) -> Record { + Record::new( + self.level, + self.message, + timestamp_ms=self.timestamp_ms, + target=self.target, + fields=self.fields, + ) +} diff --git a/src/filters.mbt b/src/filters.mbt index 0fcfee1..bccb229 100644 --- a/src/filters.mbt +++ b/src/filters.mbt @@ -1,75 +1,37 @@ -pub type RecordPredicate = (Record) -> Bool +pub type RecordPredicate = @utils.RecordPredicate pub fn level_at_least(min_level : Level) -> RecordPredicate { - fn(rec) { - rec.level.priority() >= min_level.priority() - } + @utils.level_at_least(min_level) } pub fn target_is(target : String) -> RecordPredicate { - fn(rec) { - rec.target == target - } + @utils.target_is(target) } pub fn target_has_prefix(prefix : String) -> RecordPredicate { - fn(rec) { - rec.target.has_prefix(prefix) - } + @utils.target_has_prefix(prefix) } pub fn message_contains(fragment : String) -> RecordPredicate { - fn(rec) { - rec.message.contains(fragment) - } + @utils.message_contains(fragment) } pub fn has_field(key : String) -> RecordPredicate { - fn(rec) { - for field in rec.fields { - if field.key == key { - return true - } - } - false - } + @utils.has_field(key) } pub fn field_equals(key : String, value : String) -> RecordPredicate { - fn(rec) { - for field in rec.fields { - if field.key == key && field.value == value { - return true - } - } - false - } + @utils.field_equals(key, value) } pub fn not_(predicate : RecordPredicate) -> RecordPredicate { - fn(rec) { - !(predicate(rec)) - } + @utils.not_(predicate) } pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate { - fn(rec) { - for predicate in predicates { - if !(predicate(rec)) { - return false - } - } - true - } + @utils.all_of(predicates) } pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate { - fn(rec) { - for predicate in predicates { - if predicate(rec) { - return true - } - } - false - } + @utils.any_of(predicates) } diff --git a/src/level.mbt b/src/level.mbt index e81ea30..0f76378 100644 --- a/src/level.mbt +++ b/src/level.mbt @@ -1,31 +1 @@ -pub(all) enum Level { - Trace - Debug - Info - Warn - Error -} - -pub fn Level::priority(self : Level) -> Int { - match self { - Level::Trace => 10 - Level::Debug => 20 - Level::Info => 30 - Level::Warn => 40 - Level::Error => 50 - } -} - -pub fn Level::label(self : Level) -> String { - match self { - Level::Trace => "TRACE" - Level::Debug => "DEBUG" - Level::Info => "INFO" - Level::Warn => "WARN" - Level::Error => "ERROR" - } -} - -pub fn Level::enabled(self : Level, min_level : Level) -> Bool { - self.priority() >= min_level.priority() -} +pub type Level = @core.Level diff --git a/src/moon.pkg b/src/moon.pkg index 932c4f4..27e123e 100644 --- a/src/moon.pkg +++ b/src/moon.pkg @@ -1,4 +1,6 @@ import { + "Nanaloveyuki/BitLogger/src/core" @core, + "Nanaloveyuki/BitLogger/src/utils" @utils, "maria/json_parser" @json_parser, "moonbitlang/core/array", "moonbitlang/core/builtin", diff --git a/src/patchers.mbt b/src/patchers.mbt index e5f348e..e51a042 100644 --- a/src/patchers.mbt +++ b/src/patchers.mbt @@ -1,69 +1,29 @@ -pub type RecordPatch = (Record) -> Record +pub type RecordPatch = @utils.RecordPatch pub fn identity_patch() -> RecordPatch { - fn(rec) { rec } + @utils.identity_patch() } pub fn set_target(target : String) -> RecordPatch { - fn(rec) { - { ..rec, target } - } + @utils.set_target(target) } pub fn prefix_message(prefix : String) -> RecordPatch { - fn(rec) { - { ..rec, message: "\{prefix}\{rec.message}" } - } + @utils.prefix_message(prefix) } pub fn append_fields(extra_fields : Array[Field]) -> RecordPatch { - fn(rec) { - if extra_fields.length() == 0 { - rec - } else if rec.fields.length() == 0 { - { ..rec, fields: extra_fields } - } else { - { ..rec, fields: rec.fields + extra_fields } - } - } + @utils.append_fields(extra_fields) } pub fn redact_field(key : String, placeholder~ : String = "***") -> RecordPatch { - fn(rec) { - { - ..rec, - fields: rec.fields.map(fn(field) { - if field.key == key { - { ..field, value: placeholder } - } else { - field - } - }), - } - } + @utils.redact_field(key, placeholder=placeholder) } pub fn redact_fields(keys : Array[String], placeholder~ : String = "***") -> RecordPatch { - fn(rec) { - { - ..rec, - fields: rec.fields.map(fn(field) { - if keys.contains(field.key) { - { ..field, value: placeholder } - } else { - field - } - }), - } - } + @utils.redact_fields(keys, placeholder=placeholder) } pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch { - fn(rec) { - let mut current = rec - for patch in patches { - current = patch(current) - } - current - } + @utils.compose_patches(patches) } diff --git a/src/record.mbt b/src/record.mbt index 7502e9a..89e3ad8 100644 --- a/src/record.mbt +++ b/src/record.mbt @@ -1,35 +1,14 @@ -pub struct Field { - key : String - value : String -} +pub type Field = @core.Field pub fn field(key : String, value : String) -> Field { - { key, value } + @core.field(key, value) } pub fn fields(entries : Array[(String, String)]) -> Array[Field] { - entries.map(fn(entry) { - field(entry.0, entry.1) - }) + @core.fields(entries) } -pub struct Record { - level : Level - timestamp_ms : UInt64 - target : String - message : String - fields : Array[Field] -} - -pub fn Record::new( - level : Level, - message : String, - timestamp_ms~ : UInt64 = 0UL, - target~ : String = "", - fields~ : Array[Field] = [], -) -> Record { - { level, timestamp_ms, target, message, fields } -} +pub type Record = @core.Record fn record( level : Level, @@ -38,5 +17,5 @@ fn record( target~ : String = "", fields~ : Array[Field] = [], ) -> Record { - Record::new(level, message, timestamp_ms=timestamp_ms, target=target, fields=fields) + @core.Record::new(level, message, timestamp_ms=timestamp_ms, target=target, fields=fields) } diff --git a/src/sinks.mbt b/src/sinks.mbt index 5ef9aed..c355979 100644 --- a/src/sinks.mbt +++ b/src/sinks.mbt @@ -28,7 +28,7 @@ pub impl[S : Sink] Sink for ContextSink[S] with write(self, rec) { } else { self.context_fields + rec.fields } - self.sink.write({ ..rec, fields: merged }) + self.sink.write(rec.with_fields(merged)) } pub struct JsonConsoleSink { @@ -471,7 +471,7 @@ pub fn[A, B] fanout_sink(left : A, right : B) -> FanoutSink[A, B] { pub impl[A : Sink, B : Sink] Sink for FanoutSink[A, B] with write(self, rec) { self.left.write(rec) - self.right.write({ ..rec }) + self.right.write(rec.copy()) } pub struct SplitSink[A, B] { diff --git a/src/utils/filters.mbt b/src/utils/filters.mbt new file mode 100644 index 0000000..364c5a5 --- /dev/null +++ b/src/utils/filters.mbt @@ -0,0 +1,75 @@ +pub type RecordPredicate = (@core.Record) -> Bool + +pub fn level_at_least(min_level : @core.Level) -> RecordPredicate { + fn(rec) { + rec.level.priority() >= min_level.priority() + } +} + +pub fn target_is(target : String) -> RecordPredicate { + fn(rec) { + rec.target == target + } +} + +pub fn target_has_prefix(prefix : String) -> RecordPredicate { + fn(rec) { + rec.target.has_prefix(prefix) + } +} + +pub fn message_contains(fragment : String) -> RecordPredicate { + fn(rec) { + rec.message.contains(fragment) + } +} + +pub fn has_field(key : String) -> RecordPredicate { + fn(rec) { + for field in rec.fields { + if field.key == key { + return true + } + } + false + } +} + +pub fn field_equals(key : String, value : String) -> RecordPredicate { + fn(rec) { + for field in rec.fields { + if field.key == key && field.value == value { + return true + } + } + false + } +} + +pub fn not_(predicate : RecordPredicate) -> RecordPredicate { + fn(rec) { + !(predicate(rec)) + } +} + +pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate { + fn(rec) { + for predicate in predicates { + if !(predicate(rec)) { + return false + } + } + true + } +} + +pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate { + fn(rec) { + for predicate in predicates { + if predicate(rec) { + return true + } + } + false + } +} diff --git a/src/utils/moon.pkg b/src/utils/moon.pkg new file mode 100644 index 0000000..ea28217 --- /dev/null +++ b/src/utils/moon.pkg @@ -0,0 +1,3 @@ +import { + "Nanaloveyuki/BitLogger/src/core" @core, +} diff --git a/src/utils/patchers.mbt b/src/utils/patchers.mbt new file mode 100644 index 0000000..6b94d51 --- /dev/null +++ b/src/utils/patchers.mbt @@ -0,0 +1,63 @@ +pub type RecordPatch = (@core.Record) -> @core.Record + +pub fn identity_patch() -> RecordPatch { + fn(rec) { rec } +} + +pub fn set_target(target : String) -> RecordPatch { + fn(rec) { + rec.with_target(target) + } +} + +pub fn prefix_message(prefix : String) -> RecordPatch { + fn(rec) { + rec.with_message("\{prefix}\{rec.message}") + } +} + +pub fn append_fields(extra_fields : Array[@core.Field]) -> RecordPatch { + fn(rec) { + if extra_fields.length() == 0 { + rec + } else if rec.fields.length() == 0 { + rec.with_fields(extra_fields) + } else { + rec.with_fields(rec.fields + extra_fields) + } + } +} + +pub fn redact_field(key : String, placeholder~ : String = "***") -> RecordPatch { + fn(rec) { + rec.with_fields(rec.fields.map(fn(field) { + if field.key == key { + field.with_value(placeholder) + } else { + field + } + })) + } +} + +pub fn redact_fields(keys : Array[String], placeholder~ : String = "***") -> RecordPatch { + fn(rec) { + rec.with_fields(rec.fields.map(fn(field) { + if keys.contains(field.key) { + field.with_value(placeholder) + } else { + field + } + })) + } +} + +pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch { + fn(rec) { + let mut current = rec + for patch in patches { + current = patch(current) + } + current + } +}