13 个版本
0.1.13 | 2024 年 6 月 25 日 |
---|---|
0.1.11 | 2024 年 6 月 25 日 |
0.1.4 | 2024 年 2 月 11 日 |
在 命令行界面 中排名 107
每月下载量 33
85KB
2K SLoC
jlf
cat ./examples/dummy_logs | jlf
给定以下日志文件
{"timestamp": "2024-02-09T07:22:41.439284", "level": "DEBUG", "message": "User logged in successfully", "data": {"user_id": 3175, "session_id": "Nsb3P5mZ7971NFIt", "ip_address": "149.215.200.169", "action": "login", "success": false, "error_code": null}}
{"timestamp": "2024-02-09T07:22:42.439284", "level": "ERROR", "message": "Database connection established", "data": {"user_id": 8466, "session_id": "ZMOXKPna3GbzWz2N", "ip_address": "213.135.167.95", "action": "logout", "success": true, "error_code": null}}
...
它将输出更丰富多彩且可读的日志,如下所示
安装
Cargo
cargo install jlf
手动安装
您也可以克隆仓库并手动安装。
git clone https://github.com/PoOnesNerfect/jlf.git
cd jlf
cargo install --path . --locked
CLI 选项
$ jlf -h
JSON Log Formatter CLI
Usage: jlf [OPTIONS] [FORMAT_STRING]
Arguments:
[FORMAT_STRING] [default: "{#log}{#if spans|data}\\n{spans|data:json}{/if}"]
Options:
-n, --no-color Disable color output. If output is not a terminal, this is always true
-c, --compact Display log with data in a compact format
-s, --strict If log line is not valid JSON, then report it and exit, instead of printing the line as is
-t, --take <TAKE> Take only the first N lines
-h, --help Print help
-V, --version Print version
自定义格式化
您可以提供自定义的输出行格式。
cat ./examples/dummy_logs | jlf '{#log}{#if spans|data}\n{spans|data}{/if}'
上述提供的格式是默认格式,所以它将以默认格式输出。
{#log}
是一个函数 log
,这是一个方便函数,用于打印基本日志格式。目前,函数功能还处于早期阶段,只有 log
函数可用。log
函数等价于格式 {timestamp:dimmed} {level|lvl:level} {message|msg|body}
。
{#if spans|data}...{/if}
是一个函数 if
,这是一个条件函数,如果字段 spans
或 data
存在,则打印该块内的内容。更多关于该函数行为的详细信息,请参阅 {#if}
\n
将打印换行。
{spans|data:json}
将以 json 格式打印 spans
或 data
字段。
{timestamp:dimmed}
表示命令行工具会在 JSON 中查找 timestamp
并以 dimmed
淡色打印。
level|lvl
表示命令行工具会在 JSON 中查找 level
和 lvl
并使用找到的第一个。这种样式也称为 level
,它是一种特殊样式,会根据级别(调试 = 绿色,信息 = 青色)着色级别。
{message|msg|body}
表示命令行工具会在 JSON 中查找 message
、msg
和 body
并使用找到的第一个。
打印整个 JSON
如果您想打印整个 JSON 行,只需使用 {}
。
cat ./examples/dummy_logs | jlf '{}'
您仍然可以提供样式。
cat ./examples/dummy_logs | jlf '{:compact,fg=green}'
样式
您可以通过在 :
后提供样式来为值提供样式。
cat ./examples/dummy_logs | jlf '{timestamp:bright blue,bg=red,bold} {level|lvl:level} {message|msg|body:fg=bright white}'
如果您有多个样式,可以使用 ,
分隔它们,例如 fg=red,bg=blue
。
您可以选择在 =
前提供样式类型。如果您不提供它,则默认为 fg
。
可用属性
dimmed
:使文本变暗bold
:使文本加粗fg={color}
:设置文本颜色{color}
:与fg={color}
相同bg={color}
:设置背景颜色indent={n}
:通过n
个空格缩进值key={color}
:设置键的颜色value={color}
:设置值的颜色str={color}
:设置字符串数据类型的颜色syntax={color}
:设置语法字符的颜色json
:将 JSON 值作为 JSON 打印;这是默认和唯一可用的格式,因此您不需要指定它compact
:在一行中打印level
:根据级别着色(调试 = 绿色,信息 = 青色)
{color}
是任何颜色值的占位符。
可用颜色
您可以在colors.md中查看所有可用的颜色。
函数
jlf中的函数以#
开头,位于{}
内部。
log
log
是一个便捷函数,用于打印基本日志格式。
cat ./examples/dummy_logs | jlf '{#log}'
equals
cat ./examples/dummy_logs | jlf '{timestamp:dimmed} {level|lvl:level} {message|msg|body}'
并将打印
2024-02-09T07:22:41.439284 DEBUG User logged in successfully
if
您可以使用{#if field}...{/if}
来有条件地打印块内的内容,如果该字段存在。
条件仅检查字段是否存在(或为null)或不存在,但不检查字段的真值。
如果字段存在且值为false
,它仍会打印块内的内容。
cat ./examples/dummy_logs | jlf '{#if spans|data}data: {spans|data:json}{/if}'
只有在spans
或data
字段存在时,才会打印data: { ... }
。
巧妙技巧
- 如果行不是JSON,它将直接按原样打印该行。
- 它会在将数据管道输入文件时删除所有ANSI转义码。
这意味着,您可以直接使用jlf
将非JSON日志管道输入文件,而不包含所有的ansi转义码。当您直接将其管道输入到终端时,它仍会像以前一样格式化日志。
很酷,对吧?
实现
JSON解析
程序不能假设传入的JSON日志的数据结构。无法保证管道日志的应用程序使用最佳实践进行日志记录,或者保持一致的结构。
因此,它必须能够动态解析任何JSON日志;这使我们不得不使用serde_json::Value
。
但我们能做得更好吗?答案是肯定的。
尽管我们无法假设日志的数据结构,但我们仍然可以针对JSON日志的常见特性进行优化。因此,我决定创建一个针对JSON日志优化的自定义JSON解析器。
常见JSON日志的一些特性
以下是我想针对每行日志进行优化的常见JSON日志的一些特性
- 每行日志通常不是超级巨大
- 日志行通常具有相似的结构
- 我们不需要转换数据;我们只需重新格式化它们。
优化
以下是针对上述项目实现的优化
- JSON对象被解析为键值对的vec,而不是map。
- 这样,我们不需要为每个键和值分配内存。
- 由于每行JSON日志具有相似的结构,我们可以重复使用已分配的现有vecs。
- 我们不需要为每行分配内存。
- 由于我们不需要转换数据,因此不要验证原始值。
- 我们使用日志字符串的
&str
切片,而不是为每个键和值分配新的String
。
基准测试
那么,它的性能如何?这是唯一重要的事情。
custom parse time: [987.52 ns 993.59 ns 1.0006 µs]
Found 12 outliers among 100 measurements (12.00%)
9 (9.00%) high mild
3 (3.00%) high severe
serde value parse time: [2.8045 µs 2.8357 µs 2.8729 µs]
Found 8 outliers among 100 measurements (8.00%)
4 (4.00%) high mild
4 (4.00%) high severe
serde structured parse time: [712.16 ns 714.93 ns 717.54 ns]
第一部分是自定义解析,第二部分是将解析为 serde_json::Value
解析,第三部分是将它反序列化为结构化的Rust对象。
时间是解析单行JSON日志所需的时间。
正如我们所见,我们的自定义解析器比 serde_json::Value
解析快约3倍。是的,它仍然比结构化解析慢,但我们的解析器在解析动态JSON数据时仍然非常快。
依赖项
~5–13MB
~150K SLoC