
wb04307201/methodtracelog
Developer toolsNon-intrusive AOP method tracing + trace tree + alerting for Spring Boot. Includes a standalone MCP server (`methodTraceLog-mcp`) that exposes the same capabilities to AI agents over stdio.
Overview
Non-intrusive AOP method tracing + trace tree + alerting for Spring Boot. Includes a standalone MCP server (methodTraceLog-mcp) that exposes the same capabilities to AI agents over stdio. http://localhost:8080/methodTraceLog/panel — single page with 4 tabs: 概览 (overview) / 调用记录 (trace search + export) / 日志文件 (file viewer + real-time tail) / 反编译 (CFR decompile). All routes require X-Api-Key (or MTRACE_SESSION cookie) when security.api-key is non-empty, /methodTraceLog/panel (HTML). LogAspect puts traceid / spanid / pspanid into SLF4J MDC. Use them in your logback pattern to correlate logs across the call chain: For HTTP boundaries, TraceContextFilter reads traceparent on the way in, and the RestClient interceptor writes it on the way out — upstream and downstream traceids join automatically. When security.
README
Method Trace Log
Non-intrusive AOP method tracing + trace tree + alerting for Spring Boot. Includes a standalone MCP server (
methodTraceLog-mcp) that exposes the same capabilities to AI agents over stdio.
Features
| Method tracing | AOP-based, full call chain with traceid / spanid / pspanid; sampling; @AspectLog to override the display name |
| Metrics | Micrometer Timer per method + parent/child MethodTraceInfo tree; exposed via actuator/methodtrace |
| Log file viewer | Read / filter / download log files; WebSocket live tail; path-traversal safe |
| CFR decompile | HTTP endpoint for any class on the classpath (app / 3rd-party / fat-jar nested), annotations stripped |
| OTel export | Auto-bridges trace events to OpenTelemetry OTLP/HTTP when opentelemetry-sdk is on the classpath |
| W3C traceparent | Auto-injects / extracts traceparent header for HTTP inbound and RestClient outbound |
| Cookie session | Browser login via POST /methodTraceLog/login, HTTP X-Api-Key for CLI / MCP |
| MCP server | Standalone stdio process; 15 tools, multi-host, forwards to your starter over HTTP |
Quick Start
Add the dependency
io.github.wb04307201
methodTraceLog-spring-boot-starter
1.1.0
Minimal configuration
method-trace-log:
log:
enable: true
file:
enable: true
path: ./logs
security:
api-key: change-me-in-production # required in production; empty disables auth (dev only)
management:
endpoints:
web:
exposure:
include: methodtrace # for the /actuator/methodtrace panel data
Open the panel
http://localhost:8080/methodTraceLog/panel — single page with 4 tabs: 概览 (overview) / 调用记录 (trace search + export) / 日志文件 (file viewer + real-time tail) / 反编译 (CFR decompile).
Configuration Reference
method-trace-log:
log:
enable: true # AOP master switch
sample-rate: 1.0 # 0.0 ~ 1.0; child spans inherit parent decision (clamped on startup)
exclude-patterns: [] # method-name blacklist (case-insensitive equals match); hit → proceed() directly, no events emitted. e.g. [equals, hashCode, toString, canEqual]
service-calls: # start-up enable flags
- { name: CustomLog, enable: false } # built-in services: SimpleLogService / SimpleMonitorService / AlertingService / CustomLog
trace-store: # where the in-memory tree lives
type: in-memory # in-memory | file | none
path: ./trace-store # only when type=file (auto-creates yyyy-MM-dd subdirs)
max-traces: 1000 # recent map cap (in-memory & file memory cache)
ttl-millis: 28800000 # 8h; clean() drops disk files older than this
rebuild-index-on-start: false # type=file only; rebuilds traceId→file index at startup (slows boot on large dirs)
file:
enable: true
path: ./logs
allowed-extensions: [.log, .txt, .out]
scan-lines: 10000 # stream-scan line cap; Files.lines() + limit() is lazy, so the file itself can be arbitrarily large — no size check
max-file-size: 100MB # per-file size cap (default; set to 0/null = no limit)
total-size-cap: 10GB # cumulative cap across all rolled files in the dir
# 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 # empty = no auth
session:
ttl-millis: 28800000 # 8h sliding session for browser cookies
cors: # CORS for browser panels on different origins (opt-in: empty allowed-origins = disabled)
allowed-origins: [] # ["https://your-panel.example.com"]; ["*"] = all (incompatible with credentials)
allowed-methods: [GET, POST, OPTIONS, DELETE, PUT]
allowed-headers: [Content-Type, X-Api-Key, Authorization]
allow-credentials: false # true requires allowed-origins NOT be "*"
max-age: 0 # preflight cache seconds (0 = always re-validate)
decompile:
timeout-seconds: 10 # CFR daemon-thread timeout
otel: # requires opentelemetry-sdk on classpath
enable: false
endpoint: http://localhost:4318/v1/traces
service-name: method-trace-log
service-namespace: "" # Resource service.namespace label
export-delay-millis: 5000 # OTLP client built-in batching delay
max-queue-size: 2048
max-export-batch-size: 512
export-timeout-millis: 30000
propagate: # W3C traceparent propagation
http-inbound: true # TraceContextFilter reads traceparent
rest-client-outbound: true # RestClient.Builder interceptor
rest-template-interceptor: true # exposes a RestTemplate interceptor bean
alerting: # exception alerting — opt-in; off by default
enable: false # true registers AlertingService as an ICallService
webhook-url: "" # empty = log only; non-empty POSTs events (best-effort, async)
threshold:
error-count: 10 # errors per class#method within window to fire
window-seconds: 60 # sliding-window length
cooldown-seconds: 300 # suppress repeat alerts for the same key
classes: [] # whitelist prefix list; empty = alert on every class
HTTP Surface
All routes require X-Api-Key (or MTRACE_SESSION cookie) when security.api-key is non-empty, except /methodTraceLog/panel (HTML).
| Method | Path | Purpose |
|---|---|---|
| GET | /methodTraceLog/panel |
HTML panel — 4 tabs (whitelisted) |
| GET | /methodTraceLog/view/callServices |
List services + enable state |
| GET | /methodTraceLog/view/callService?name=&enable= |
Toggle a service at runtime |
| GET | /methodTraceLog/view/list?className=&methodName=&onlyErrors=&limit= |
Recent root traces |
| GET | /methodTraceLog/view/traceid?id= |
Full call chain for a trace id |
| GET | /methodTraceLog/view/export?format=json|csv&className=&methodName=&onlyErrors=&limit= |
Bulk export (default limit 1000) |
| GET | /methodTraceLog/view/alerts?limit= |
Recent alert events (default limit 50; empty list when alerting disabled) |
| GET | /methodTraceLog/view/slowMethods?windowMinutes=&topN= |
Slowest methods top-N from Micrometer histograms (default 5min / top 10) |
| GET | /methodTraceLog/decompile?className=&methodName=&timeoutSeconds= |
Text/plain source |
| GET | /methodTraceLog/logFile/files |
List log files in the configured dir |
| POST | /methodTraceLog/logFile/query |
Filter / paginate / time-range / level |
| POST | /methodTraceLog/logFile/download |
Stream the same content as text |
| GET | /methodTraceLog/logFile/monitor/{start,stop,status}?fileName= |
REST live-tail (companion to STOMP) |
| POST | /methodTraceLog/login |
Body {"apiKey":"..."} → Set-Cookie: MTRACE_SESSION=... |
| POST | /methodTraceLog/logout |
Invalidate session |
| GET | /methodTraceLog/session/status |
{ sessionValid: true/false } |
| WS | /ws (SockJS) → /topic/log-monitor |
Live log lines; STOMP send to /app/{start-monitor,stop-monitor,monitor-status,heartbeat} |
| GET | /actuator/methodtrace |
Per-class / per-method Micrometer stats |
MDC Trace IDs
LogAspect puts traceid / spanid / pspanid into SLF4J MDC. Use them in your logback pattern to correlate logs across the call chain:
%d{HH:mm:ss.SSS} [%thread] [trace=%X{traceid} span=%X{spanid}] %-5level %logger - %msg%n
For HTTP boundaries, TraceContextFilter reads traceparent on the way in, and the RestClient interceptor writes it on the way out — upstream and downstream traceids join automatically.
Web Panel Authentication
When security.api-key is non-empty, the panel UI uses a top banner (not a modal) to collect the API Key:
- Banner is shown above the tab content the first time you visit
/methodTraceLog/panelwithout a valid session. - Submitting a valid Key (button or Enter) hides the banner, sets the
MTRACE_SESSIONcookie, and auto-loads the current tab’s data — no manual refresh. - Wrong / empty Key shows an inline error (
请输入 API Key/❌ API Key 无效或鉴权未启用). - Session is a sliding 8-hour cookie (
security.session.ttl-millis, default 28 800 000). It renews on use, so you only re-enter the Key after 8h of inactivity or after clicking the 🚪 注销 button. - The logout button only appears in the header when a session is active; the
/methodTraceLog/logoutendpoint invalidates the cookie and re-mounts the banner. - In dev mode (
api-key: ""), the banner is suppressed entirely and no logout button is shown.
GET /methodTraceLog/session/status returns { authEnabled, sessionValid } so the panel JS can decide whether to show the banner. While the banner is up, the in-page mtlFetch queues 401 responses and replays them on successful login, so the user never sees an “unauthorized” toast during the login flow.
CLI / MCP clients should keep using the X-Api-Key header directly — the cookie session is purely a browser convenience.
@AspectLog Annotation
Method-level opt-in (the class doesn’t have to be a @Component). Use it to rename the method in the trace tree and on the OTel span:
public class MyHelper {
@AspectLog("do-something")
public void doSomething(String s) { ... }
}
The trace list and OTel span name will show do-something instead of the raw method signature.
Custom ICallService
Extend AbstractCallService and implement consumer(ServiceCallInfo). It’s auto-picked up by the CallServiceStrategy:
@Component
public class MyService extends AbstractCallService {
@Override
public void consumer(ServiceCallInfo info) {
// logActionEnum is one of BEFORE / AFTER_RETURN / AFTER_THROW
log.info("{} {}", info.getClassName(), info.getMethodName());
}
@Override public String getCallServiceName() { return "MyService"; }
@Override public String getCallServiceDesc() { return "My desc"; }
}
Start it disabled: service-calls: [{ name: MyService, enable: false }], then flip via the panel.
MCP Server
A separate, standalone Spring Boot process that speaks Model Context Protocol over stdio. It forwards @Tool calls to one or more hosts (each host = an app that has the starter on the classpath) over HTTP.
MCP server config (mcpServers JSON block) for AI clients like Claude Desktop, Cursor, Cline:
{
"mcpServers": {
"sql-forge-mcp": {
"command": "jbang.cmd",
"args": [
"io.github.wb04307201:methodTraceLog-mcp:1.1.0",
"--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=Local dev",
"--method-trace-log.mcp.hosts[0].api-key=change-me-in-production"
]
}
}
}
15 tools exposed: getHosts, ping, getCallServices, setCallServiceEnable, getMethodTraceList, getMethodTraceByTraceId, getAlerts, getSlowMethods, decompileMethod, getLogFiles, queryLogContent, downloadLog, startMonitor, stopMonitor, getMonitorStatus.
Gotchas
LogAspectexclusions: framework-internal types (ICallService,MethodTraceLogEndPoint,LogFileService,LogFileRealTimeService) are excluded. Add yours to the pointcut if you have similar internal beans.- Path traversal:
FileUtils.pathInspectionis the whitelist forLogFileServiceandLogFileRealTimeService—[a-zA-Z0-9._-]+, no.., ≤ 255 chars. - Log pattern: the default
log-patternonly matches the standard logback pattern. If you change `` inlogback.xml, updatelog-patternin YAML orLogLineInfo.parsewill not split keyword / level / time. - CFR resources: decompile reads class bytes through the classloader’s
getResourceAsStream— works uniformly for file paths, thin jars, and Spring Boot fat-jar nested jars. Don’t parse theURL.getPath()string. - Spring Boot fat-jar: the test module does not declare
spring-boot-maven-plugin. Usemvn packagethenjava -cp target/classes; cn.wubo.method.trace.log.MethodTraceLogTestApplication. - Maven on this machine: invoke
mvnas/c/developer/apache-maven-3.9.16/bin/mvn— the defaultmvnshim is broken.
Install
This server does not publish a one-line install command.
Open the repository installation guide New to MCP? Start with the mcpskill.org guide →Configuration
{
"mcpServers": {
"sql-forge-mcp": {
"command": "jbang.cmd",
"args": [
"io.github.wb04307201:methodTraceLog-mcp:1.1.0",
"--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=Local dev",
"--method-trace-log.mcp.hosts[0].api-key=change-me-in-production"
]
}
}
}