# 方法观测日志
**Repository Path**: wb04307201/methodTraceLog
## Basic Information
- **Project Name**: 方法观测日志
- **Description**: Spring Boot starter,提供方法调用链路追踪、性能监控、日志文件管理、CFR 反编译。附带独立 MCP 服务(methodTraceLog-mcp),通过 stdio 把上述能力开放给 AI Agent。
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 1
- **Created**: 2025-07-28
- **Last Updated**: 2026-06-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: 日志, 分析, Spring
## README
# Method Trace Log - 方法观测日志
> Spring Boot starter,提供方法调用链路追踪、性能监控、日志文件管理、CFR 反编译。附带独立 MCP 服务(`methodTraceLog-mcp`),通过 stdio 把上述能力开放给 AI Agent。
[](https://jitpack.io/#com.gitee.wb04307201/methodTraceLog)
[](https://gitee.com/wb04307201/methodTraceLog)
[](https://gitee.com/wb04307201/methodTraceLog)
[](https://github.com/wb04307201/methodTraceLog)
[](https://github.com/wb04307201/methodTraceLog)
  

---
## 功能
| | |
|---|---|
| **方法追踪** | AOP 拦截,全链路 `traceid` / `spanid` / `pspanid`;可采样;`@AspectLog` 可改名 |
| **指标** | 每个方法的 Micrometer `Timer` + 父子 `MethodTraceInfo` 树;通过 `actuator/methodtrace` 暴露 |
| **日志文件** | 读 / 过滤 / 下载;WebSocket 实时 tail;路径穿越保护 |
| **CFR 反编译** | HTTP 端点,支持应用类 / 第三方 jar / fat-jar 嵌套,自动去除注解 |
| **OTel 导出** | classpath 上有 `opentelemetry-sdk` 时自动桥接到 OTLP/HTTP |
| **W3C traceparent** | HTTP 入站和 `RestClient` 出站自动注入/提取 |
| **Cookie 会话** | 浏览器 `POST /methodTraceLog/login` 登录;CLI / MCP 继续用 `X-Api-Key` |
| **MCP 服务** | 独立 stdio 进程;13 个工具,多主机,通过 HTTP 转发到目标应用 |
---
## 快速开始
### 引入依赖
```xml
io.github.wb04307201
methodTraceLog-spring-boot-starter
1.0.20
```
### 最小配置
```yaml
method-trace-log:
log:
enable: true
file:
enable: true
path: ./logs
security:
api-key: change-me-in-production # 生产环境必填;留空则关闭鉴权(仅限开发)
management:
endpoints:
web:
exposure:
include: methodtrace # 面板依赖的端点
```
### 打开面板
`http://localhost:8080/methodTraceLog/panel` —— 单页 4 个 tab:概览 / 调用记录(含 JSON/CSV 导出)/ 日志文件(含实时 tail)/ 反编译(CFR)。
---
## 配置参考
```yaml
method-trace-log:
log:
enable: true # AOP 总开关
sample-rate: 1.0 # 0.0 ~ 1.0;子调用继承父决定
service-calls: # 启动时各服务开关
- { name: CustomLog, enable: false } # 内置 3 个: SimpleLogService / SimpleMonitorService / CustomLog
trace-store: # 内存 trace 树持久化
type: in-memory # in-memory | file | none
path: ./trace-store # 仅 type=file 时生效(自动按 yyyy-MM-dd 建子目录)
max-traces: 1000 # recent map 上限(in-memory / file 的内存缓存共用)
ttl-millis: 28800000 # 8h,clean() 会删超过此时长的磁盘文件
rebuild-index-on-start: false # 仅 type=file 时生效;启动时扫描目录重建 traceId→file 索引,文件量大时拖慢启动
file:
enable: true
path: ./logs
allowed-extensions: [.log, .txt, .out]
scan-lines: 10000 # 流式扫描行数上限;Files.lines() + limit() 是懒加载,文件本身多大都无所谓,没有 size check
# log-pattern: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+\[([^\]]+)\]\s+(\w+)\s+([^\s]+)\s*-\s*(.*)
security:
api-key: change-me-in-production # 留空 = 关闭鉴权
session:
ttl-millis: 28800000 # 浏览器 cookie 会话 8h 滑动过期
decompile:
timeout-seconds: 10 # CFR daemon 线程超时
otel: # 需要 classpath 上有 opentelemetry-sdk
enable: false
endpoint: http://localhost:4318/v1/traces
service-name: method-trace-log
service-namespace: "" # Resource service.namespace 标签
export-delay-millis: 5000 # OTLP 客户端内置 batching 延迟
max-queue-size: 2048
max-export-batch-size: 512
export-timeout-millis: 30000
propagate: # W3C traceparent 传播
http-inbound: true # TraceContextFilter 读 traceparent
rest-client-outbound: true # RestClient.Builder 拦截器
rest-template-interceptor: true # 暴露 RestTemplate 拦截器 Bean
```
---
## HTTP 端点
`security.api-key` 非空时,除 `/methodTraceLog/panel`(HTML 页面本身)外,所有路由都需要 `X-Api-Key` 或 `MTRACE_SESSION` cookie。
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | `/methodTraceLog/panel` | HTML 面板 — 4 tab(白名单) |
| GET | `/methodTraceLog/view/callServices` | 服务列表 + 当前 enable |
| GET | `/methodTraceLog/view/callService?name=&enable=` | 运行时开关 |
| GET | `/methodTraceLog/view/list?className=&methodName=&onlyErrors=&limit=` | 最近根 trace |
| GET | `/methodTraceLog/view/traceid?id=` | 单个 trace 完整调用链 |
| GET | `/methodTraceLog/view/export?format=json\|csv&className=&methodName=&onlyErrors=&limit=` | 批量导出(默认 limit 1000) |
| GET | `/methodTraceLog/decompile?className=&methodName=&timeoutSeconds=` | text/plain 源码 |
| GET | `/methodTraceLog/logFile/files` | 日志目录文件列表 |
| POST | `/methodTraceLog/logFile/query` | 关键字 / 时间 / 级别过滤分页 |
| POST | `/methodTraceLog/logFile/download` | 流式下载 |
| GET | `/methodTraceLog/logFile/monitor/{start,stop,status}?fileName=` | REST 实时 tail(STOMP 之外) |
| POST | `/methodTraceLog/login` | Body `{"apiKey":"..."}` → `Set-Cookie: MTRACE_SESSION=...` |
| POST | `/methodTraceLog/logout` | 销毁会话 |
| GET | `/methodTraceLog/session/status` | `{ sessionValid: true/false }` |
| WS | `/ws` (SockJS) → `/topic/log-monitor` | 实时日志推送;STOMP 发送到 `/app/{start-monitor,stop-monitor,monitor-status,heartbeat}` |
| GET | `/actuator/methodtrace` | 每个方法 / 每个类的 Micrometer 统计 |
---
## MDC 中的 trace id
`LogAspect` 把 `traceid` / `spanid` / `pspanid` 写入 SLF4J MDC。把它放进 logback pattern 就能让日志自带链路信息:
```xml
%d{HH:mm:ss.SSS} [%thread] [trace=%X{traceid} span=%X{spanid}] %-5level %logger - %msg%n
```
跨服务时 `TraceContextFilter` 解析入站 `traceparent`,`RestClient` 拦截器给所有出站请求注入 `traceparent` —— 上下游 `traceid` 自动接上。
---
## Web 面板鉴权
`security.api-key` 非空时,面板用页面顶部的**横幅**(不是弹窗)收集 API Key:
- 首次访问 `/methodTraceLog/panel` 且没有有效 session 时,横幅出现在 tab 内容上方。
- 提交正确的 Key(点按钮或按 **Enter**)后,横幅消失、`MTRACE_SESSION` cookie 被设置,当前 tab 的数据**自动加载**——无需手动刷新。
- 错误 / 空 Key 会显示行内错误(`请输入 API Key` / `❌ API Key 无效或鉴权未启用`)。
- Session 是 **8 小时滑动 cookie**(`security.session.ttl-millis`,默认 28 800 000)。每次使用都会续期,所以 8 小时不操作或点 **🚪 注销** 之前都不用重输。
- header 上的登出按钮只在有 session 时才出现;`/methodTraceLog/logout` 销毁 cookie 后,横幅会自动重新挂载。
- 开发模式(`api-key: ""`)下横幅完全不显示,也不会有登出按钮。
`GET /methodTraceLog/session/status` 返回 `{ authEnabled, sessionValid }`,面板 JS 据此决定是否显示横幅。横幅挂着时,页面内的 `mtlFetch` 会把 401 暂存到队列,登录成功后自动重放,登录过程中不会出现 "unauthorized" 提示。
CLI / MCP 客户端继续用 `X-Api-Key` 请求头即可,cookie session 只是为了浏览器体验更顺。
---
## `@AspectLog` 注解
方法级独立开关(不要求所在类是 `@Component`)。用来给 trace 列表和 OTel span 起个可读名:
```java
public class MyHelper {
@AspectLog("do-something")
public void doSomething(String s) { ... }
}
```
trace 列表和 OTel span name 会显示 `do-something` 而不是原始方法签名。
---
## 自定义 `ICallService`
继承 `AbstractCallService` 实现 `consumer(ServiceCallInfo)`,由 `CallServiceStrategy` 自动发现:
```java
@Component
public class MyService extends AbstractCallService {
@Override
public void consumer(ServiceCallInfo info) {
// logActionEnum: BEFORE / AFTER_RETURN / AFTER_THROW
log.info("{} {}", info.getClassName(), info.getMethodName());
}
@Override public String getCallServiceName() { return "MyService"; }
@Override public String getCallServiceDesc() { return "我的服务"; }
}
```
启动时关闭:`service-calls: [{ name: MyService, enable: false }]`,再用面板开。
---
## MCP 服务
独立 Spring Boot 进程,stdio 通信,把 `@Tool` 调用通过 HTTP 转发到一个或多个目标主机(每个目标 = 部署了 starter 的应用)。
Claude Desktop / Cursor / Cline 等 AI 客户端的 MCP server 配置(`mcpServers` JSON 块):
```json
{
"mcpServers": {
"methodTraceLog-mcp": {
"command": "jbang.cmd",
"args": [
"io.github.wb04307201:methodTraceLog-mcp:1.0.20",
"--method-trace-log.mcp.hosts[0].name=local-dev",
"--method-trace-log.mcp.hosts[0].url=http://localhost:8080",
"--method-trace-log.mcp.hosts[0].description=本地开发",
"--method-trace-log.mcp.hosts[0].api-key=change-me-in-production"
]
}
}
}
```
**13 个工具**:`getHosts`, `ping`, `getCallServices`, `setCallServiceEnable`, `getMethodTraceList`, `getMethodTraceByTraceId`, `decompileMethod`, `getLogFiles`, `queryLogContent`, `downloadLog`, `startMonitor`, `stopMonitor`, `getMonitorStatus`。
---
## 使用注意
- **LogAspect 排除规则**:框架内部类型(`ICallService` / `MethodTraceLogEndPoint` / `LogFileService` / `LogFileRealTimeService`)默认不追踪。如果有类似内部 bean 不想被追踪,加入 `LogAspect` 的 pointcut 表达式。
- **路径穿越保护**:`FileUtils.pathInspection` 是 `LogFileService` 和 `LogFileRealTimeService` 共用的白名单 —— `[a-zA-Z0-9._-]+`,不允许 `..`,长度 ≤ 255。
- **日志 pattern**:默认 `log-pattern` 只匹配标准 logback pattern。如果改了 `logback.xml` 里的 ``,要同步更新 `log-pattern`,否则 `LogLineInfo.parse` 不会拆分关键字 / 级别 / 时间。
- **CFR 资源**:通过 ClassLoader 的 `getResourceAsStream` 读 class 字节 —— 文件路径、thin jar、Spring Boot fat-jar 嵌套 jar 都通用。不要去解析 `URL.getPath()` 字符串。
- **Spring Boot fat-jar**:测试模块没有声明 `spring-boot-maven-plugin`,所以 `mvn package` 出来的 jar 没主清单。运行方式:`mvn package` 之后 `java -cp target/classes; cn.wubo.method.trace.log.MethodTraceLogTestApplication`。
- **Maven**:本机 `mvn` 命令是坏的,调用 `/c/developer/apache-maven-3.9.16/bin/mvn`。