♻️ Extract core and utils subpackages

This commit is contained in:
Nanaloveyuki
2026-05-20 08:15:31 +08:00
parent 91096a9e0d
commit d6e47d4bb8
12 changed files with 278 additions and 155 deletions
+31
View File
@@ -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()
}
+2
View File
@@ -0,0 +1,2 @@
import {
}
+76
View File
@@ -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,
)
}
+10 -48
View File
@@ -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)
}
+1 -31
View File
@@ -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
+2
View File
@@ -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",
+8 -48
View File
@@ -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)
}
+5 -26
View File
@@ -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)
}
+2 -2
View File
@@ -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] {
+75
View File
@@ -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
}
}
+3
View File
@@ -0,0 +1,3 @@
import {
"Nanaloveyuki/BitLogger/src/core" @core,
}
+63
View File
@@ -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
}
}