前言

在.NET生态中,Serilog凭借其强大的结构化日志记录功能和与Seq的无缝集成,已经成为许多开发者的首选日志记录工具。Seq作为一个日志检索和仪表板工具,能够将日志中的插值转换为结构化数据,极大地方便了开发者快速检索日志、定位问题并进行简单的统计分析。这种便捷性让人难以割舍。

背景

最近需要搞一个JAVA项目,当开发环境转移到Java生态,尤其是采用Spring Boot框架时,许多开发者发现自己不得不面对一个新的挑战。Spring Boot的默认日志框架Logback,在处理日志结构化方面并不如Serilog那样给人以深刻印象。习惯了Seq带来的便捷,我自然希望在Java环境中也能找到类似的解决方案。

幸运的是,Seq提供了通过GELF(GrayLog Extended Log Format)接收日志的能力,这为Java生态中的日志结构化提供了可能。在Spring Boot 3.2中,通过引入logback-gelf的JAR包,开发者可以实现将日志以GELF格式通过UDP发送到Seq,尽管这种方式对结构化支持并不是非常友好。

GELF服务端配置

  • 安装Seq

    version: '3'
    services:
    seq-input-gelf:
    image: datalust/seq-input-gelf:latest
    depends_on:
    - seq
    ports:
    - "12201:12201/udp"
    environment:
    SEQ_ADDRESS: "http://seq:5341"
    restart: unless-stopped
    seq:
    image: datalust/seq:latest
    ports:
    - "5341:80"
    environment:
    ACCEPT_EULA: Y
    restart: unless-stopped
    volumes:
    - ./seq-data:/data
  • 安装Gelf Input

Spring配置

  • 安装logback-gelf包

    gradle

    implementation 'de.siegmar:logback-gelf:6.0.0'
  • 添加 logback-spring.xml

    <configuration>
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 设置队列的最大容量,默认值为 256 -->
    <queueSize>512</queueSize>
    <!-- 设置当队列满时是否丢弃新的日志事件,默认为 false -->
    <discardingThreshold>0</discardingThreshold>
    <!-- 引用其他的 appender,例如控制台 appender -->
    <appender-ref ref="GELF" />
    </appender>
    <appender name="Console"
    class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    <Pattern>
    [%white(%d{HH:mm:ss.SSS}) %highlight(%-5level)] [%blue(%t)] %yellow(%C{1}): %msg%n%throwable
    </Pattern>
    </encoder>
    </appender>
    <appender name="GELF" class="de.siegmar.logbackgelf.GelfUdpAppender">
    <!--GELF Server-->
    <graylogHost>{{替换为GELF的UDP端口}}</graylogHost>
    <graylogPort>12201</graylogPort>
    <maxChunkSize>508</maxChunkSize>
    <compressionMethod>GZIP</compressionMethod>
    <messageIdSupplier class="de.siegmar.logbackgelf.MessageIdSupplier"/>
    <encoder class="com.leesiper.logseqsample.utils.SeqEncoder">
    <includeRawMessage>false</includeRawMessage>
    <includeKeyValues>true</includeKeyValues>
    <includeMarker>false</includeMarker>
    <includeMdcData>true</includeMdcData>
    <includeCallerData>false</includeCallerData>
    <includeRootCauseData>false</includeRootCauseData>
    <includeLevelName>false</includeLevelName>
    <shortMessageLayout class="ch.qos.logback.classic.PatternLayout">
    <pattern>%msg%n</pattern>
    </shortMessageLayout>
    <fullMessageLayout class="ch.qos.logback.classic.PatternLayout">
    <pattern>%msg%n</pattern>
    </fullMessageLayout>
    <numbersAsString>false</numbersAsString>
    <!--增加app_name 区分服务-->
    <staticField>app_name:java-demo</staticField>
    <!--<staticField>os_arch:${os.arch}</staticField>-->
    <!--<staticField>os_name:${os.name}</staticField>-->
    <!--<staticField>os_version:${os.version}</staticField>-->
    </encoder>
    </appender> <!-- LOG everything at INFO level -->
    <root level="info">
    <appender-ref ref="ASYNC" />
    <appender-ref ref="Console" />
    </root> </configuration>

特别注意

logback-gelf提供的de.siegmar.logbackgelf.GelfEncoder并未进行格式化写入GELF,这自然不友好,所以直接深入源码找方案。经过一番努力,我发现,通过对Logback的encoder进行定制,可以创建一个专门的SeqEncoder,这样不仅能够保持日志的结构化特性,还能够继续享受Seq带来的各种便利

所以com.leesiper.logseqsample.utils.SeqEncoder 类是override的,可以在Github(SeqEncoder)中找到

旨在解决logback日志参数格式化转换为K/V形式,在Seq上方便检索。

其中参数化format约定为"[边界][参数key]={}" 的,

边界可以为以下字符

private static final char[] Delimiter = {',',' ','.','。'};

例如你记录的日志如下:

Logger logger = LoggerFactory.getLogger(LogseqsampleApplication.class);

logger.info("Hello {}","World");
logger.info("Hello world={}","World");
logger.info("log config={}",Map.of("k1","v1"));
logger.info("log config={}",Map.of("key",new String[]{"value1","value2"}));
logger.info("log config={}",Map.of("key",Map.of("k1","v1")));

可以看出 config或者world参数前都有空格,即边界符。

如果运气好,配置没什么问题,Seq上可以看到日志

这一发现对于习惯了.NET生态中Serilog和Seq搭配使用的开发者来说,无疑是一个好消息。它意味着,即使在转向Java生态时,也无需放弃熟悉的日志记录习惯和工具。通过适当的配置和一些定制化开发,开发者可以在Spring Boot项目中实现与.NET生态相似的日志记录体验,继续享受快速检索和日志问题定位的便利。

总之,通过探索和创新,Java生态中的开发者同样能够享受到Serilog和Seq带来的高效日志处理体验。这不仅展示了技术跨界整合的可能性,也再次证明了开发者社区在面对挑战时不断探索和创新的精神。

Git示例仓库

spring-logback-seq

JAVA也能用上Seq啦的更多相关文章

  1. Java FtpClient 实现文件上传服务

    一.Ubuntu 安装 Vsftpd 服务 1.安装 sudo apt-get install vsftpd 2.添加用户(uftp) sudo useradd -d /home/uftp -s /b ...

  2. Java基础知识【上】(转载)

    http://blog.csdn.net/silentbalanceyh/article/details/4608272 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...

  3. JAVA中使用FTPClient上传下载

    Java中使用FTPClient上传下载 在JAVA程序中,经常需要和FTP打交道,比如向FTP服务器上传文件.下载文件,本文简单介绍如何利用jakarta commons中的FTPClient(在c ...

  4. HTTP请求中的Body构建——.NET客户端调用JAVA服务进行文件上传

    PS:今日的第二篇,当日事还要当日毕:)   http的POST请求发送的内容在Body中,因此有时候会有我们自己构建body的情况. JAVA使用http—post上传file时,spring框架中 ...

  5. java微信接口之四—上传素材

    一.微信上传素材接口简介 1.请求:该请求是使用post提交地址为: https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=A ...

  6. Java中实现文件上传下载的三种解决方案

    第一点:Java代码实现文件上传 FormFile file=manform.getFile(); String newfileName = null; String newpathname=null ...

  7. 【原创】用JAVA实现大文件上传及显示进度信息

    用JAVA实现大文件上传及显示进度信息 ---解析HTTP MultiPart协议 (本文提供全部源码下载,请访问 https://github.com/grayprince/UploadBigFil ...

  8. 浅入深出之Java集合框架(上)

    Java中的集合框架(上) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架 ...

  9. Java面向对象 网络编程 上

     Java面向对象 网络编程 上 知识概要:                     (1)网络模型 (2)网络通讯要素 (3)UDP TCP 概念 (4)Socket (5)UDP TCP 传输 ...

  10. Java面向对象 集合(上)

     Java面向对象  集合(上) 知识概要:             (1)体系概述 (2)共性方法 (3)迭代器 (4)list集合 (5)Set 集合 体系概述:              集 ...

随机推荐

  1. Oracle 触发器迁移至KingbaseES常见的问题

    oracle数据库的触发器迁移到KingbaseES的时候经常会出现一下两类错误: 1.SQL 错误 [42809]: 错误: "xxxxxxxx" 是一个视图.Detail: 视 ...

  2. 使用fiddler抓取HTTPS的数据包(抓取App端的数据包)

    众所周知,我们在做接口测试的时候有两种情况: 第一种是先拿到接口测试规范文档,再去做接口测试. 第二种是没有接口文档,只有通过自己抓包. 那么说到抓包,就不得不说抓包工具,对于浏览器web端,我们只需 ...

  3. #Tarjan,树的直径#CF1000E We Need More Bosses

    题目 给定一个\(n\)个点\(m\)条边的无向图,找到两个点\(s,t\),使得\(s\)到\(t\)必须经过的边最多 分析 桥就是必须经过的边,考虑给无向图缩点, 按照桥建一棵树,那么就转换成了求 ...

  4. 重磅官宣,OpenHarmony技术峰会来了

      技术构筑万物智联 创新使能行业发展 2月25日 第一届开放原子开源基金会OpenHarmony技术峰会即将启幕 众多行业大咖齐聚深圳 开启一场"技术硬核"探索盛宴 亮点拉满,我 ...

  5. Linux 配置Git

    前言:请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i 一.用git --version命令检查是否已经安装 二.下载git源码并解压 wget https://github.com/git/ ...

  6. 当JDBC遇上返回Cursor

    当 JDBC 遇上返回 Cursor 本文出处:https://www.modb.pro/db/400426 使用 jdbc 访问 PostgreSQL 或者 MogDB(openGauss)数据库里 ...

  7. 通过path在windows下临时修改python和pip路径 以便于配置环境只对当前命令行窗口生效

    配置前 在cmd命令行下输入新env的路径 path=D:\Miniconda2\envs\openmmlab\openmmlab;D:\Miniconda2\envs\openmmlab\openm ...

  8. Kalman滤波器的原理与实现

    Kalman滤波器的原理与实现 卡尔曼滤波器(Kalman Filter)是一个十分强大滤波器,虽然叫做滤波器,卡尔曼滤波器其实可以起到到两个作用,即预测与更新,这与我们在其运行时所关注的环节有关.当 ...

  9. POJ2251 基础bfs

    题目: 你进入了一个3D的宝藏地宫中探寻宝藏到了宝藏,你可以找到走出地宫的路带出宝藏,或者使用炉石空手回家. 地宫由立方体单位构成,立方体中不定会充满岩石.向上下前后左右移动一个单位需要一分钟.你不能 ...

  10. 重新点亮shell————awk数组[十四]

    前言 简单介绍一下awk的数组. 正文 数组的定义: 数组的遍历: 删除数组: 例子: 例子2: 结 下一节awk函数.