LogCLI 教程
本 LogCLI 教程将引导您学习以下概念
- 查询日志
- 对 Loki 实例执行元查询
- 对静态日志文件执行查询
前提条件
在开始之前,您需要具备以下条件
- Docker
- Docker-compose
- LogCLI 已安装在您的机器上(参见 LogCLI 安装)
提示
此外,您可以在我们的交互式学习环境中尝试此示例:LogCLI 教程。
这是一个已安装所有依赖项的完整配置环境。
在Grafana Killercoda 仓库中提供反馈、报告错误和提出问题。
场景
您是一家新物流公司的站点经理。该公司使用结构化日志来跟踪发送和接收的每批货物。载荷格式如下所示
{"timestamp": "2024-11-22T13:22:56.377884", "state": "New York", "city": "Buffalo", "package_id": "PKG34245", "package_type": "Documents", "package_size": "Medium", "package_status": "error", "note": "Out for delivery", "sender": {"name": "Sender27", "address": "144 Elm St, Buffalo, New York"}, "receiver": {"name": "Receiver4", "address": "260 Cedar Blvd, New York City, New York"}}
这些日志通过 Grafana Alloy 处理,提取标签和结构化元数据,然后存储在 Loki 中。您的任务是使用 LogCLI 监控日志并生成一份关于货物整体健康状况的报告。
设置
首先,我们需要克隆 Alloy Scenario 仓库并启动 mail-house 示例
- 克隆仓库
git clone https://github.com/grafana/alloy-scenarios.git
- 启动 mail-house 示例
docker compose -f alloy-scenarios/mail-house/docker-compose.yml up -d
这将启动 mail-house 示例并将 Loki 实例暴露在 https://:3100
。我们还包含了一个 Grafana 实例,用于验证 LogCLI 结果,可通过 https://:3000 访问。
将 LogCLI 连接到 Loki
要将 LogCLI 连接到 Loki 实例,您需要设置 LOKI_ADDR
环境变量
提示
如果您将此示例针对您自己的 Loki 实例运行并已配置身份验证,您还需要设置
LOKI_USERNAME
和LOKI_PASSWORD
环境变量。
export LOKI_ADDR=https://:3100
现在,让我们通过运行以下命令来验证连接
logcli labels
这应该会返回类似以下的输出
https://:3100/loki/api/v1/labels?end=1732282703894072000&start=1732279103894072000
package_size
service_name
state
这确认 LogCLI 已连接到 Loki 实例,我们现在知道日志包含以下标签:package_size
、service_name
和 state
。让我们对 Loki 运行一些查询,以便更好地了解我们的包裹物流。
查询日志
作为物流公司角色的一部分,我们需要生成一份关于货物整体健康状况的报告。不幸的是,我们只能访问控制台,无法使用 Grafana 来可视化数据。我们可以使用 LogCLI 来查询日志并生成报告。
查找所有关键包裹
要查找最近一小时内的所有关键包裹(默认回溯时间),我们可以运行以下查询
logcli query '{service_name="Delivery World"} | package_status="critical"'
这将返回所有 service_name
为 Delivery World
且 package_status
为 critical
的日志。输出将类似于以下内容
https://:3100/loki/api/v1/query_range?direction=BACKWARD&end=1732617594381712000&limit=30&query=%7Bservice_name%3D%22Delivery+World%22%7D+%7C+package_status%3D%22critical%22&start=1732613994381712000
Common labels: {package_status="critical", service_name="Delivery World"}
2024-11-26T10:39:52Z {package_id="PKG79755", package_size="Small", state="Texas"} {"timestamp": "2024-11-26T10:39:52.521602Z", "state": "Texas", "city": "Dallas", "package_id": "PKG79755", "package_type": "Clothing", "package_size": "Small", "package_status": "critical", "note": "In transit", "sender": {"name": "Sender38", "address": "906 Maple Ave, Dallas, Texas"}, "receiver": {"name": "Receiver41", "address": "455 Pine Rd, Dallas, Texas"}}
2024-11-26T10:39:50Z {package_id="PKG34018", package_size="Large", state="Illinois"} {"timestamp": "2024-11-26T10:39:50.510841Z", "state": "Illinois", "city": "Chicago", "package_id": "PKG34018", "package_type": "Clothing", "package_size": "Large", "package_status": "critical", "note": "Delayed due to weather", "sender": {"name": "Sender22", "address": "758 Elm St, Chicago, Illinois"}, "receiver": {"name": "Receiver10", "address": "441 Cedar Blvd, Naperville, Illinois"}}
假设我们要回溯查看最近 24 小时的日志,我们可以使用 --since
标志来指定时间范围
logcli query --since 24h '{service_name="Delivery World"} | package_status="critical"'
这将查询最近 24 小时内 package_status
为 critical
的所有日志。但它不会返回所有日志,只会返回前 30 条日志。我们可以使用 --limit
标志来指定返回的日志数量
logcli query --since 24h --limit 100 '{service_name="Delivery World"} | package_status="critical"'
指标查询
我们还可以使用 LogCLI 基于指标来查询日志。例如,作为站点报告的一部分,我们想计算过去 24 小时内每隔 1 小时从加州发出的包裹总数。我们可以使用以下查询
logcli query --since 24h 'sum(count_over_time({state="California"}[1h]))'
这将返回一个 JSON 对象,其中包含时间戳列表(Unix 格式)以及每隔 1 小时从加州发出的包裹数量。由于我们汇总了随时间变化的日志计数,我们将看到日志总数随时间稳定增长。输出将类似于以下内容
[
{
"metric": {},
"values": [
[
1733913765,
"46"
],
[
1733914110,
"114"
],
[
1733914455,
"179"
],
[
1733914800,
"250"
],
[
1733915145,
"318"
],
[
1733915490,
"392"
],
[
1733915835,
"396"
]
]
}
]
我们可以更进一步,根据 package_type
标签过滤日志。例如,我们可以计算过去 24 小时内每隔 1 小时从加州发出的文档数量
logcli query --since 24h 'sum(count_over_time({state="California"}| json | package_type= "Documents" [1h]))'
这将返回一个与上述类似的 JSON 对象,但仅显示过去 24 小时内每隔 1 小时从加州发出的文档数量趋势。
即时指标查询
即时指标查询是指标查询的一个子集,它返回特定时间点指标的值。这对于快速了解存储日志的聚合状态非常有用。
例如,我们可以使用以下查询来获取过去 5 分钟内从加州发出的包裹数量
logcli instant-query 'sum(count_over_time({state="California"}[5m]))'
这将返回一个类似于以下内容的结果
[
{
"metric": {},
"value": [
1732702998.725,
"58"
]
}
]
将查询结果写入文件
LogCLI 的另一个有用功能是将查询结果写入文件。这对于下载我们的库存报告结果非常有用。
首先,我们需要创建一个目录来存储日志
mkdir -p ./inventory
接下来,我们可以运行以下查询将日志写入 ./inventory
目录
logcli query \
--timezone=UTC \
--output=jsonl \
--parallel-duration="12h" \
--parallel-max-workers="4" \
--part-path-prefix="./inventory/inv" \
--since=24h \
'{service_name="Delivery World"}'
这将把过去 24 小时内 service_name
为 Delivery World
的所有日志写入 ./inventory
目录。日志将分成两个文件,每个文件包含 12 小时的日志。请注意,我们无需指定 --limit
,因为该标志会被 --parallel-duration
标志覆盖。
元查询
作为站点经理,保持良好数据卫生并确保 Loki 高效运行至关重要。理解日志中的标签和日志量在此过程中起着关键作用。除了查询日志,LogCLI 还支持对您的 Loki 实例进行元查询。元查询不返回日志数据,但提供有关日志结构和查询性能的洞察。以下示例演示了我们在内部运行的一些核心元查询,以更好地了解 Loki 实例的运行情况。
检查序列基数
保持 Loki 健康最重要的方面之一是监控序列基数。这是日志中唯一序列的数量。高序列基数可能导致性能问题和存储成本增加。我们可以使用 LogCLI 来检查日志的序列基数。
首先,让我们打印日志中有多少个唯一序列
logcli series '{}'
这将返回日志中所有唯一序列的列表。输出将类似于以下内容
{package_size="Small", service_name="Delivery World", state="Florida"}
{package_size="Medium", service_name="Delivery World", state="Florida"}
{package_size="Small", service_name="Delivery World", state="California"}
{package_size="Large", service_name="Delivery World", state="New York"}
{package_size="Small", service_name="Delivery World", state="Illinois"}
{package_size="Large", service_name="Delivery World", state="Florida"}
{package_size="Medium", service_name="Delivery World", state="Illinois"}
{package_size="Large", service_name="Delivery World", state="Texas"}
{package_size="Medium", service_name="Delivery World", state="California"}
{package_size="Medium", service_name="Delivery World", state="Texas"}
{package_size="Small", service_name="Delivery World", state="Texas"}
{package_size="Large", service_name="Delivery World", state="Illinois"}
{package_size="Small", service_name="Delivery World", state="New York"}
{package_size="Medium", service_name="Delivery World", state="New York"}
{package_size="Large", service_name="Delivery World", state="California"}
我们可以通过添加 --analyze-labels
进一步改进此查询
logcli series '{}' --analyze-labels
这将返回日志中每个标签的唯一值摘要。输出将类似于以下内容。
Label Name Unique Values Found In Streams
state 5 15
package_size 3 15
service_name 1 15
检测到的字段
LogCLI 的另一个有用功能是检测日志中的字段。这对于理解日志结构和存在的键非常有用。这使我们能够检测可以提升为标签或结构化元数据的键。
logcli detected-fields --since 24h '{service_name="Delivery World"}'
这将返回日志中检测到的所有键列表。输出将类似于以下内容。
label: city type: string cardinality: 15
label: detected_level type: string cardinality: 3
label: note type: string cardinality: 7
label: package_id type: string cardinality: 994
label: package_size_extracted type: string cardinality: 3
label: package_status type: string cardinality: 4
label: package_type type: string cardinality: 5
label: receiver_address type: string cardinality: 991
label: receiver_name type: string cardinality: 100
label: sender_address type: string cardinality: 991
label: sender_name type: string cardinality: 100
label: state_extracted type: string cardinality: 5
label: timestamp type: string cardinality: 1000
现在您知道为什么我们选择将 package_id
保留在结构化元数据中,而将 package_size
作为标签了。Package ID 基数高,且每个日志条目唯一,这使得它成为结构化元数据的良好候选,因为我们可能需要直接查询它。另一方面,Package size 基数低,这使得它成为标签的良好候选。
检查查询性能
注意
LogCLI 只能返回涉及对象存储的查询统计信息。在此示例中,我们强制 Loki ingesters 每 5 分钟刷新一次 chunk,这不建议用于生产环境。运行此演示时,如果您没有看到任何统计信息返回,请在几分钟后再次尝试运行该命令。
首先,让我们打印日志的查询性能
这将提供一个 JSON 对象,其中包含查询数据量的统计信息。输出将类似于以下内容。
logcli stats --since 24h '{service_name="Delivery World"}'
这将返回查询的总字节数、查询的 chunk 数、查询的 stream 数和查询的条目数。如果我们通过指定次要标签来缩小查询范围,我们可以看到查询的性能
https://:3100/loki/api/v1/index/stats?end=1732639430272850000&query=%7Bservice_name%3D%22Delivery+World%22%7D&start=1732553030272850000
{
bytes: 12MB
chunks: 63
streams: 15
entries: 29529
}
这将返回 service_name
为 Delivery World
且 package_size
为 Large
的日志统计信息。输出将类似于以下内容。
logcli stats --since 24h '{service_name="Delivery World", package_size="Large"}'
如您所见,通过缩小查询范围,我们接触到的 stream 和条目少得多。
{
bytes: 4.2MB
chunks: 22
streams: 5
entries: 10198
}
检查日志量
我们可能还想检查日志中的日志量。这对于了解摄取到 Loki 中的数据量非常有用。我们可以使用 LogCLI 来检查日志中的日志量。
这将返回过去 24 小时内标签 Delivery World
的总摄取日志数。输出将类似于以下内容
logcli volume --since 24h '{service_name="Delivery World"}'
结果包括时间戳和总摄取日志数。
[
{
"metric": {
"service_name": "Delivery World"
},
"value": [
1732640292.354,
"11669299"
]
}
]
我们还可以使用 volume_range
返回随时间变化的日志量
这将提供一个 JSON 对象,其中包含过去 24 小时内标签 Delivery World
的日志量。--step
将日志量按 1 小时分桶聚合。请注意,如果特定小时没有日志,则该小时的日志量将不返回任何值。
logcli volume_range --since 24h --step=1h '{service_name="Delivery World"}'
我们甚至可以根据特定标签值将日志量聚合到桶中
这将提供一个类似的 JSON 对象,但会根据 state
标签值将日志量聚合到桶中。
logcli volume_range --since 24h --step=1h --targetLabels='state' '{service_name="Delivery World"}'
除了从 Loki 查询日志外,LogCLI 还支持查询静态日志文件。这对于查询未存储在 Loki 中的日志非常有用。在本教程前面,我们将日志存储在 ./inventory
目录中。让我们运行一个类似的查询,但将其通过管道输出到日志文件
对静态日志文件执行查询
接下来让我们对静态日志文件运行查询
logcli query \
--timezone=UTC \
--parallel-duration="12h" \
--parallel-max-workers="4" \
--part-path-prefix="./inventory/inv" \
--since=24h \
--merge-parts \
--output=raw \
'{service_name="Delivery World"}' > ./inventory/complete.log
请注意,由于我们查询的是静态日志文件,因此标签不会自动检测
cat ./inventory/complete.log | logcli --stdin query '{service_name="Delivery World"} | json | package_status="critical"'
{service_name="Delivery World"}
在这种情况下是可选的,但为了清晰起见建议使用。
- 需要
json
来将日志文件解析为 JSON。这使我们能够提取package_status
字段。 - 例如,假设我们尝试不带
json
过滤器的查询日志文件
这将不返回任何结果,因为未检测到 package_status
字段。
cat ./inventory/complete.log | logcli --stdin query '{service_name="Delivery World"} | package_status="critical"'
结论
在本教程中,作为物流公司的站点经理,我们成功使用了 LogCLI 来查询日志并生成了一份关于货物整体健康状况的报告。我们还使用元查询来更好地了解数据卫生和查询性能。LogCLI 是一个强大的工具,可用于理解您的日志以及它们在 Loki 中的存储方式,随着您不断扩展解决方案,请记住利用 LogCLI 来监控基数和查询性能。
此页面是否有帮助?