# TLog-example **Repository Path**: bryan31/tlog-example ## Basic Information - **Project Name**: TLog-example - **Description**: TLog框架的测试工程,包含log4j,log4j2,logback三大日志框架,涉及dubbo,dubbox,spring cloud三种rpc框架 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 57 - **Forks**: 28 - **Created**: 2020-09-14 - **Last Updated**: 2026-10-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # TLog 2.0 可运行示例与真实链路验证 这个分支使用当前的 TLog 2.0.0 构建真实应用。验收会启动独立 JVM、发送 HTTP/RPC/AMQP 请求、读取实际日志,并检查成功、失败、取消和线程复用后的状态。全部断言通过才返回退出码 0。 旧版示例和原始聚合 POM 保存在 `legacy/`,不参与 2.0 默认构建。它们是历史资料,不计入本分支的运行验证结果。 ## 一键验收 需要 Python 3、Maven、构建 JDK 17+。运行 JDK 单独选择。完整套件还需要运行中的本地 Docker。 ```sh # Boot 2.7 / Dubbo 2.7,运行在 JDK 8 python3 scripts/verify-demo.py --profile boot2 \ --build-java-home /path/to/jdk21 \ --java /path/to/jdk8/bin/java --tlog-source ../TLog # Boot 3.5 / Dubbo 3.3 python3 scripts/verify-demo.py --profile boot3 \ --build-java-home /path/to/jdk21 \ --java /path/to/jdk17/bin/java --tlog-source ../TLog # Boot 4.0 / Dubbo 3.3 python3 scripts/verify-demo.py --profile boot4 \ --build-java-home /path/to/jdk21 \ --java /path/to/jdk25/bin/java --tlog-source ../TLog ``` 脚本会先将本地 TLog 安装到 Maven 仓库,再 `clean package` 构建 demo,避免切换 profile 时复用旧 fat jar。若省略 `--tlog-source`,会检查同级 `../TLog`;不存在时使用本地/远端 Maven 仓库中的 2.0.0。未发布的开发版本推荐明确提供源码路径。 所有 HTTP 和 RPC 端口动态分配。脚本自动启动的 Docker 容器都只映射到本机回环地址:RabbitMQ(`rabbitmq:4.1-alpine`)、Kafka(`apache/kafka:3.9.1`,KRaft 单节点)、XXL-JOB 调度中心(`xuxueli/xxl-job-admin:2.3.0` + `mysql:8.0`,Apple Silicon 上以 amd64 模拟运行)、Logstash(`logstash:8.15.5`)。完成或失败后都会停止测试 JVM,并删除自己创建的容器、匿名卷和网络,不操作其它容器。日志、产物 SHA-256、每项断言和关闭结果保存在 `validation-results/<时间-profile-run-id>/`,Maven clean 不会删除它们。 常用选项: | 参数 | 用途 | | --- | --- | | `--log4j2` | HTTP demo 改用 Log4j2,校验其实际日志标签与 MDC;其它模块保留各自日志配置 | | `--skip-build` | 重用已构建产物;脚本仍检查 Boot/TLog 版本和 HTTP 日志后端 | | `--amqp-uri='amqp://user:pass@127.0.0.1:56720/%2F'` | 使用已有 RabbitMQ,脚本不会停止这个外部提供的 broker | | `--without-mq` | 显式运行不含真实 RabbitMQ 的部分套件,结果标为 `partial-pass`,不等于完整验收 | | `--without-kafka` | 显式运行不含真实 Kafka 的部分套件,结果标为 `partial-pass` | | `--without-docker-extras` | 跳过 XXL-JOB 调度中心和 Logstash 两组容器,结果同样标为 `partial-pass` | 默认 RabbitMQ 测试用户名和密码均为 `tlogdemo`,仅用于本机 demo。默认 `/` vhost 的 URI 必须编码为 `/%2F`;末尾仅写 `/` 会被 AMQP 客户端解释为空 vhost。 ## 工程分类 和旧版示例一样按类别分目录,每个 case 是一个可以单独 `java -jar` 启动的工程。 | 类别 | 工程 | 覆盖的 TLog 功能 | | --- | --- | --- | | `tlog-example-web` | `tlog-example-springboot-web` | Boot Servlet 自动配置、RestTemplate/Feign/RestClient、Boot 内 HttpClient 4/5、OkHttp、Hutool、Forest、`@Async` 与用户 TaskDecorator、Callable、`@Scheduled`、自定义 ID Bean、W3C、`tlog.web.order` 与各开关 | | | `tlog-example-webflux` | WebFlux、WebClient、Reactor 线程切换、错误与断连取消 | | | `tlog-example-gateway` | Spring Cloud Gateway 路由及三进程链 | | | `tlog-example-servlet` | 无 Spring 容器的原生 Servlet:手工注册 `TLogServletFilter`/`TLogJakartaServletFilter`,AsyncContext、ERROR 派发、`ReplaceStreamFilter`(javax) | | | `tlog-example-springmvc` | 无 Spring Boot 的 Spring MVC:`tlog-all` + 手工声明 `TLogPropertyInit`、`AspectLogAop`、`TLogWebConfig`(javax)/过滤器(jakarta)、RestTemplate 拦截器 | | `tlog-example-rpc` | `tlog-example-dubbo-provider` / `-consumer` | Apache Dubbo 直连、provider 线程清理、`TLogDubboInvokeTimeFilter` | | | `tlog-example-dubbox-provider` / `-consumer` | Dubbox 2.8.4 直连、`TLogDubboxFilter`、`TLogDubboxInvokeTimeFilter`、provider 线程清理 | | `tlog-example-mq` | `tlog-example-mq-rabbitmq` | `TLogMqWrapBean` / `TLogMqConsumerProcessor` 包装消息体,经真实 RabbitMQ 双进程传递 | | | `tlog-example-mq-rabbitmq-spring` | Spring AMQP 自动装配,header 透传:RabbitTemplate、@RabbitListener 及其返回值回复、重试、批量监听 | | | `tlog-example-mq-rabbitmq-native` | 原生 amqp-client,`TLogRabbitHeaders.inject` / `TLogRabbitConsumerProcessor.wrap` | | | `tlog-example-mq-kafka` | Spring Kafka 自动装配,header 透传:KafkaTemplate、@KafkaListener、批量监听 | | | `tlog-example-mq-kafka-native` | 原生 kafka-clients,`interceptor.classes` / `TLogKafkaConsumerProcessor` | | `tlog-example-plain` | `tlog-example-plain-java` | 无 Spring:HttpClient 4/5、OkHttp、Hutool、Forest 拦截器,`TLogExecutors` | | `tlog-example-task` | `tlog-example-task-jdk` | `TLogTimerTask` | | | `tlog-example-task-spring-scheduled` | `SpringScheduledTaskAop`(starter 自动生效) | | | `tlog-example-task-quartz` | `TLogQuartzJobBean` | | | `tlog-example-task-xxljob` | `TLogXxlJobAop`,真实 XXL-JOB 调度中心经 HTTP 触发执行器 | | `tlog-example-log` | `tlog-example-log-logback-sync` | `AspectLogbackEncoder`、`AspectLogbackLayout`、`AspectLogbackConverter` | | | `tlog-example-log-logback-async` | `AspectLogbackAsyncAppender` | | | `tlog-example-log-logback-mdc` | `%X{tl}`,原生 AsyncAppender,`tlog.mdc-enable` | | | `tlog-example-log-logback-ttl-mdc` | `TLogLogbackTTLMdcListener`(MDC 随 TTL 传到 new Thread) | | | `tlog-example-log-log4j-sync` / `-async` / `-mdc` | log4j 1:`AspectLog4jPatternLayout`、`AspectLog4jAsyncAppender`、`%X{tl}` | | | `tlog-example-log-log4j2-sync` / `-async` / `-mdc` | log4j2:`%tmsg`(`AspectLogLog4j2Converter`)、Async appender、`%TX{tl}`(`AspectLogLog4j2MDCConverter`) | | | `tlog-example-log-logstash` | `TLogLogstashLogbackProvider` 经 TCP 发往真实 Logstash | | `tlog-example-feature` | `tlog-example-customlabel` | `@TLogAspect`:str、QLExpress 表达式、convert、pattern/joint、JSON、嵌套、异常恢复、非法表达式 | | | `tlog-example-custom-traceid` | `tlog.id-generator` 类名、`TLogIdGenerator` Bean 优先、`tlog.pattern` 全部占位符 | 日志类工程共用 `tlog-example-log-common` 的业务代码,定时任务共用 `tlog-example-task-common`,区别只在日志配置与依赖。所有观察器只读上下文,不手工清理 TLog 来掩盖错误。 不在本工程范围内:ShenYu、Soul 网关(按约定不做)。 ## 手工运行与观察 先使用 JDK 17+ 构建,默认 Boot 2.7。现代组合使用 `-Pboot3` 或 `-Pboot4`,切换时必须 clean。 ```sh mvn clean package # 两个终端,实际跨进程 HTTP java -jar tlog-example-web/tlog-example-springboot-web/target/tlog-example-springboot-web-2.0.0.jar --server.port=18081 --spring.application.name=demo-http-downstream java -jar tlog-example-web/tlog-example-springboot-web/target/tlog-example-springboot-web-2.0.0.jar --server.port=18082 --spring.application.name=demo-http-caller --demo.downstream-url=http://127.0.0.1:18081 curl -H 'tlogTraceId: manual-trace' 'http://127.0.0.1:18082/api/chain?client=feign&probe=manual' ``` `client` 可选 `rest-template`、`feign`、`httpclient4`、`httpclient5`、`okhttp`、`hutool`、`forest`,Boot 3/4 还可选 `rest-client`。这些请求都由当前 Boot 应用向另一个 JVM 发起,不是进程内 mock。 响应包含 `entry`、`async`、`labeled`、`afterLabel`、`downstream`、`after`。同一 trace 保持一致,本地 span 为 `0`,首个下游 span 为 `0.1`。日志同时展示配置文件实际渲染的标签和 `DEMO|probe=...|stage=...|trace=...|span=...|mdc=...` 观测字段。脚本对两部分分别断言,防止只看返回字段造成假通过。 ```sh java -jar tlog-example-web/tlog-example-webflux/target/tlog-example-webflux-2.0.0.jar java -jar tlog-example-web/tlog-example-gateway/target/tlog-example-gateway-2.0.0.jar curl -H 'tlogTraceId: gateway-trace' 'http://127.0.0.1:18084/reactive/api/reactive?probe=gateway-manual' java -jar tlog-example-rpc/tlog-example-dubbo-provider/target/tlog-example-dubbo-provider-2.0.0.jar java -jar tlog-example-rpc/tlog-example-dubbo-consumer/target/tlog-example-dubbo-consumer-2.0.0.jar curl -H 'tlogTraceId: rpc-trace' 'http://127.0.0.1:18086/api/rpc?probe=rpc-manual' java -jar tlog-example-plain/tlog-example-plain-java/target/tlog-example-plain-java-2.0.0.jar --downstream-url=http://127.0.0.1:18081 --probe=plain-manual ``` ```sh # Dubbox:JDK 16+ 需要开放 java.lang,jar 的 MANIFEST 已写入 Add-Opens,java -jar 时自动生效 java -jar tlog-example-rpc/tlog-example-dubbox-provider/target/tlog-example-dubbox-provider-2.0.0.jar --tlog.enable-invoke-time-print=true java -jar tlog-example-rpc/tlog-example-dubbox-consumer/target/tlog-example-dubbox-consumer-2.0.0.jar curl -H 'tlogTraceId: dubbox-trace' 'http://127.0.0.1:18088/api/rpc?probe=dubbox-manual' # 原生 Servlet 与非 Boot Spring MVC java -jar tlog-example-web/tlog-example-servlet/target/tlog-example-servlet-2.0.0.jar --tlog.enable-invoke-time-print=true curl -H 'tlogTraceId: servlet-trace' 'http://127.0.0.1:18089/api/async?probe=servlet-manual' java -jar tlog-example-web/tlog-example-springmvc/target/tlog-example-springmvc-2.0.0.jar curl 'http://127.0.0.1:18090/api/chain?probe=mvc-manual&downstream=http://127.0.0.1:18090' # 日志框架:每个工程的 /api/log 覆盖请求线程、自定义标签、@Async、TLogInheritableTask、TLogExecutors、new Thread、未包装线程池 java -jar tlog-example-log/tlog-example-log-log4j-async/target/tlog-example-log-log4j-async-2.0.0.jar curl -H 'tlogTraceId: log-trace' 'http://127.0.0.1:18106/api/log?probe=log-manual' # 定时任务:/api/executions 返回每次执行中与执行后的上下文 java -jar tlog-example-task/tlog-example-task-quartz/target/tlog-example-task-quartz-2.0.0.jar curl 'http://127.0.0.1:18123/api/executions' # 自定义标签 java -jar tlog-example-feature/tlog-example-customlabel/target/tlog-example-customlabel-2.0.0.jar curl -H 'tlogTraceId: label-trace' 'http://127.0.0.1:18131/api/labels?probe=label-manual' ``` XXL-JOB 和 Logstash 需要 Docker 中的服务端,手工运行时请参照 `scripts/verify-demo.py` 中的 `xxl_job_admin()` 与 `logstash()`,验收脚本会自行创建和清理。 Dubbo 直连不需要 ZooKeeper。Dubbo 会自行选择绑定地址;即使使用回环直连,也不要把示例当作已经加固的公网服务。 真实 MQ 可使用 Compose 单独启动: ```sh docker compose up -d --wait rabbitmq # 先启动消费者,再在另一终端启动生产者 java -jar tlog-example-mq/tlog-example-mq-rabbitmq/target/tlog-example-mq-rabbitmq-2.0.0.jar --role=consumer --amqp-uri='amqp://tlogdemo:tlogdemo@127.0.0.1:56720/%2F' --queue=tlog.manual java -jar tlog-example-mq/tlog-example-mq-rabbitmq/target/tlog-example-mq-rabbitmq-2.0.0.jar --role=producer --amqp-uri='amqp://tlogdemo:tlogdemo@127.0.0.1:56720/%2F' --queue=tlog.manual --probe=mq-manual # 结束两个 JVM 后清理 demo 容器和数据 docker compose down -v ``` ## 验证范围 - Boot 内 RestTemplate、Feign、RestClient(Boot 3/4)以及 HttpClient 4/5、OkHttp、Hutool、Forest 的真实跨进程请求,24 个并发请求覆盖各客户端并检查 trace/span/MDC、上游应用名和日志隔离。 - WebFlux、Gateway、WebClient 三进程链,24 并发、defer/subscribeOn/publishOn/delay、错误恢复、真实客户端断连取消。 - Dubbo 24 个网络并发调用;provider 外层观察器在 TLog 返回后检查 ThreadLocal、spanIndex、标签和所有 TLog MDC 字段。 - 纯 Java HttpClient4/5、OkHttp、Hutool、Forest;运行时确认 Spring 不存在;预热线程池、定时执行器、异常恢复和异步日志事件 MDC。 - RabbitMQ 双 JVM 三条消息:成功、预期消费异常、再次成功;发布确认、业务载荷、关联回执、span 唯一和消费线程清理。 - `@Async` 用户 TaskDecorator 保留、Callable 和响应渲染、真实 `@Scheduled` 执行、自定义 ID Bean/标签模板、AOP 标签恢复、中文表单。 - W3C 入站、优先级和非法输入,总开关与各功能开关,响应头关闭。 - Dubbox 24 个网络并发调用、上游应用名、provider 线程清理;Dubbo/Dubbox 调用耗时日志(开启和默认关闭)。 - 原生 Servlet:同步、AsyncContext 重派发、ERROR 派发、中文表单、`ReplaceStreamFilter` 重复读请求体及排除路径(javax)。 - 非 Boot Spring MVC:`TLogPropertyInit` 的 pattern 与按类名指定的 ID 生成器、手工 `AspectLogAop`、RestTemplate 拦截器、Callable、耗时日志。 - `tlog.web.order`:调低 TLog 过滤器优先级后,排在它前面的过滤器看不到 traceId。 - JDK Timer、Spring `@Scheduled`、Quartz、XXL-JOB:单工作线程上每次执行 traceId 不同,执行结束后线程上 TLog 上下文与 MDC 全部为空;XXL-JOB 由真实调度中心逐次触发,每个参数分别检查 during/after,调度日志 `handle_code=200`。 - 10 个日志接入工程逐行读取真实输出:每个 appender 对每个阶段恰好一行,标签只出现一次、与本次请求一致,未包装线程池没有残留;Logstash 实际收到的 JSON 事件含 TLog 全部 MDC 字段。 - `@TLogAspect` 全部写法、表达式错误时业务方法不执行;`tlog.id-generator` 类名、Bean 优先、`tlog.pattern` 六个占位符。 - 实际日志标签精确匹配、过程退出与关闭异常检查。没有依赖手工浏览日志才能判断成功的步骤。 Forest demo 采用 1.8.0:旧 1.5.14 的动态代理在现代 JDK 上不可用。HTTP 模块提供 `log4j2` profile;纯 Java/MQ 模块使用真正的 logback AsyncAppender。 范围说明:ShenYu、Soul 网关不在本工程范围内。Quartz 只验证单节点内存调度,没有覆盖集群模式;第三方库只验证 pom 中列出的版本。`legacy/` 是 1.x 时代的历史示例,不参与构建,也不计入验证结果。 实际执行版本、通过数量和结果路径见 [验证记录](docs/VALIDATION.md)。