视频

了解更多
随着您的 IT 基础设施规模的增长和复杂性的增加,您可能被迫花费更多精力来确保一切都能得到妥善管理。
自云计算兴起以来,这一点变得尤为重要,因为我们现在拥有大量分布在不同位置的技术信息。
但是,进行全面的日志分析可能会很繁琐、费时且*令人痛苦地无聊*。
摆脱这种负担的一个简单而有效的方法是使用旨在简化日志监控的软件或应用程序…… 这就是 Alexis Gardin 在他的应用程序 Logub 中所做的事情。
与许多其他 SaaS 解决方案不同,Logub 可以本地执行这些操作,并且是开源的。通过按照以下步骤,您将能够创建一个应用程序,该应用程序将为您收集、探索和分析应用程序日志。
此应用程序的核心是依赖于 RediSearch 的能力,它能够以无与伦比的效率跨不同位置探索和分析日志。让我们来看看 Alexis 如何将这个应用程序整合在一起。
但在深入研究之前,我们应该告诉您,我们还在 Redis Launchpad 上提供了一系列激动人心的应用程序供您查看。
您将构建一个由 Redis 提供支持的特殊应用程序,用于收集、分析和探索日志应用程序。在下面的步骤中,我们将逐步介绍构建此应用程序所需的一切,以及所需的组件。
即使您是 Redis 新手,我们也会向您展示如何掌握这个强大的数据库。您准备好开始了吗?
好的,让我们直接开始吧。
在演示中,DEMO 应用程序将在 Logub 中发布日志。您将能够与这个 DEMO 应用程序交互以生成您的日志。然后,您将能够在 Logub 中请求它们
首先,确保您的系统上已打开以下端口:8080、8081、3000 和 6379。
git clone https://github.com/redis-developer/logub
docker-compose up -d
% docker-compose ps
NAME COMMAND SERVICE STATUS PORTS
demo_fluentd_1 "tini -- /bin/entryp…" fluentd running 5140/tcp, 0.0.0.0:24224->24224/tcp, :::24224->24224/tcp, 0.0.0.0:24224->24224/udp, :::24224->24224/udp
demo_logub-controller_1 "java -XX:+UnlockExp…" logub-controller running 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp
demo_logub-generator_1 "java -XX:+UnlockExp…" logub-generator running 0.0.0.0:8081->8081/tcp, :::8081->8081/tcp
demo_logub-ui_1 "docker-entrypoint.s…" logub-ui running 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp
demo_redis_1 "redis-server /usr/l…" redis running 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp
转到 localhost:3000 以浏览日志。
您可能需要大约一分钟的时间才能看到日志出现。您可以通过右侧的边栏过滤日志在页面上查看日志。或者,您可以通过顶部的搜索栏按过滤器或全文查询搜索日志。
单击日志时,将显示详细信息,并且您将可以选择索引业务属性。这些业务属性以后可用作过滤器。
接下来,转到 localhost:3000/demo 访问游乐场并添加自定义日志。此演示页面将允许您:
如果您返回主页,您可以尝试搜索您刚刚生成的日志。
注意:容器中日志生成与 Logub 中显示之间存在大约 1 分钟的延迟。这种延迟是由收集、格式化和将日志导入数据库的过程造成的。
数据使用 Fluentd Redis 插件 存储。它使用 HSET 存储每个日志。例如:HSET level DEBUG message “Hello World” thread main
public class LogubLog {
@Builder.Default
private String id = UUID.randomUUID().toString();
@Builder.Default
private String index = "principal";
@NonNull
private SystemProperties systemProperties;
@Builder.Default
private Map<String, Object> businessProperties = Collections.emptyMap();
@Builder.Default
private Optional<String> message = Optional.empty();
@Builder.Default
private Instant timestamp = Instant.now();
@Builder.Default
private Optional<String> service = Optional.empty();
@Builder.Default
private Optional<String> logger = Optional.empty();
@Builder.Default
private Optional<String> thread = Optional.empty();
@Builder.Default
private Optional<String> source = Optional.empty();
@Builder.Default
private LogLevel level = UNKNOWN;
}
public class SystemProperties {
@Builder.Default
Optional<String> imageName = Optional.empty();
@Builder.Default
Optional<String> containerName= Optional.empty();
@Builder.Default
Optional<String> containerId= Optional.empty();
@Builder.Default
Optional<String> env= Optional.empty();
@Builder.Default
Optional<String> host= Optional.empty();
}
这是您将用于操作日志并从 Redis 中检索日志的对象。执行此操作将允许 Logub UI 显示日志。为了在日志中执行复杂的查询,您可以使用 RediSearch。
由于您能够动态更改 RediSearch 架构,因此可以使用“列表”数据结构来跟踪已索引的架构。
public class LogSearch {
@Builder.Default
private List<LogubFieldSearch> texts = emptyList();
@Builder.Default
private List<LogubFieldSearch> systemProperties = emptyList();
@Builder.Default
private List<LogubFieldSearch> businessProperties = emptyList();
@Builder.Default
private List<LogubFieldSearch> basicProperties = emptyList();
@Builder.Default
private List<LogubFieldSearch> levels = Collections.emptyList();
@Builder.Default
private int limit = 25;
@Builder.Default
private int offset = 0;
@Builder.Default
private Optional<LogubSort> sort = Optional.empty();
@Builder.Default
private Instant beginAt = Instant.now().minus(15, ChronoUnit.MINUTES);
@Builder.Default
private Instant endAt = Instant.now();
@SneakyThrows
public QueryBuilder toQuery() {
var query = new QueryBuilder();
var businessPrefix = "businessProperties.";
var systemPropertiesPrefix = "systemProperties.";
for (LogubFieldSearch properties : businessProperties) {
query.append(QueryBuilders.tag(businessPrefix + properties.getName(), properties.getValues(),
properties.isNegation()));
}
for (LogubFieldSearch properties : systemProperties) {
query.append(QueryBuilders
.tag(systemPropertiesPrefix + properties.getName(), properties.getValues(),
properties.isNegation()));
}
for (LogubFieldSearch properties : basicProperties) {
query.append(QueryBuilders
.tag(properties.getName(), properties.getValues(),
properties.isNegation()));
}
if (!levels.isEmpty()) {
for (LogubFieldSearch level : levels) {
var onError = !level.getValues().stream().allMatch(v -> Arrays.stream(LogLevel.values())
.anyMatch(enumLevel -> enumLevel.name().equalsIgnoreCase(v)));
if(onError){
log.error("bad payload for levels {}", level);
throw new IllegalArgumentException("bad payload for level");
}
query.append(QueryBuilders.tag("level",level.getValues(), level.isNegation()));
}
}
for (LogubFieldSearch text : texts) {
if(!text.getType().equals(LogubFieldType.FullText)){
log.warn("type {} not handle for text search", text.getType());
}
for (String value : text.getValues()) {
query.append(QueryBuilders.text("message", value, text.isNegation()));
}
}
return query;
}
}
上面的命令将允许您根据用户输入创建纯文本 RediSearch 查询。在 RediSearch 库的顶部构建了一系列小的 QueryBuilders。它是 Logub UI 将发送的相同命令,以在您的日志中执行全面而有效的搜索。
您可以按标签或全文搜索进行搜索。以下是一些您可以用作模型的示例,如果您遇到困难。
为了获得良好的应用程序测试体验,我们强烈建议您使用游乐场创建自己的日志,添加业务属性,然后进行一些实验,以了解它的工作原理。
目前,Logub 只能处理一种特定的日志格式。将来,这种格式将扩展并变得更可定制。
以下是 Logub 格式
{
"level": "....",
"thread": "....",
"logger": "....",
"message": "....."
}
请注意,这些字段不是必需的。
如果您想添加业务属性,则需要添加一个嵌套的 JSON 对象,该对象以“mdc”作为键。例如
{
"level": "....",
"thread": "....",
"logger": "....",
"message": ".....",
"mdc":{
"myproperties": "....",
"anotherOne":".....",
}
}
要在 Loghub 中浏览日志,您的容器需要使用 Docker Fluentd 日志记录驱动程序。以下是客户集成的配置示例。
# Your container(s)
MY-CUSTOM-APP:
image: "MY-CUSTOM-APP-IMAGE"
logging:
driver: "Fluentd"
options:
Fluentd-address: localhost:24224
tag: MY-CUSTOM-TAG
## Logub Fluentd + Redis conf
logub-controller:
image: "logub/logub-controller:0.1"
ports:
- "8080:8080"
depends_on:
- redis
links:
- "Fluentd"
- "redis"
logub-ui:
image: "logub/logub-ui:0.1"
ports:
- "3000:3000"
depends_on:
- redis
Fluentd:
image: "logub/logub-Fluentd:0.1"
links:
- "redis"
ports:
- "24224:24224"
- "24224:24224/udp"
redis:
image: "redislabs/redismod"
command: ["/usr/local/etc/redis/redis.conf","--bind","redis","--port", "6379"]
volumes:
- ./redis/data:/data
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
ports:
- "6379:6379"
RediSearch
Logub 使用 RediSearch 的功能来处理应用程序日志。当日志持久保存到 Redis 数据库时,它们会附带 3 种类型的字段
{
"timestamp": "2021-05-14 11:01:11.686",
"level": "WARN",
"thread": "scheduling-1",
"mdc": {
"app": "Toughjoyfax",
"correlationId": "521f075f-36be-4f85-957e-d1c87ad71aa8",
"originRequest": "Tonga",
"origin": "LoremIpsum"
},
"logger": "com.loghub.loggenerator.service.LoggerService",
"message": "Doloremque dolores ut minima sed."
}
这里有一个日志示例,描述了当 Fluentd 将数据扁平化并持久化到 Redis 数据库时,我们的工具是如何工作的。Logub API 将允许用户或公司索引 mdc 对象的一个或所有字段。
在这个项目中,Tag 数据类型被广泛使用。在日志搜索中(例如客户 ID),通常会根据业务属性进行搜索。此外,我们还将TextField 数据类型用于日志消息。这允许用户在此字段中进行全文搜索。
以下是搜索过程的简化模式:
Redis
Redis 用于通过 Fluentd 以这种方式将日志存储在 Redis 的HashSet 类型中。
为了跟踪用户索引的字段,您还可以添加一个“schema”对象,该对象使用 Redis 的List 类型。
云等数字创新爆炸带来的一个缺点是,监控 IT 基础设施可能变得复杂。应用程序可能散布在不同的位置,这使得将所有日志拉到一个位置变得很困难。
但是,通过使用 Redis,此过程的单调性将被消除,使您可以轻松地搜索、收集和存储日志。如果您想详细了解此应用程序的开发方式,请查看 Alexis 的YouTube 视频。
我们还有许多由像 Alex 这样才华横溢的程序员开发的创新应用程序,它们已发布在我们的 Launchpad 上。查看它,获得灵感,并看看使用 Redis 可以实现哪些创新。
谁构建了这个应用程序?
Alexis Gardin
Alexis 是一位创新型软件工程师,目前在 Zendoc 工作。前往他的 GitHub 页面查看他参与的其他项目。