视频

了解更多
随着你的 IT 基础设施规模的增长和复杂性的增加,你可能不得不花费更多的精力来确保一切都得到妥善管理。
自从云计算兴起以来,这一点变得尤为重要,因为我们现在有大量技术信息分散在许多不同的位置。
但是,能够进行全面的日志分析可能既繁琐、耗时,又令人痛苦地无聊。
摆脱这种负担的一个简单而有效的方法是使用专门用于简化日志监控的软件或应用程序……这正是 Alexis Gardin 在他的应用程序 Logub 中所做的。
与许多其他 SaaS 解决方案不同,Logub 可以在本地和开源方式下执行这些操作。 通过遵循以下步骤,你将能够创建一个应用程序,该应用程序将为你收集、浏览和分析应用程序日志。
该应用程序的核心是依赖 RediSearch 能够以无与伦比的效率浏览和分析不同位置的日志。 让我们来看看 Alexis 是如何将这个应用程序组合在一起的。
但在我们深入研究之前,我们应该让你知道,我们还在 Redis Launchpad 上提供了一系列令人兴奋的应用程序供你查看。
你将构建一个由 Redis 驱动的特殊应用程序,用于收集、分析和浏览日志应用程序。 在下面的步骤中,我们将详细介绍构建此应用程序所需的 A-Z,以及所需的组件。
即使你是 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 以访问 playground 并添加你的自定义日志。 此演示页面将允许你:
如果你返回主页,你可以尝试搜索你刚刚生成的日志。
注意:在容器中生成日志与其在 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 架构,你可以使用“List”数据结构来跟踪索引了哪些架构。
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 将发送的命令相同,以便在你的日志中执行全面而高效的搜索。
你可以按标签或全文搜索执行搜索。 如果你遇到困难,可以使用以下示例作为模型。
为了让你有良好的应用程序测试体验,我们强烈建议你使用 playground 创建你自己的日志,添加业务属性,然后进行一些实验,只是为了感受一下它。
目前,Logub 只能处理一种特定的日志格式。 将来,此格式将扩展并更可自定义。
这是 Logub 格式
{
"level": "....",
"thread": "....",
"logger": "....",
"message": "....."
}
请注意,这些字段不是强制性的。
如果要添加你的业务属性,你需要添加一个以“mdc”作为键的嵌套 JSON 对象。 例如
{
"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 视频。
我们还在我们的 Launchpad 上拥有一系列令人兴奋的创新应用程序,这些应用程序由像 Alex 这样的才华横溢的程序员开发。 查看一下,获得灵感,看看您可以使用 Redis 提出哪些创新。
谁构建了这个应用程序?
Alexis Gardin
Alexis 是一位创新的软件工程师,目前在 Zendoc 工作。前往 他的 GitHub 页面,看看他参与过的其他项目。