mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-07-26 18:02:19 +00:00
🔊 Update 1.0.0
This commit is contained in:
+195
-95
@@ -1,7 +1,9 @@
|
||||
///|
|
||||
pub(all) suberror ConfigError {
|
||||
InvalidConfig(String)
|
||||
}
|
||||
|
||||
///|
|
||||
pub(all) enum SinkKind {
|
||||
Console
|
||||
JsonConsole
|
||||
@@ -9,6 +11,7 @@ pub(all) enum SinkKind {
|
||||
File
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct TextFormatterConfig {
|
||||
show_timestamp : Bool
|
||||
show_level : Bool
|
||||
@@ -25,20 +28,21 @@ pub struct TextFormatterConfig {
|
||||
style_tags : Map[String, TextStyle]
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn TextFormatterConfig::new(
|
||||
show_timestamp~ : Bool = true,
|
||||
show_level~ : Bool = true,
|
||||
show_target~ : Bool = true,
|
||||
show_fields~ : Bool = true,
|
||||
separator~ : String = " ",
|
||||
field_separator~ : String = " ",
|
||||
template~ : String = "",
|
||||
color_mode~ : ColorMode = ColorMode::Never,
|
||||
color_support~ : ColorSupport = ColorSupport::TrueColor,
|
||||
style_markup~ : StyleMarkupMode = StyleMarkupMode::Full,
|
||||
target_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||
fields_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||
style_tags~ : Map[String, TextStyle] = {},
|
||||
show_timestamp? : Bool = true,
|
||||
show_level? : Bool = true,
|
||||
show_target? : Bool = true,
|
||||
show_fields? : Bool = true,
|
||||
separator? : String = " ",
|
||||
field_separator? : String = " ",
|
||||
template? : String = "",
|
||||
color_mode? : ColorMode = ColorMode::Never,
|
||||
color_support? : ColorSupport = ColorSupport::TrueColor,
|
||||
style_markup? : StyleMarkupMode = StyleMarkupMode::Full,
|
||||
target_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||
fields_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||
style_tags? : Map[String, TextStyle] = {},
|
||||
) -> TextFormatterConfig {
|
||||
{
|
||||
show_timestamp,
|
||||
@@ -57,15 +61,21 @@ pub fn TextFormatterConfig::new(
|
||||
}
|
||||
}
|
||||
|
||||
fn style_tag_registry_from_config(style_tags : Map[String, TextStyle]) -> StyleTagRegistry {
|
||||
///|
|
||||
fn style_tag_registry_from_config(
|
||||
style_tags : Map[String, TextStyle],
|
||||
) -> StyleTagRegistry {
|
||||
let registry = style_tag_registry()
|
||||
for name, style in style_tags {
|
||||
ignore(registry.set_tag(name, style=style))
|
||||
ignore(registry.set_tag(name, style~))
|
||||
}
|
||||
registry
|
||||
}
|
||||
|
||||
pub fn TextFormatterConfig::to_formatter(self : TextFormatterConfig) -> TextFormatter {
|
||||
///|
|
||||
pub fn TextFormatterConfig::to_formatter(
|
||||
self : TextFormatterConfig,
|
||||
) -> TextFormatter {
|
||||
text_formatter(
|
||||
show_timestamp=self.show_timestamp,
|
||||
show_level=self.show_level,
|
||||
@@ -87,18 +97,21 @@ pub fn TextFormatterConfig::to_formatter(self : TextFormatterConfig) -> TextForm
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct QueueConfig {
|
||||
max_pending : Int
|
||||
overflow : QueueOverflowPolicy
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn QueueConfig::new(
|
||||
max_pending : Int,
|
||||
overflow~ : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||
overflow? : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||
) -> QueueConfig {
|
||||
{ max_pending, overflow }
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct SinkConfig {
|
||||
kind : SinkKind
|
||||
path : String
|
||||
@@ -108,24 +121,19 @@ pub struct SinkConfig {
|
||||
text_formatter : TextFormatterConfig
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn SinkConfig::new(
|
||||
kind~ : SinkKind = SinkKind::Console,
|
||||
path~ : String = "",
|
||||
append~ : Bool = true,
|
||||
auto_flush~ : Bool = true,
|
||||
rotation~ : FileRotation? = None,
|
||||
text_formatter~ : TextFormatterConfig = default_text_formatter_config(),
|
||||
kind? : SinkKind = SinkKind::Console,
|
||||
path? : String = "",
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : FileRotation? = None,
|
||||
text_formatter? : TextFormatterConfig = default_text_formatter_config(),
|
||||
) -> SinkConfig {
|
||||
{
|
||||
kind,
|
||||
path,
|
||||
append,
|
||||
auto_flush,
|
||||
rotation,
|
||||
text_formatter,
|
||||
}
|
||||
{ kind, path, append, auto_flush, rotation, text_formatter }
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct LoggerConfig {
|
||||
min_level : @core.Level
|
||||
target : String
|
||||
@@ -134,34 +142,33 @@ pub struct LoggerConfig {
|
||||
queue : QueueConfig?
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn LoggerConfig::new(
|
||||
min_level~ : @core.Level = @core.Level::Info,
|
||||
target~ : String = "",
|
||||
timestamp~ : Bool = false,
|
||||
sink~ : SinkConfig = default_sink_config(),
|
||||
queue~ : QueueConfig? = None,
|
||||
min_level? : @core.Level = @core.Level::Info,
|
||||
target? : String = "",
|
||||
timestamp? : Bool = false,
|
||||
sink? : SinkConfig = default_sink_config(),
|
||||
queue? : QueueConfig? = None,
|
||||
) -> LoggerConfig {
|
||||
{
|
||||
min_level,
|
||||
target,
|
||||
timestamp,
|
||||
sink,
|
||||
queue,
|
||||
}
|
||||
{ min_level, target, timestamp, sink, queue }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn default_text_formatter_config() -> TextFormatterConfig {
|
||||
TextFormatterConfig::new()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn default_sink_config() -> SinkConfig {
|
||||
SinkConfig::new()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn default_logger_config() -> LoggerConfig {
|
||||
LoggerConfig::new()
|
||||
}
|
||||
|
||||
///|
|
||||
fn expect_object(
|
||||
value : @json_parser.JsonValue,
|
||||
context : String,
|
||||
@@ -172,33 +179,40 @@ fn expect_object(
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn get_string(
|
||||
obj : Map[String, @json_parser.JsonValue],
|
||||
key : String,
|
||||
default~ : String = "",
|
||||
default? : String = "",
|
||||
) -> String raise ConfigError {
|
||||
match obj.get(key) {
|
||||
None => default
|
||||
Some(value) => match value.as_string() {
|
||||
Some(text) => text
|
||||
None => raise ConfigError::InvalidConfig("Expected string at key " + key)
|
||||
}
|
||||
Some(value) =>
|
||||
match value.as_string() {
|
||||
Some(text) => text
|
||||
None =>
|
||||
raise ConfigError::InvalidConfig("Expected string at key " + key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn get_optional_string(
|
||||
obj : Map[String, @json_parser.JsonValue],
|
||||
key : String,
|
||||
) -> String? raise ConfigError {
|
||||
match obj.get(key) {
|
||||
None => None
|
||||
Some(value) => match value.as_string() {
|
||||
Some(text) => Some(text)
|
||||
None => raise ConfigError::InvalidConfig("Expected string at key " + key)
|
||||
}
|
||||
Some(value) =>
|
||||
match value.as_string() {
|
||||
Some(text) => Some(text)
|
||||
None =>
|
||||
raise ConfigError::InvalidConfig("Expected string at key " + key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn get_bool(
|
||||
obj : Map[String, @json_parser.JsonValue],
|
||||
key : String,
|
||||
@@ -206,13 +220,15 @@ fn get_bool(
|
||||
) -> Bool raise ConfigError {
|
||||
match obj.get(key) {
|
||||
None => default
|
||||
Some(value) => match value.as_bool() {
|
||||
Some(flag) => flag
|
||||
None => raise ConfigError::InvalidConfig("Expected bool at key " + key)
|
||||
}
|
||||
Some(value) =>
|
||||
match value.as_bool() {
|
||||
Some(flag) => flag
|
||||
None => raise ConfigError::InvalidConfig("Expected bool at key " + key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn get_int(
|
||||
obj : Map[String, @json_parser.JsonValue],
|
||||
key : String,
|
||||
@@ -220,13 +236,16 @@ fn get_int(
|
||||
) -> Int raise ConfigError {
|
||||
match obj.get(key) {
|
||||
None => default
|
||||
Some(value) => match value.as_number() {
|
||||
Some(number) => number.to_int()
|
||||
None => raise ConfigError::InvalidConfig("Expected number at key " + key)
|
||||
}
|
||||
Some(value) =>
|
||||
match value.as_number() {
|
||||
Some(number) => number.to_int()
|
||||
None =>
|
||||
raise ConfigError::InvalidConfig("Expected number at key " + key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_level(name : String) -> @core.Level raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"TRACE" => @core.Level::Trace
|
||||
@@ -238,15 +257,20 @@ fn parse_level(name : String) -> @core.Level raise ConfigError {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_overflow(name : String) -> QueueOverflowPolicy raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"DROPNEWEST" => QueueOverflowPolicy::DropNewest
|
||||
"DROPPOLDEST" => QueueOverflowPolicy::DropOldest
|
||||
"DROPOLDEST" => QueueOverflowPolicy::DropOldest
|
||||
_ => raise ConfigError::InvalidConfig("Unsupported queue overflow policy: " + name)
|
||||
_ =>
|
||||
raise ConfigError::InvalidConfig(
|
||||
"Unsupported queue overflow policy: " + name,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_sink_kind(name : String) -> SinkKind raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"CONSOLE" => SinkKind::Console
|
||||
@@ -259,6 +283,7 @@ fn parse_sink_kind(name : String) -> SinkKind raise ConfigError {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_color_mode(name : String) -> ColorMode raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"NEVER" => ColorMode::Never
|
||||
@@ -268,6 +293,7 @@ fn parse_color_mode(name : String) -> ColorMode raise ConfigError {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_color_support(name : String) -> ColorSupport raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"BASIC" => ColorSupport::Basic
|
||||
@@ -276,15 +302,18 @@ fn parse_color_support(name : String) -> ColorSupport raise ConfigError {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_style_markup_mode(name : String) -> StyleMarkupMode raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"DISABLED" => StyleMarkupMode::Disabled
|
||||
"BUILTIN" => StyleMarkupMode::Builtin
|
||||
"FULL" => StyleMarkupMode::Full
|
||||
_ => raise ConfigError::InvalidConfig("Unsupported style markup mode: " + name)
|
||||
_ =>
|
||||
raise ConfigError::InvalidConfig("Unsupported style markup mode: " + name)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn sink_kind_label(kind : SinkKind) -> String {
|
||||
match kind {
|
||||
SinkKind::Console => "console"
|
||||
@@ -294,7 +323,10 @@ fn sink_kind_label(kind : SinkKind) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_text_formatter_config(value : @json_parser.JsonValue) -> TextFormatterConfig raise ConfigError {
|
||||
///|
|
||||
fn parse_text_formatter_config(
|
||||
value : @json_parser.JsonValue,
|
||||
) -> TextFormatterConfig raise ConfigError {
|
||||
let obj = expect_object(value, "text_formatter")
|
||||
TextFormatterConfig::new(
|
||||
show_timestamp=get_bool(obj, "show_timestamp", default=true),
|
||||
@@ -305,10 +337,18 @@ fn parse_text_formatter_config(value : @json_parser.JsonValue) -> TextFormatterC
|
||||
field_separator=get_string(obj, "field_separator", default=" "),
|
||||
template=get_string(obj, "template", default=""),
|
||||
color_mode=parse_color_mode(get_string(obj, "color_mode", default="never")),
|
||||
color_support=parse_color_support(get_string(obj, "color_support", default="truecolor")),
|
||||
style_markup=parse_style_markup_mode(get_string(obj, "style_markup", default="full")),
|
||||
target_style_markup=parse_style_markup_mode(get_string(obj, "target_style_markup", default="disabled")),
|
||||
fields_style_markup=parse_style_markup_mode(get_string(obj, "fields_style_markup", default="disabled")),
|
||||
color_support=parse_color_support(
|
||||
get_string(obj, "color_support", default="truecolor"),
|
||||
),
|
||||
style_markup=parse_style_markup_mode(
|
||||
get_string(obj, "style_markup", default="full"),
|
||||
),
|
||||
target_style_markup=parse_style_markup_mode(
|
||||
get_string(obj, "target_style_markup", default="disabled"),
|
||||
),
|
||||
fields_style_markup=parse_style_markup_mode(
|
||||
get_string(obj, "fields_style_markup", default="disabled"),
|
||||
),
|
||||
style_tags=match obj.get("style_tags") {
|
||||
None => {}
|
||||
Some(inner) => parse_style_tags_config(inner)
|
||||
@@ -316,6 +356,7 @@ fn parse_text_formatter_config(value : @json_parser.JsonValue) -> TextFormatterC
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_text_style_config(
|
||||
value : @json_parser.JsonValue,
|
||||
context : String,
|
||||
@@ -331,16 +372,25 @@ fn parse_text_style_config(
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_style_tags_config(value : @json_parser.JsonValue) -> Map[String, TextStyle] raise ConfigError {
|
||||
///|
|
||||
fn parse_style_tags_config(
|
||||
value : @json_parser.JsonValue,
|
||||
) -> Map[String, TextStyle] raise ConfigError {
|
||||
let obj = expect_object(value, "text_formatter.style_tags")
|
||||
let style_tags : Map[String, TextStyle] = {}
|
||||
for name, item in obj {
|
||||
style_tags[name] = parse_text_style_config(item, "text_formatter.style_tags." + name)
|
||||
style_tags[name] = parse_text_style_config(
|
||||
item,
|
||||
"text_formatter.style_tags." + name,
|
||||
)
|
||||
}
|
||||
style_tags
|
||||
}
|
||||
|
||||
fn parse_queue_config(value : @json_parser.JsonValue) -> QueueConfig raise ConfigError {
|
||||
///|
|
||||
fn parse_queue_config(
|
||||
value : @json_parser.JsonValue,
|
||||
) -> QueueConfig raise ConfigError {
|
||||
let obj = expect_object(value, "queue")
|
||||
QueueConfig::new(
|
||||
get_int(obj, "max_pending", default=0),
|
||||
@@ -348,7 +398,10 @@ fn parse_queue_config(value : @json_parser.JsonValue) -> QueueConfig raise Confi
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_file_rotation_config(value : @json_parser.JsonValue) -> FileRotation raise ConfigError {
|
||||
///|
|
||||
fn parse_file_rotation_config(
|
||||
value : @json_parser.JsonValue,
|
||||
) -> FileRotation raise ConfigError {
|
||||
let obj = expect_object(value, "sink.rotation")
|
||||
file_rotation(
|
||||
get_int(obj, "max_bytes", default=1),
|
||||
@@ -356,7 +409,10 @@ fn parse_file_rotation_config(value : @json_parser.JsonValue) -> FileRotation ra
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_sink_config(value : @json_parser.JsonValue) -> SinkConfig raise ConfigError {
|
||||
///|
|
||||
fn parse_sink_config(
|
||||
value : @json_parser.JsonValue,
|
||||
) -> SinkConfig raise ConfigError {
|
||||
let obj = expect_object(value, "sink")
|
||||
let kind = parse_sink_kind(get_string(obj, "kind", default="console"))
|
||||
let formatter = match obj.get("text_formatter") {
|
||||
@@ -365,14 +421,15 @@ fn parse_sink_config(value : @json_parser.JsonValue) -> SinkConfig raise ConfigE
|
||||
}
|
||||
let path = get_string(obj, "path", default="")
|
||||
match kind {
|
||||
SinkKind::File => if path == "" {
|
||||
raise ConfigError::InvalidConfig("File sink requires non-empty path")
|
||||
}
|
||||
SinkKind::File =>
|
||||
if path == "" {
|
||||
raise ConfigError::InvalidConfig("File sink requires non-empty path")
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
SinkConfig::new(
|
||||
kind=kind,
|
||||
path=path,
|
||||
kind~,
|
||||
path~,
|
||||
append=get_bool(obj, "append", default=true),
|
||||
auto_flush=get_bool(obj, "auto_flush", default=true),
|
||||
rotation=match obj.get("rotation") {
|
||||
@@ -383,7 +440,10 @@ fn parse_sink_config(value : @json_parser.JsonValue) -> SinkConfig raise ConfigE
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse_logger_config_text(input : String) -> LoggerConfig raise ConfigError {
|
||||
///|
|
||||
pub fn parse_logger_config_text(
|
||||
input : String,
|
||||
) -> LoggerConfig raise ConfigError {
|
||||
let root = @json_parser.parse(input) catch {
|
||||
e => raise ConfigError::InvalidConfig("Invalid JSON: " + e.to_string())
|
||||
}
|
||||
@@ -403,17 +463,24 @@ pub fn parse_logger_config_text(input : String) -> LoggerConfig raise ConfigErro
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn queue_config_to_json(queue : QueueConfig) -> @json_parser.JsonValue {
|
||||
@json_parser.JsonValue::Object({
|
||||
"max_pending": @json_parser.JsonValue::Number(queue.max_pending.to_double()),
|
||||
"overflow": @json_parser.JsonValue::String(match queue.overflow {
|
||||
QueueOverflowPolicy::DropNewest => "DropNewest"
|
||||
QueueOverflowPolicy::DropOldest => "DropOldest"
|
||||
}),
|
||||
"overflow": @json_parser.JsonValue::String(
|
||||
match queue.overflow {
|
||||
QueueOverflowPolicy::DropNewest => "DropNewest"
|
||||
QueueOverflowPolicy::DropOldest => "DropOldest"
|
||||
},
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn stringify_queue_config(queue : QueueConfig, pretty~ : Bool = false) -> String {
|
||||
///|
|
||||
pub fn stringify_queue_config(
|
||||
queue : QueueConfig,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
let value = queue_config_to_json(queue)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
@@ -422,7 +489,10 @@ pub fn stringify_queue_config(queue : QueueConfig, pretty~ : Bool = false) -> St
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_formatter_config_to_json(config : TextFormatterConfig) -> @json_parser.JsonValue {
|
||||
///|
|
||||
pub fn text_formatter_config_to_json(
|
||||
config : TextFormatterConfig,
|
||||
) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"show_timestamp": @json_parser.JsonValue::Bool(config.show_timestamp),
|
||||
"show_level": @json_parser.JsonValue::Bool(config.show_level),
|
||||
@@ -431,11 +501,21 @@ pub fn text_formatter_config_to_json(config : TextFormatterConfig) -> @json_pars
|
||||
"separator": @json_parser.JsonValue::String(config.separator),
|
||||
"field_separator": @json_parser.JsonValue::String(config.field_separator),
|
||||
"template": @json_parser.JsonValue::String(config.template),
|
||||
"color_mode": @json_parser.JsonValue::String(color_mode_label(config.color_mode)),
|
||||
"color_support": @json_parser.JsonValue::String(color_support_label(config.color_support)),
|
||||
"style_markup": @json_parser.JsonValue::String(style_markup_mode_label(config.style_markup)),
|
||||
"target_style_markup": @json_parser.JsonValue::String(style_markup_mode_label(config.target_style_markup)),
|
||||
"fields_style_markup": @json_parser.JsonValue::String(style_markup_mode_label(config.fields_style_markup)),
|
||||
"color_mode": @json_parser.JsonValue::String(
|
||||
color_mode_label(config.color_mode),
|
||||
),
|
||||
"color_support": @json_parser.JsonValue::String(
|
||||
color_support_label(config.color_support),
|
||||
),
|
||||
"style_markup": @json_parser.JsonValue::String(
|
||||
style_markup_mode_label(config.style_markup),
|
||||
),
|
||||
"target_style_markup": @json_parser.JsonValue::String(
|
||||
style_markup_mode_label(config.target_style_markup),
|
||||
),
|
||||
"fields_style_markup": @json_parser.JsonValue::String(
|
||||
style_markup_mode_label(config.fields_style_markup),
|
||||
),
|
||||
}
|
||||
if config.style_tags.length() != 0 {
|
||||
obj["style_tags"] = style_tags_config_to_json(config.style_tags)
|
||||
@@ -443,6 +523,7 @@ pub fn text_formatter_config_to_json(config : TextFormatterConfig) -> @json_pars
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
///|
|
||||
fn text_style_config_to_json(style : TextStyle) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"bold": @json_parser.JsonValue::Bool(style.bold),
|
||||
@@ -461,7 +542,10 @@ fn text_style_config_to_json(style : TextStyle) -> @json_parser.JsonValue {
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
fn style_tags_config_to_json(style_tags : Map[String, TextStyle]) -> @json_parser.JsonValue {
|
||||
///|
|
||||
fn style_tags_config_to_json(
|
||||
style_tags : Map[String, TextStyle],
|
||||
) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {}
|
||||
for name, style in style_tags {
|
||||
obj[name] = text_style_config_to_json(style)
|
||||
@@ -469,9 +553,10 @@ fn style_tags_config_to_json(style_tags : Map[String, TextStyle]) -> @json_parse
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn stringify_text_formatter_config(
|
||||
config : TextFormatterConfig,
|
||||
pretty~ : Bool = false,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
let value = text_formatter_config_to_json(config)
|
||||
if pretty {
|
||||
@@ -481,13 +566,19 @@ pub fn stringify_text_formatter_config(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_rotation_config_to_json(config : FileRotation) -> @json_parser.JsonValue {
|
||||
///|
|
||||
pub fn file_rotation_config_to_json(
|
||||
config : FileRotation,
|
||||
) -> @json_parser.JsonValue {
|
||||
@json_parser.JsonValue::Object({
|
||||
"max_bytes": @json_parser.JsonValue::Number(config.max_bytes.to_double()),
|
||||
"max_backups": @json_parser.JsonValue::Number(config.max_backups.to_double()),
|
||||
"max_backups": @json_parser.JsonValue::Number(
|
||||
config.max_backups.to_double(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"kind": @json_parser.JsonValue::String(sink_kind_label(config.kind)),
|
||||
@@ -503,7 +594,11 @@ pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
pub fn stringify_sink_config(config : SinkConfig, pretty~ : Bool = false) -> String {
|
||||
///|
|
||||
pub fn stringify_sink_config(
|
||||
config : SinkConfig,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
let value = sink_config_to_json(config)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
@@ -512,6 +607,7 @@ pub fn stringify_sink_config(config : SinkConfig, pretty~ : Bool = false) -> Str
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"min_level": @json_parser.JsonValue::String(config.min_level.label()),
|
||||
@@ -526,7 +622,11 @@ pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
pub fn stringify_logger_config(config : LoggerConfig, pretty~ : Bool = false) -> String {
|
||||
///|
|
||||
pub fn stringify_logger_config(
|
||||
config : LoggerConfig,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
let value = logger_config_to_json(config)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
///|
|
||||
fn string_to_c_bytes(str : String) -> Bytes {
|
||||
let res : Array[Byte] = []
|
||||
let len = str.length()
|
||||
@@ -31,14 +32,18 @@ fn string_to_c_bytes(str : String) -> Bytes {
|
||||
Bytes::from_array(res)
|
||||
}
|
||||
|
||||
///|
|
||||
#external
|
||||
type NativeFileHandle
|
||||
|
||||
///|
|
||||
#borrow(path, mode)
|
||||
extern "C" fn file_open_ffi(path : Bytes, mode : Bytes) -> NativeFileHandle = "bitlogger_file_open"
|
||||
|
||||
///|
|
||||
extern "C" fn file_is_null_ffi(handle : NativeFileHandle) -> Bool = "bitlogger_pointer_is_null"
|
||||
|
||||
///|
|
||||
#borrow(buffer)
|
||||
extern "C" fn file_write_ffi(
|
||||
buffer : Bytes,
|
||||
@@ -47,32 +52,37 @@ extern "C" fn file_write_ffi(
|
||||
handle : NativeFileHandle,
|
||||
) -> Int = "bitlogger_file_write"
|
||||
|
||||
///|
|
||||
extern "C" fn file_flush_ffi(handle : NativeFileHandle) -> Int = "bitlogger_file_flush"
|
||||
|
||||
///|
|
||||
extern "C" fn file_close_ffi(handle : NativeFileHandle) -> Int = "bitlogger_file_close"
|
||||
|
||||
///|
|
||||
extern "C" fn file_seek_ffi(
|
||||
handle : NativeFileHandle,
|
||||
offset : Int,
|
||||
origin : Int,
|
||||
) -> Int = "bitlogger_file_seek"
|
||||
|
||||
///|
|
||||
extern "C" fn file_tell_ffi(handle : NativeFileHandle) -> Int = "bitlogger_file_tell"
|
||||
|
||||
///|
|
||||
#borrow(from_path, to_path)
|
||||
extern "C" fn file_rename_ffi(
|
||||
from_path : Bytes,
|
||||
to_path : Bytes,
|
||||
) -> Int = "bitlogger_file_rename"
|
||||
extern "C" fn file_rename_ffi(from_path : Bytes, to_path : Bytes) -> Int = "bitlogger_file_rename"
|
||||
|
||||
///|
|
||||
#borrow(path)
|
||||
extern "C" fn file_remove_ffi(path : Bytes) -> Int = "bitlogger_file_remove"
|
||||
|
||||
///|
|
||||
pub struct FileHandle {
|
||||
path : String
|
||||
raw : NativeFileHandle
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||
let mode = if append { "ab" } else { "wb" }
|
||||
let raw = file_open_ffi(string_to_c_bytes(path), string_to_c_bytes(mode))
|
||||
@@ -83,20 +93,27 @@ pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
||||
///|
|
||||
pub fn write_file_handle_internal(
|
||||
handle : FileHandle,
|
||||
content : String,
|
||||
) -> Bool {
|
||||
let bytes = string_to_c_bytes(content)
|
||||
let written = file_write_ffi(bytes, 1, bytes.length() - 1, handle.raw)
|
||||
written == bytes.length() - 1
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
||||
file_flush_ffi(handle.raw) == 0
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
||||
file_close_ffi(handle.raw) == 0
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_size_internal(handle : FileHandle) -> Int {
|
||||
ignore(file_seek_ffi(handle.raw, 0, 2))
|
||||
let size = file_tell_ffi(handle.raw)
|
||||
@@ -107,18 +124,22 @@ pub fn file_size_internal(handle : FileHandle) -> Int {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
||||
file_rename_ffi(string_to_c_bytes(from_path), string_to_c_bytes(to_path)) == 0
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn remove_file_internal(path : String) -> Bool {
|
||||
file_remove_ffi(string_to_c_bytes(path)) == 0
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn string_byte_length_internal(content : String) -> Int {
|
||||
string_to_c_bytes(content).length() - 1
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn native_files_supported_internal() -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
///|
|
||||
pub struct FileHandle {
|
||||
path : String
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||
ignore(append)
|
||||
ignore(path)
|
||||
@@ -10,42 +12,53 @@ pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
||||
///|
|
||||
pub fn write_file_handle_internal(
|
||||
handle : FileHandle,
|
||||
content : String,
|
||||
) -> Bool {
|
||||
ignore(handle)
|
||||
ignore(content)
|
||||
false
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
||||
ignore(handle)
|
||||
false
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
||||
ignore(handle)
|
||||
false
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_size_internal(handle : FileHandle) -> Int {
|
||||
ignore(handle)
|
||||
0
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
||||
ignore(from_path)
|
||||
ignore(to_path)
|
||||
false
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn remove_file_internal(path : String) -> Bool {
|
||||
ignore(path)
|
||||
false
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn string_byte_length_internal(content : String) -> Int {
|
||||
content.length()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn native_files_supported_internal() -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
+16
-16
@@ -1,29 +1,27 @@
|
||||
///|
|
||||
pub type RecordPredicate = (@core.Record) -> Bool
|
||||
|
||||
///|
|
||||
pub fn level_at_least(min_level : @core.Level) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
rec.level.priority() >= min_level.priority()
|
||||
}
|
||||
fn(rec) { rec.level.priority() >= min_level.priority() }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn target_is(target : String) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
rec.target == target
|
||||
}
|
||||
fn(rec) { rec.target == target }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn target_has_prefix(prefix : String) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
rec.target.has_prefix(prefix)
|
||||
}
|
||||
fn(rec) { rec.target.has_prefix(prefix) }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn message_contains(fragment : String) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
rec.message.contains(fragment)
|
||||
}
|
||||
fn(rec) { rec.message.contains(fragment) }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn has_field(key : String) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for field in rec.fields {
|
||||
@@ -35,6 +33,7 @@ pub fn has_field(key : String) -> RecordPredicate {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for field in rec.fields {
|
||||
@@ -46,16 +45,16 @@ pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn not_(predicate : RecordPredicate) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
!(predicate(rec))
|
||||
}
|
||||
fn(rec) { !predicate(rec) }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for predicate in predicates {
|
||||
if !(predicate(rec)) {
|
||||
if !predicate(rec) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -63,6 +62,7 @@ pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for predicate in predicates {
|
||||
|
||||
+322
-150
@@ -1,22 +1,27 @@
|
||||
///|
|
||||
pub type RecordFormatter = (@core.Record) -> String
|
||||
|
||||
///|
|
||||
pub(all) enum ColorMode {
|
||||
Never
|
||||
Auto
|
||||
Always
|
||||
}
|
||||
|
||||
///|
|
||||
pub(all) enum ColorSupport {
|
||||
Basic
|
||||
TrueColor
|
||||
}
|
||||
|
||||
///|
|
||||
pub(all) enum StyleMarkupMode {
|
||||
Disabled
|
||||
Builtin
|
||||
Full
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct TextStyle {
|
||||
fg : String?
|
||||
bg : String?
|
||||
@@ -26,29 +31,34 @@ pub struct TextStyle {
|
||||
underline : Bool
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn text_style(
|
||||
fg~ : String? = None,
|
||||
bg~ : String? = None,
|
||||
bold~ : Bool = false,
|
||||
dim~ : Bool = false,
|
||||
italic~ : Bool = false,
|
||||
underline~ : Bool = false,
|
||||
fg? : String? = None,
|
||||
bg? : String? = None,
|
||||
bold? : Bool = false,
|
||||
dim? : Bool = false,
|
||||
italic? : Bool = false,
|
||||
underline? : Bool = false,
|
||||
) -> TextStyle {
|
||||
{ fg, bg, bold, dim, italic, underline }
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct StyleTagRegistry {
|
||||
entries : Map[String, TextStyle]
|
||||
}
|
||||
|
||||
///|
|
||||
fn normalize_style_tag_name(name : String) -> String {
|
||||
name.trim().to_lower().to_owned()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn style_tag_registry() -> StyleTagRegistry {
|
||||
{ entries: {} }
|
||||
}
|
||||
|
||||
///|
|
||||
fn merge_text_style(base : TextStyle, overlay : TextStyle) -> TextStyle {
|
||||
{
|
||||
fg: match overlay.fg {
|
||||
@@ -66,91 +76,113 @@ fn merge_text_style(base : TextStyle, overlay : TextStyle) -> TextStyle {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn StyleTagRegistry::set_tag(
|
||||
self : StyleTagRegistry,
|
||||
name : String,
|
||||
style~ : TextStyle = text_style(),
|
||||
fg~ : String? = None,
|
||||
bg~ : String? = None,
|
||||
bold~ : Bool = false,
|
||||
dim~ : Bool = false,
|
||||
italic~ : Bool = false,
|
||||
underline~ : Bool = false,
|
||||
style? : TextStyle = text_style(),
|
||||
fg? : String? = None,
|
||||
bg? : String? = None,
|
||||
bold? : Bool = false,
|
||||
dim? : Bool = false,
|
||||
italic? : Bool = false,
|
||||
underline? : Bool = false,
|
||||
) -> StyleTagRegistry {
|
||||
let overlay = text_style(fg=fg, bg=bg, bold=bold, dim=dim, italic=italic, underline=underline)
|
||||
self.entries[normalize_style_tag_name(name)] = merge_text_style(style, overlay)
|
||||
let overlay = text_style(fg~, bg~, bold~, dim~, italic~, underline~)
|
||||
self.entries[normalize_style_tag_name(name)] = merge_text_style(
|
||||
style, overlay,
|
||||
)
|
||||
self
|
||||
}
|
||||
|
||||
pub fn StyleTagRegistry::get(self : StyleTagRegistry, name : String) -> TextStyle? {
|
||||
///|
|
||||
pub fn StyleTagRegistry::get(
|
||||
self : StyleTagRegistry,
|
||||
name : String,
|
||||
) -> TextStyle? {
|
||||
self.entries.get(normalize_style_tag_name(name))
|
||||
}
|
||||
|
||||
pub fn StyleTagRegistry::contains(self : StyleTagRegistry, name : String) -> Bool {
|
||||
///|
|
||||
pub fn StyleTagRegistry::contains(
|
||||
self : StyleTagRegistry,
|
||||
name : String,
|
||||
) -> Bool {
|
||||
self.entries.contains(normalize_style_tag_name(name))
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn StyleTagRegistry::define_alias(
|
||||
self : StyleTagRegistry,
|
||||
name : String,
|
||||
target : String,
|
||||
) -> StyleTagRegistry {
|
||||
match self.get(target) {
|
||||
Some(style) => self.set_tag(name, style=style)
|
||||
None => match global_style_tag_registry().get(target) {
|
||||
Some(style) => self.set_tag(name, style=style)
|
||||
None => match builtin_text_style_for_tag(normalize_style_tag_name(target)) {
|
||||
Some(style) => self.set_tag(name, style=style)
|
||||
None => self
|
||||
Some(style) => self.set_tag(name, style~)
|
||||
None =>
|
||||
match global_style_tag_registry().get(target) {
|
||||
Some(style) => self.set_tag(name, style~)
|
||||
None =>
|
||||
match builtin_text_style_for_tag(normalize_style_tag_name(target)) {
|
||||
Some(style) => self.set_tag(name, style~)
|
||||
None => self
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn default_style_tag_registry() -> StyleTagRegistry {
|
||||
style_tag_registry()
|
||||
.set_tag("black", fg=Some("black"))
|
||||
.set_tag("red", fg=Some("red"))
|
||||
.set_tag("green", fg=Some("green"))
|
||||
.set_tag("yellow", fg=Some("yellow"))
|
||||
.set_tag("blue", fg=Some("blue"))
|
||||
.set_tag("magenta", fg=Some("magenta"))
|
||||
.set_tag("cyan", fg=Some("cyan"))
|
||||
.set_tag("white", fg=Some("white"))
|
||||
.set_tag("bright_black", fg=Some("bright_black"))
|
||||
.set_tag("bright_red", fg=Some("bright_red"))
|
||||
.set_tag("bright_green", fg=Some("bright_green"))
|
||||
.set_tag("bright_yellow", fg=Some("bright_yellow"))
|
||||
.set_tag("bright_blue", fg=Some("bright_blue"))
|
||||
.set_tag("bright_magenta", fg=Some("bright_magenta"))
|
||||
.set_tag("bright_cyan", fg=Some("bright_cyan"))
|
||||
.set_tag("bright_white", fg=Some("bright_white"))
|
||||
.set_tag("accent", fg=Some("bright_cyan"), bold=true)
|
||||
.set_tag("info", fg=Some("cyan"))
|
||||
.set_tag("success", fg=Some("green"), bold=true)
|
||||
.set_tag("warning", fg=Some("yellow"), bold=true)
|
||||
.set_tag("danger", fg=Some("red"), bold=true)
|
||||
.set_tag("muted", fg=Some("bright_black"), dim=true)
|
||||
.set_tag("b", bold=true)
|
||||
.set_tag("dim", dim=true)
|
||||
.set_tag("i", italic=true)
|
||||
.set_tag("u", underline=true)
|
||||
.set_tag("black", fg=Some("black"))
|
||||
.set_tag("red", fg=Some("red"))
|
||||
.set_tag("green", fg=Some("green"))
|
||||
.set_tag("yellow", fg=Some("yellow"))
|
||||
.set_tag("blue", fg=Some("blue"))
|
||||
.set_tag("magenta", fg=Some("magenta"))
|
||||
.set_tag("cyan", fg=Some("cyan"))
|
||||
.set_tag("white", fg=Some("white"))
|
||||
.set_tag("bright_black", fg=Some("bright_black"))
|
||||
.set_tag("bright_red", fg=Some("bright_red"))
|
||||
.set_tag("bright_green", fg=Some("bright_green"))
|
||||
.set_tag("bright_yellow", fg=Some("bright_yellow"))
|
||||
.set_tag("bright_blue", fg=Some("bright_blue"))
|
||||
.set_tag("bright_magenta", fg=Some("bright_magenta"))
|
||||
.set_tag("bright_cyan", fg=Some("bright_cyan"))
|
||||
.set_tag("bright_white", fg=Some("bright_white"))
|
||||
.set_tag("accent", fg=Some("bright_cyan"), bold=true)
|
||||
.set_tag("info", fg=Some("cyan"))
|
||||
.set_tag("success", fg=Some("green"), bold=true)
|
||||
.set_tag("warning", fg=Some("yellow"), bold=true)
|
||||
.set_tag("danger", fg=Some("red"), bold=true)
|
||||
.set_tag("muted", fg=Some("bright_black"), dim=true)
|
||||
.set_tag("b", bold=true)
|
||||
.set_tag("dim", dim=true)
|
||||
.set_tag("i", italic=true)
|
||||
.set_tag("u", underline=true)
|
||||
}
|
||||
|
||||
let global_style_tag_registry_ref : Ref[StyleTagRegistry] = Ref(style_tag_registry())
|
||||
///|
|
||||
let global_style_tag_registry_ref : Ref[StyleTagRegistry] = Ref(
|
||||
style_tag_registry(),
|
||||
)
|
||||
|
||||
///|
|
||||
pub fn global_style_tag_registry() -> StyleTagRegistry {
|
||||
global_style_tag_registry_ref.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn set_global_style_tag_registry(registry : StyleTagRegistry) -> Unit {
|
||||
global_style_tag_registry_ref.val = registry
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn reset_global_style_tag_registry() -> Unit {
|
||||
global_style_tag_registry_ref.val = style_tag_registry()
|
||||
}
|
||||
|
||||
///|
|
||||
priv struct InlineStyle {
|
||||
fg_code : String?
|
||||
bg_code : String?
|
||||
@@ -162,24 +194,29 @@ priv struct InlineStyle {
|
||||
underline : Bool
|
||||
}
|
||||
|
||||
///|
|
||||
priv struct StyledSegment {
|
||||
text : String
|
||||
style : InlineStyle
|
||||
}
|
||||
|
||||
///|
|
||||
priv struct StyleFrame {
|
||||
tag : String
|
||||
style : InlineStyle
|
||||
}
|
||||
|
||||
///|
|
||||
fn code_unit(ch : Char) -> Int {
|
||||
ch.to_int()
|
||||
}
|
||||
|
||||
///|
|
||||
fn code_unit16(ch : UInt16) -> Int {
|
||||
ch.to_int()
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct TextFormatter {
|
||||
show_timestamp : Bool
|
||||
show_level : Bool
|
||||
@@ -196,20 +233,21 @@ pub struct TextFormatter {
|
||||
style_tags : StyleTagRegistry?
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn text_formatter(
|
||||
show_timestamp~ : Bool = true,
|
||||
show_level~ : Bool = true,
|
||||
show_target~ : Bool = true,
|
||||
show_fields~ : Bool = true,
|
||||
separator~ : String = " ",
|
||||
field_separator~ : String = " ",
|
||||
template~ : String = "",
|
||||
color_mode~ : ColorMode = ColorMode::Never,
|
||||
color_support~ : ColorSupport = ColorSupport::TrueColor,
|
||||
style_markup~ : StyleMarkupMode = StyleMarkupMode::Full,
|
||||
target_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||
fields_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||
style_tags~ : StyleTagRegistry? = None,
|
||||
show_timestamp? : Bool = true,
|
||||
show_level? : Bool = true,
|
||||
show_target? : Bool = true,
|
||||
show_fields? : Bool = true,
|
||||
separator? : String = " ",
|
||||
field_separator? : String = " ",
|
||||
template? : String = "",
|
||||
color_mode? : ColorMode = ColorMode::Never,
|
||||
color_support? : ColorSupport = ColorSupport::TrueColor,
|
||||
style_markup? : StyleMarkupMode = StyleMarkupMode::Full,
|
||||
target_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||
fields_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||
style_tags? : StyleTagRegistry? = None,
|
||||
) -> TextFormatter {
|
||||
{
|
||||
show_timestamp,
|
||||
@@ -228,6 +266,7 @@ pub fn text_formatter(
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn color_support_label(support : ColorSupport) -> String {
|
||||
match support {
|
||||
ColorSupport::Basic => "basic"
|
||||
@@ -235,7 +274,11 @@ pub fn color_support_label(support : ColorSupport) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn TextFormatter::with_color_support(self : TextFormatter, color_support : ColorSupport) -> TextFormatter {
|
||||
///|
|
||||
pub fn TextFormatter::with_color_support(
|
||||
self : TextFormatter,
|
||||
color_support : ColorSupport,
|
||||
) -> TextFormatter {
|
||||
text_formatter(
|
||||
show_timestamp=self.show_timestamp,
|
||||
show_level=self.show_level,
|
||||
@@ -245,7 +288,7 @@ pub fn TextFormatter::with_color_support(self : TextFormatter, color_support : C
|
||||
field_separator=self.field_separator,
|
||||
template=self.template,
|
||||
color_mode=self.color_mode,
|
||||
color_support=color_support,
|
||||
color_support~,
|
||||
style_markup=self.style_markup,
|
||||
target_style_markup=self.target_style_markup,
|
||||
fields_style_markup=self.fields_style_markup,
|
||||
@@ -253,6 +296,7 @@ pub fn TextFormatter::with_color_support(self : TextFormatter, color_support : C
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn style_markup_mode_label(mode : StyleMarkupMode) -> String {
|
||||
match mode {
|
||||
StyleMarkupMode::Disabled => "disabled"
|
||||
@@ -261,7 +305,11 @@ pub fn style_markup_mode_label(mode : StyleMarkupMode) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn TextFormatter::with_style_markup(self : TextFormatter, style_markup : StyleMarkupMode) -> TextFormatter {
|
||||
///|
|
||||
pub fn TextFormatter::with_style_markup(
|
||||
self : TextFormatter,
|
||||
style_markup : StyleMarkupMode,
|
||||
) -> TextFormatter {
|
||||
text_formatter(
|
||||
show_timestamp=self.show_timestamp,
|
||||
show_level=self.show_level,
|
||||
@@ -272,17 +320,21 @@ pub fn TextFormatter::with_style_markup(self : TextFormatter, style_markup : Sty
|
||||
template=self.template,
|
||||
color_mode=self.color_mode,
|
||||
color_support=self.color_support,
|
||||
style_markup=style_markup,
|
||||
style_markup~,
|
||||
target_style_markup=self.target_style_markup,
|
||||
fields_style_markup=self.fields_style_markup,
|
||||
style_tags=self.style_tags,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn TextFormatter::without_style_markup(self : TextFormatter) -> TextFormatter {
|
||||
///|
|
||||
pub fn TextFormatter::without_style_markup(
|
||||
self : TextFormatter,
|
||||
) -> TextFormatter {
|
||||
self.with_style_markup(StyleMarkupMode::Disabled)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn TextFormatter::with_target_style_markup(
|
||||
self : TextFormatter,
|
||||
style_markup : StyleMarkupMode,
|
||||
@@ -304,6 +356,7 @@ pub fn TextFormatter::with_target_style_markup(
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn TextFormatter::with_fields_style_markup(
|
||||
self : TextFormatter,
|
||||
style_markup : StyleMarkupMode,
|
||||
@@ -325,7 +378,11 @@ pub fn TextFormatter::with_fields_style_markup(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn TextFormatter::with_style_tags(self : TextFormatter, style_tags : StyleTagRegistry) -> TextFormatter {
|
||||
///|
|
||||
pub fn TextFormatter::with_style_tags(
|
||||
self : TextFormatter,
|
||||
style_tags : StyleTagRegistry,
|
||||
) -> TextFormatter {
|
||||
text_formatter(
|
||||
show_timestamp=self.show_timestamp,
|
||||
show_level=self.show_level,
|
||||
@@ -343,6 +400,7 @@ pub fn TextFormatter::with_style_tags(self : TextFormatter, style_tags : StyleTa
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn color_mode_label(mode : ColorMode) -> String {
|
||||
match mode {
|
||||
ColorMode::Never => "never"
|
||||
@@ -351,17 +409,20 @@ pub fn color_mode_label(mode : ColorMode) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn use_ansi_color(mode : ColorMode) -> Bool {
|
||||
match mode {
|
||||
ColorMode::Never => false
|
||||
ColorMode::Always => true
|
||||
ColorMode::Auto => match @env.get_env_var("NO_COLOR") {
|
||||
Some(_) => false
|
||||
None => true
|
||||
}
|
||||
ColorMode::Auto =>
|
||||
match @env.get_env_var("NO_COLOR") {
|
||||
Some(_) => false
|
||||
None => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn ansi_wrap(text : String, code : String, enabled : Bool) -> String {
|
||||
if !enabled || text == "" {
|
||||
text
|
||||
@@ -370,7 +431,12 @@ fn ansi_wrap(text : String, code : String, enabled : Bool) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn ansi_wrap_with_style(text : String, style : InlineStyle, enabled : Bool) -> String {
|
||||
///|
|
||||
fn ansi_wrap_with_style(
|
||||
text : String,
|
||||
style : InlineStyle,
|
||||
enabled : Bool,
|
||||
) -> String {
|
||||
if !enabled || text == "" {
|
||||
text
|
||||
} else {
|
||||
@@ -404,6 +470,7 @@ fn ansi_wrap_with_style(text : String, style : InlineStyle, enabled : Bool) -> S
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn default_inline_style() -> InlineStyle {
|
||||
{
|
||||
fg_code: None,
|
||||
@@ -417,6 +484,7 @@ fn default_inline_style() -> InlineStyle {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn named_color_code(tag : String) -> String? {
|
||||
match tag {
|
||||
"black" => Some("30")
|
||||
@@ -439,6 +507,7 @@ fn named_color_code(tag : String) -> String? {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn named_bg_color_code(tag : String) -> String? {
|
||||
match tag {
|
||||
"black" => Some("40")
|
||||
@@ -461,6 +530,7 @@ fn named_bg_color_code(tag : String) -> String? {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn basic_name_from_hex(value : String) -> String {
|
||||
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
||||
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
||||
@@ -495,18 +565,17 @@ fn basic_name_from_hex(value : String) -> String {
|
||||
} else {
|
||||
"green"
|
||||
}
|
||||
} else if r > 96 && g < 96 {
|
||||
"magenta"
|
||||
} else if g > 96 && r < 96 {
|
||||
"cyan"
|
||||
} else {
|
||||
if r > 96 && g < 96 {
|
||||
"magenta"
|
||||
} else if g > 96 && r < 96 {
|
||||
"cyan"
|
||||
} else {
|
||||
"blue"
|
||||
}
|
||||
"blue"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn resolve_inline_color_code(
|
||||
formatter : TextFormatter,
|
||||
basic_name : String?,
|
||||
@@ -514,21 +583,25 @@ fn resolve_inline_color_code(
|
||||
) -> String {
|
||||
match formatter.color_support {
|
||||
ColorSupport::TrueColor => truecolor_code
|
||||
ColorSupport::Basic => match basic_name {
|
||||
Some(name) => named_code_from_basic_name(name).unwrap_or(truecolor_code)
|
||||
None => truecolor_code
|
||||
}
|
||||
ColorSupport::Basic =>
|
||||
match basic_name {
|
||||
Some(name) => named_code_from_basic_name(name).unwrap_or(truecolor_code)
|
||||
None => truecolor_code
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn named_code_from_basic_name(name : String) -> String? {
|
||||
named_color_code(name)
|
||||
}
|
||||
|
||||
///|
|
||||
fn named_bg_code_from_basic_name(name : String) -> String? {
|
||||
named_bg_color_code(name)
|
||||
}
|
||||
|
||||
///|
|
||||
fn resolve_inline_bg_code(
|
||||
formatter : TextFormatter,
|
||||
basic_name : String?,
|
||||
@@ -536,13 +609,16 @@ fn resolve_inline_bg_code(
|
||||
) -> String {
|
||||
match formatter.color_support {
|
||||
ColorSupport::TrueColor => truecolor_code
|
||||
ColorSupport::Basic => match basic_name {
|
||||
Some(name) => named_bg_code_from_basic_name(name).unwrap_or(truecolor_code)
|
||||
None => truecolor_code
|
||||
}
|
||||
ColorSupport::Basic =>
|
||||
match basic_name {
|
||||
Some(name) =>
|
||||
named_bg_code_from_basic_name(name).unwrap_or(truecolor_code)
|
||||
None => truecolor_code
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn is_hex_color(value : String) -> Bool {
|
||||
if value.length() != 7 {
|
||||
return false
|
||||
@@ -562,6 +638,7 @@ fn is_hex_color(value : String) -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
///|
|
||||
fn hex_to_int(ch : UInt16) -> Int {
|
||||
let code = code_unit16(ch)
|
||||
if code >= code_unit('0') && code <= code_unit('9') {
|
||||
@@ -573,10 +650,12 @@ fn hex_to_int(ch : UInt16) -> Int {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn hex_pair_to_int(high : UInt16, low : UInt16) -> Int {
|
||||
hex_to_int(high) * 16 + hex_to_int(low)
|
||||
}
|
||||
|
||||
///|
|
||||
fn rgb_fg_code(value : String) -> String {
|
||||
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
||||
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
||||
@@ -584,6 +663,7 @@ fn rgb_fg_code(value : String) -> String {
|
||||
"38;2;\{r};\{g};\{b}"
|
||||
}
|
||||
|
||||
///|
|
||||
fn rgb_bg_code(value : String) -> String {
|
||||
let r = hex_pair_to_int(value.unsafe_get(4), value.unsafe_get(5))
|
||||
let g = hex_pair_to_int(value.unsafe_get(6), value.unsafe_get(7))
|
||||
@@ -591,6 +671,7 @@ fn rgb_bg_code(value : String) -> String {
|
||||
"48;2;\{r};\{g};\{b}"
|
||||
}
|
||||
|
||||
///|
|
||||
fn rgb_bg_code_from_hex(value : String) -> String {
|
||||
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
||||
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
||||
@@ -598,6 +679,7 @@ fn rgb_bg_code_from_hex(value : String) -> String {
|
||||
"48;2;\{r};\{g};\{b}"
|
||||
}
|
||||
|
||||
///|
|
||||
fn inline_style_from_text_style(
|
||||
base : InlineStyle,
|
||||
style : TextStyle,
|
||||
@@ -609,15 +691,24 @@ fn inline_style_from_text_style(
|
||||
let normalized = normalize_style_tag_name(value)
|
||||
match named_color_code(normalized) {
|
||||
Some(code) => Some((Some(code), Some(normalized)))
|
||||
None => if is_hex_color(value) {
|
||||
let basic_name = basic_name_from_hex(value)
|
||||
Some((
|
||||
Some(resolve_inline_color_code(formatter, Some(basic_name), rgb_fg_code(value))),
|
||||
Some(basic_name),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None =>
|
||||
if is_hex_color(value) {
|
||||
let basic_name = basic_name_from_hex(value)
|
||||
Some(
|
||||
(
|
||||
Some(
|
||||
resolve_inline_color_code(
|
||||
formatter,
|
||||
Some(basic_name),
|
||||
rgb_fg_code(value),
|
||||
),
|
||||
),
|
||||
Some(basic_name),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -634,36 +725,48 @@ fn inline_style_from_text_style(
|
||||
}
|
||||
Some((Some(code), Some(bg_name)))
|
||||
}
|
||||
None => if is_hex_color(value) {
|
||||
let basic_name = basic_name_from_hex(value)
|
||||
Some((
|
||||
Some(resolve_inline_bg_code(formatter, Some(basic_name), rgb_bg_code_from_hex(value))),
|
||||
Some(basic_name),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None =>
|
||||
if is_hex_color(value) {
|
||||
let basic_name = basic_name_from_hex(value)
|
||||
Some(
|
||||
(
|
||||
Some(
|
||||
resolve_inline_bg_code(
|
||||
formatter,
|
||||
Some(basic_name),
|
||||
rgb_bg_code_from_hex(value),
|
||||
),
|
||||
),
|
||||
Some(basic_name),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
match fg {
|
||||
Some((next_fg_code, next_fg_name)) => match bg {
|
||||
Some((next_bg_code, next_bg_name)) => Some({
|
||||
fg_code: next_fg_code,
|
||||
bg_code: next_bg_code,
|
||||
fg_basic_name: next_fg_name,
|
||||
bg_basic_name: next_bg_name,
|
||||
bold: base.bold || style.bold,
|
||||
dim: base.dim || style.dim,
|
||||
italic: base.italic || style.italic,
|
||||
underline: base.underline || style.underline,
|
||||
})
|
||||
None => None
|
||||
}
|
||||
Some((next_fg_code, next_fg_name)) =>
|
||||
match bg {
|
||||
Some((next_bg_code, next_bg_name)) =>
|
||||
Some({
|
||||
fg_code: next_fg_code,
|
||||
bg_code: next_bg_code,
|
||||
fg_basic_name: next_fg_name,
|
||||
bg_basic_name: next_bg_name,
|
||||
bold: base.bold || style.bold,
|
||||
dim: base.dim || style.dim,
|
||||
italic: base.italic || style.italic,
|
||||
underline: base.underline || style.underline,
|
||||
})
|
||||
None => None
|
||||
}
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn builtin_text_style_for_tag(tag : String) -> TextStyle? {
|
||||
match normalize_style_tag_name(tag) {
|
||||
"black" => Some(text_style(fg=Some("black")))
|
||||
@@ -696,41 +799,63 @@ fn builtin_text_style_for_tag(tag : String) -> TextStyle? {
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_registered_text_style(tag : String, formatter : TextFormatter) -> TextStyle? {
|
||||
///|
|
||||
fn resolve_registered_text_style(
|
||||
tag : String,
|
||||
formatter : TextFormatter,
|
||||
) -> TextStyle? {
|
||||
let normalized = normalize_style_tag_name(tag)
|
||||
match formatter.style_markup {
|
||||
StyleMarkupMode::Builtin => return builtin_text_style_for_tag(normalized)
|
||||
_ => ()
|
||||
}
|
||||
match formatter.style_tags {
|
||||
Some(registry) => match registry.get(normalized) {
|
||||
Some(style) => Some(style)
|
||||
None => match global_style_tag_registry().get(normalized) {
|
||||
Some(registry) =>
|
||||
match registry.get(normalized) {
|
||||
Some(style) => Some(style)
|
||||
None =>
|
||||
match global_style_tag_registry().get(normalized) {
|
||||
Some(style) => Some(style)
|
||||
None => builtin_text_style_for_tag(normalized)
|
||||
}
|
||||
}
|
||||
None =>
|
||||
match global_style_tag_registry().get(normalized) {
|
||||
Some(style) => Some(style)
|
||||
None => builtin_text_style_for_tag(normalized)
|
||||
}
|
||||
}
|
||||
None => match global_style_tag_registry().get(normalized) {
|
||||
Some(style) => Some(style)
|
||||
None => builtin_text_style_for_tag(normalized)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_inline_tag(style : InlineStyle, tag : String, formatter : TextFormatter) -> InlineStyle? {
|
||||
///|
|
||||
fn apply_inline_tag(
|
||||
style : InlineStyle,
|
||||
tag : String,
|
||||
formatter : TextFormatter,
|
||||
) -> InlineStyle? {
|
||||
let normalized = normalize_style_tag_name(tag)
|
||||
if is_hex_color(tag) {
|
||||
let basic_name = basic_name_from_hex(tag)
|
||||
Some({
|
||||
..style,
|
||||
fg_code: Some(resolve_inline_color_code(formatter, Some(basic_name), rgb_fg_code(tag))),
|
||||
fg_code: Some(
|
||||
resolve_inline_color_code(formatter, Some(basic_name), rgb_fg_code(tag)),
|
||||
),
|
||||
fg_basic_name: Some(basic_name),
|
||||
})
|
||||
} else if normalized.length() == 10 && normalized.has_prefix("bg:") && is_hex_color(normalized[3:].to_owned()) {
|
||||
} else if normalized.length() == 10 &&
|
||||
normalized.has_prefix("bg:") &&
|
||||
is_hex_color(normalized[3:].to_owned()) {
|
||||
let basic_name = basic_name_from_hex(normalized[3:].to_owned())
|
||||
Some({
|
||||
..style,
|
||||
bg_code: Some(resolve_inline_bg_code(formatter, Some(basic_name), rgb_bg_code(normalized))),
|
||||
bg_code: Some(
|
||||
resolve_inline_bg_code(
|
||||
formatter,
|
||||
Some(basic_name),
|
||||
rgb_bg_code(normalized),
|
||||
),
|
||||
),
|
||||
bg_basic_name: Some(basic_name),
|
||||
})
|
||||
} else {
|
||||
@@ -741,6 +866,7 @@ fn apply_inline_tag(style : InlineStyle, tag : String, formatter : TextFormatter
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn push_plain_segment(
|
||||
segments : Array[StyledSegment],
|
||||
buffer : StringBuilder,
|
||||
@@ -753,6 +879,7 @@ fn push_plain_segment(
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn pop_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
||||
let normalized = normalize_style_tag_name(tag)
|
||||
if stack.length() <= 1 {
|
||||
@@ -769,6 +896,7 @@ fn pop_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
///|
|
||||
fn has_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
||||
let normalized = normalize_style_tag_name(tag)
|
||||
if stack.length() <= 1 {
|
||||
@@ -782,7 +910,11 @@ fn has_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn parse_inline_markup(input : String, formatter : TextFormatter) -> Array[StyledSegment] {
|
||||
///|
|
||||
fn parse_inline_markup(
|
||||
input : String,
|
||||
formatter : TextFormatter,
|
||||
) -> Array[StyledSegment] {
|
||||
let segments : Array[StyledSegment] = []
|
||||
let buffer = StringBuilder::new()
|
||||
let stack : Array[StyleFrame] = [{ tag: "", style: default_inline_style() }]
|
||||
@@ -845,7 +977,12 @@ fn parse_inline_markup(input : String, formatter : TextFormatter) -> Array[Style
|
||||
segments
|
||||
}
|
||||
|
||||
fn render_styled_text(text : String, formatter : TextFormatter, mode : StyleMarkupMode) -> String {
|
||||
///|
|
||||
fn render_styled_text(
|
||||
text : String,
|
||||
formatter : TextFormatter,
|
||||
mode : StyleMarkupMode,
|
||||
) -> String {
|
||||
match mode {
|
||||
StyleMarkupMode::Disabled => return text
|
||||
_ => ()
|
||||
@@ -860,10 +997,12 @@ fn render_styled_text(text : String, formatter : TextFormatter, mode : StyleMark
|
||||
out.to_string()
|
||||
}
|
||||
|
||||
///|
|
||||
fn render_inline_markup(message : String, formatter : TextFormatter) -> String {
|
||||
render_styled_text(message, formatter, formatter.style_markup)
|
||||
}
|
||||
|
||||
///|
|
||||
fn level_ansi_code(level : @core.Level) -> String {
|
||||
match level {
|
||||
@core.Level::Trace => "90"
|
||||
@@ -874,6 +1013,7 @@ fn level_ansi_code(level : @core.Level) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn fields_to_json(fields : Array[@core.Field]) -> Json {
|
||||
let obj : Map[String, Json] = {}
|
||||
for item in fields {
|
||||
@@ -882,58 +1022,89 @@ fn fields_to_json(fields : Array[@core.Field]) -> Json {
|
||||
Json::object(obj)
|
||||
}
|
||||
|
||||
///|
|
||||
fn timestamp_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||
if formatter.show_timestamp && rec.timestamp_ms != 0UL {
|
||||
ansi_wrap(rec.timestamp_ms.to_string(), "90", use_ansi_color(formatter.color_mode))
|
||||
ansi_wrap(
|
||||
rec.timestamp_ms.to_string(),
|
||||
"90",
|
||||
use_ansi_color(formatter.color_mode),
|
||||
)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn level_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||
if formatter.show_level {
|
||||
ansi_wrap(rec.level.label(), level_ansi_code(rec.level), use_ansi_color(formatter.color_mode))
|
||||
ansi_wrap(
|
||||
rec.level.label(),
|
||||
level_ansi_code(rec.level),
|
||||
use_ansi_color(formatter.color_mode),
|
||||
)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn target_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||
if formatter.show_target && rec.target != "" {
|
||||
let rendered = render_styled_text(rec.target, formatter, formatter.target_style_markup)
|
||||
let rendered = render_styled_text(
|
||||
rec.target,
|
||||
formatter,
|
||||
formatter.target_style_markup,
|
||||
)
|
||||
ansi_wrap(rendered, "34", use_ansi_color(formatter.color_mode))
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn format_field_text(field : @core.Field, formatter : TextFormatter) -> String {
|
||||
let value = render_styled_text(field.value, formatter, formatter.fields_style_markup)
|
||||
let value = render_styled_text(
|
||||
field.value,
|
||||
formatter,
|
||||
formatter.fields_style_markup,
|
||||
)
|
||||
"\{field.key}=\{value}"
|
||||
}
|
||||
|
||||
///|
|
||||
fn fields_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||
if formatter.show_fields && rec.fields.length() != 0 {
|
||||
let content = rec.fields.map(fn(field) { format_field_text(field, formatter) }).join(formatter.field_separator)
|
||||
let content = rec.fields
|
||||
.map(fn(field) { format_field_text(field, formatter) })
|
||||
.join(formatter.field_separator)
|
||||
ansi_wrap(content, "35", use_ansi_color(formatter.color_mode))
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn render_template(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||
formatter.template
|
||||
.replace_all(old="{timestamp}", new=timestamp_text(rec, formatter))
|
||||
.replace_all(old="{timestamp_ms}", new=timestamp_text(rec, formatter))
|
||||
.replace_all(old="{level}", new=level_text(rec, formatter))
|
||||
.replace_all(old="{target}", new=target_text(rec, formatter))
|
||||
.replace_all(old="{message}", new=render_inline_markup(rec.message, formatter))
|
||||
.replace_all(old="{fields}", new=fields_text(rec, formatter))
|
||||
.trim()
|
||||
.to_owned()
|
||||
.replace_all(old="{timestamp}", new=timestamp_text(rec, formatter))
|
||||
.replace_all(old="{timestamp_ms}", new=timestamp_text(rec, formatter))
|
||||
.replace_all(old="{level}", new=level_text(rec, formatter))
|
||||
.replace_all(old="{target}", new=target_text(rec, formatter))
|
||||
.replace_all(
|
||||
old="{message}",
|
||||
new=render_inline_markup(rec.message, formatter),
|
||||
)
|
||||
.replace_all(old="{fields}", new=fields_text(rec, formatter))
|
||||
.trim()
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
pub fn format_text(rec : @core.Record, formatter~ : TextFormatter = text_formatter()) -> String {
|
||||
///|
|
||||
pub fn format_text(
|
||||
rec : @core.Record,
|
||||
formatter? : TextFormatter = text_formatter(),
|
||||
) -> String {
|
||||
if formatter.template != "" {
|
||||
return render_template(rec, formatter)
|
||||
}
|
||||
@@ -957,6 +1128,7 @@ pub fn format_text(rec : @core.Record, formatter~ : TextFormatter = text_formatt
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn format_json(rec : @core.Record) -> String {
|
||||
let obj : Map[String, Json] = {
|
||||
"level": Json::string(rec.level.label()),
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core" @core,
|
||||
"maria/json_parser" @json_parser,
|
||||
"moonbitlang/core/env" @env,
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"maria/json_parser",
|
||||
"moonbitlang/core/env",
|
||||
"moonbitlang/core/json",
|
||||
"moonbitlang/core/ref",
|
||||
}
|
||||
|
||||
+33
-22
@@ -1,21 +1,22 @@
|
||||
///|
|
||||
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)
|
||||
}
|
||||
fn(rec) { rec.with_target(target) }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn prefix_message(prefix : String) -> RecordPatch {
|
||||
fn(rec) {
|
||||
rec.with_message("\{prefix}\{rec.message}")
|
||||
}
|
||||
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 {
|
||||
@@ -28,30 +29,40 @@ pub fn append_fields(extra_fields : Array[@core.Field]) -> RecordPatch {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn redact_field(key : String, placeholder~ : String = "***") -> RecordPatch {
|
||||
///|
|
||||
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
|
||||
}
|
||||
}))
|
||||
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 {
|
||||
///|
|
||||
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
|
||||
}
|
||||
}))
|
||||
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
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
///|
|
||||
pub struct RuntimeFileState {
|
||||
file : FileSinkState
|
||||
queued : Bool
|
||||
@@ -5,16 +6,20 @@ pub struct RuntimeFileState {
|
||||
dropped_count : Int
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeFileState::new(
|
||||
file : FileSinkState,
|
||||
queued~ : Bool = false,
|
||||
pending_count~ : Int = 0,
|
||||
dropped_count~ : Int = 0,
|
||||
queued? : Bool = false,
|
||||
pending_count? : Int = 0,
|
||||
dropped_count? : Int = 0,
|
||||
) -> RuntimeFileState {
|
||||
{ file, queued, pending_count, dropped_count }
|
||||
}
|
||||
|
||||
fn file_sink_policy_to_json_value(policy : FileSinkPolicy) -> @json_parser.JsonValue {
|
||||
///|
|
||||
fn file_sink_policy_to_json_value(
|
||||
policy : FileSinkPolicy,
|
||||
) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"append": @json_parser.JsonValue::Bool(policy.append),
|
||||
"auto_flush": @json_parser.JsonValue::Bool(policy.auto_flush),
|
||||
@@ -26,11 +31,18 @@ fn file_sink_policy_to_json_value(policy : FileSinkPolicy) -> @json_parser.JsonV
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
pub fn file_sink_policy_to_json(policy : FileSinkPolicy) -> @json_parser.JsonValue {
|
||||
///|
|
||||
pub fn file_sink_policy_to_json(
|
||||
policy : FileSinkPolicy,
|
||||
) -> @json_parser.JsonValue {
|
||||
file_sink_policy_to_json_value(policy)
|
||||
}
|
||||
|
||||
pub fn stringify_file_sink_policy(policy : FileSinkPolicy, pretty~ : Bool = false) -> String {
|
||||
///|
|
||||
pub fn stringify_file_sink_policy(
|
||||
policy : FileSinkPolicy,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
let value = file_sink_policy_to_json_value(policy)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
@@ -39,16 +51,27 @@ pub fn stringify_file_sink_policy(policy : FileSinkPolicy, pretty~ : Bool = fals
|
||||
}
|
||||
}
|
||||
|
||||
fn file_sink_state_to_json_value(state : FileSinkState) -> @json_parser.JsonValue {
|
||||
///|
|
||||
fn file_sink_state_to_json_value(
|
||||
state : FileSinkState,
|
||||
) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"path": @json_parser.JsonValue::String(state.path),
|
||||
"available": @json_parser.JsonValue::Bool(state.available),
|
||||
"append": @json_parser.JsonValue::Bool(state.append),
|
||||
"auto_flush": @json_parser.JsonValue::Bool(state.auto_flush),
|
||||
"open_failures": @json_parser.JsonValue::Number(state.open_failures.to_double()),
|
||||
"write_failures": @json_parser.JsonValue::Number(state.write_failures.to_double()),
|
||||
"flush_failures": @json_parser.JsonValue::Number(state.flush_failures.to_double()),
|
||||
"rotation_failures": @json_parser.JsonValue::Number(state.rotation_failures.to_double()),
|
||||
"open_failures": @json_parser.JsonValue::Number(
|
||||
state.open_failures.to_double(),
|
||||
),
|
||||
"write_failures": @json_parser.JsonValue::Number(
|
||||
state.write_failures.to_double(),
|
||||
),
|
||||
"flush_failures": @json_parser.JsonValue::Number(
|
||||
state.flush_failures.to_double(),
|
||||
),
|
||||
"rotation_failures": @json_parser.JsonValue::Number(
|
||||
state.rotation_failures.to_double(),
|
||||
),
|
||||
}
|
||||
match state.rotation {
|
||||
None => obj["rotation"] = @json_parser.JsonValue::Null
|
||||
@@ -57,11 +80,16 @@ fn file_sink_state_to_json_value(state : FileSinkState) -> @json_parser.JsonValu
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {
|
||||
file_sink_state_to_json_value(state)
|
||||
}
|
||||
|
||||
pub fn stringify_file_sink_state(state : FileSinkState, pretty~ : Bool = false) -> String {
|
||||
///|
|
||||
pub fn stringify_file_sink_state(
|
||||
state : FileSinkState,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
let value = file_sink_state_to_json_value(state)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
@@ -70,16 +98,27 @@ pub fn stringify_file_sink_state(state : FileSinkState, pretty~ : Bool = false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn runtime_file_state_to_json(state : RuntimeFileState) -> @json_parser.JsonValue {
|
||||
///|
|
||||
pub fn runtime_file_state_to_json(
|
||||
state : RuntimeFileState,
|
||||
) -> @json_parser.JsonValue {
|
||||
@json_parser.JsonValue::Object({
|
||||
"file": file_sink_state_to_json_value(state.file),
|
||||
"queued": @json_parser.JsonValue::Bool(state.queued),
|
||||
"pending_count": @json_parser.JsonValue::Number(state.pending_count.to_double()),
|
||||
"dropped_count": @json_parser.JsonValue::Number(state.dropped_count.to_double()),
|
||||
"pending_count": @json_parser.JsonValue::Number(
|
||||
state.pending_count.to_double(),
|
||||
),
|
||||
"dropped_count": @json_parser.JsonValue::Number(
|
||||
state.dropped_count.to_double(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn stringify_runtime_file_state(state : RuntimeFileState, pretty~ : Bool = false) -> String {
|
||||
///|
|
||||
pub fn stringify_runtime_file_state(
|
||||
state : RuntimeFileState,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
let value = runtime_file_state_to_json(state)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
|
||||
+29
-14
@@ -1,8 +1,10 @@
|
||||
///|
|
||||
pub struct FileRotation {
|
||||
max_bytes : Int
|
||||
max_backups : Int
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FileSinkState {
|
||||
path : String
|
||||
available : Bool
|
||||
@@ -15,30 +17,33 @@ pub struct FileSinkState {
|
||||
rotation_failures : Int
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FileSinkPolicy {
|
||||
append : Bool
|
||||
auto_flush : Bool
|
||||
rotation : FileRotation?
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSinkPolicy::new(
|
||||
append~ : Bool = true,
|
||||
auto_flush~ : Bool = true,
|
||||
rotation~ : FileRotation? = None,
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : FileRotation? = None,
|
||||
) -> FileSinkPolicy {
|
||||
{ append, auto_flush, rotation }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSinkState::new(
|
||||
path : String,
|
||||
available~ : Bool = false,
|
||||
append~ : Bool = true,
|
||||
auto_flush~ : Bool = true,
|
||||
rotation~ : FileRotation? = None,
|
||||
open_failures~ : Int = 0,
|
||||
write_failures~ : Int = 0,
|
||||
flush_failures~ : Int = 0,
|
||||
rotation_failures~ : Int = 0,
|
||||
available? : Bool = false,
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : FileRotation? = None,
|
||||
open_failures? : Int = 0,
|
||||
write_failures? : Int = 0,
|
||||
flush_failures? : Int = 0,
|
||||
rotation_failures? : Int = 0,
|
||||
) -> FileSinkState {
|
||||
{
|
||||
path,
|
||||
@@ -53,13 +58,23 @@ pub fn FileSinkState::new(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_rotation(max_bytes : Int, max_backups~ : Int = 1) -> FileRotation {
|
||||
///|
|
||||
pub fn file_rotation(max_bytes : Int, max_backups? : Int = 1) -> FileRotation {
|
||||
{
|
||||
max_bytes: if max_bytes <= 0 { 1 } else { max_bytes },
|
||||
max_backups: if max_backups <= 0 { 1 } else { max_backups },
|
||||
max_bytes: if max_bytes <= 0 {
|
||||
1
|
||||
} else {
|
||||
max_bytes
|
||||
},
|
||||
max_backups: if max_backups <= 0 {
|
||||
1
|
||||
} else {
|
||||
max_backups
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub(all) enum QueueOverflowPolicy {
|
||||
DropNewest
|
||||
DropOldest
|
||||
|
||||
Reference in New Issue
Block a user