diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
index f0896b0..8ebedce 100644
--- a/docs/.vitepress/config.mts
+++ b/docs/.vitepress/config.mts
@@ -1,4 +1,4 @@
-import { defineConfig } from 'vitepress'
+import { defineConfig } from "vitepress";
// https://vitepress.dev/reference/site-config
export default defineConfig({
@@ -6,57 +6,64 @@ export default defineConfig({
description: "Kyanos official website",
head: [["link", { rel: "icon", href: "/kyanos.png" }]], // 浏览器标签页logo
locales: {
- cn: { label: '简体中文', lang: 'cn' },
- root: { label: 'English', lang: 'en' },
+ cn: { label: "简体中文", lang: "cn" },
+ root: { label: "English", lang: "en" }
},
- appearance: 'dark',
+ appearance: "dark",
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: "/kyanos.png",
nav: [
- { text: 'Home', link: '/' },
- { text: 'Guide', link: './what-is-kyanos' }
+ { text: "Home", link: "/" },
+ { text: "Guide", link: "./what-is-kyanos" }
],
sidebar: [
{
- text: 'Introduction',
+ text: "Introduction",
items: [
- { text: 'What is Kyanos?', link: './what-is-kyanos' },
- { text: 'Quickstart', link: './quickstart' },
- { text: 'FAQ', link: './faq' },
+ { text: "What is Kyanos?", link: "./what-is-kyanos" },
+ { text: "Quickstart", link: "./quickstart" },
+ { text: "FAQ", link: "./faq" }
]
},
{
- text: 'Tutorial',
+ text: "Tutorial",
items: [
-
- { text: 'Learn kyanos in 5 minutes', link: './how-to' },
- { text: 'How to use watch', link: './watch' },
- { text: 'How to use stat', link: './stat' },
+ { text: "Learn kyanos in 5 minutes", link: "./how-to" },
+ { text: "How to use watch", link: "./watch" },
+ { text: "How to use stat", link: "./stat" }
]
},
{
- text: 'Development',
+ text: "Development",
items: [
-
- { text: 'How to build', link: './how-to-build' },
- { text: 'How to add a new protocol', link: './how-to-add-a-new-protocol' },
+ { text: "How to build", link: "./how-to-build" },
+ {
+ text: "How to add a new protocol",
+ link: "./how-to-add-a-new-protocol"
+ },
+ {
+ text: "Debug Tips",
+ link: "./debug-tips"
+ }
]
}
],
socialLinks: [
- { icon: 'github', link: 'https://github.com/hengyoush/kyanos' }
+ { icon: "github", link: "https://github.com/hengyoush/kyanos" }
],
-
+
footer: {
- message: 'Released under the Apache-2.0 license.',
- copyright: 'Copyright © 2024-present Hengyoush'
+ message:
+ 'Released under the Apache-2.0 license.',
+ copyright:
+ 'Copyright © 2024-present Hengyoush'
},
-
+
search: {
- provider: 'local'
- },
+ provider: "local"
+ }
}
-})
+});
diff --git a/docs/.vitepress/theme/index.mts b/docs/.vitepress/theme/index.mts
index 50ccb9e..e98b6f2 100644
--- a/docs/.vitepress/theme/index.mts
+++ b/docs/.vitepress/theme/index.mts
@@ -1,5 +1,5 @@
import Theme from "vitepress/theme";
import "./style/index.css";
export default {
- ...Theme,
-};
\ No newline at end of file
+ ...Theme
+};
diff --git a/docs/.vitepress/theme/style/index.css b/docs/.vitepress/theme/style/index.css
index c9efd04..2164da9 100644
--- a/docs/.vitepress/theme/style/index.css
+++ b/docs/.vitepress/theme/style/index.css
@@ -1 +1 @@
-@import "./var.css"
\ No newline at end of file
+@import "./var.css";
diff --git a/docs/.vitepress/theme/style/var.css b/docs/.vitepress/theme/style/var.css
index a53dbec..ba0f6f6 100644
--- a/docs/.vitepress/theme/style/var.css
+++ b/docs/.vitepress/theme/style/var.css
@@ -1,19 +1,19 @@
:root {
- /* 标题 */
- --vp-home-hero-name-color: transparent;
- /* 渐变色 */
- --vp-home-hero-name-background: linear-gradient(
- 135deg,
- #76fddd 10%,
- #bbe2fe 100%
- );
- /* 纯色 */
- /* --vp-home-hero-name-background: red; */
- --vp-home-hero-image-background-image: linear-gradient(
- 135deg,
- #bbe2fe 10%,
- #76fddd 100%
- );
- /* 设置模糊度 */
- --vp-home-hero-image-filter: blur(150px);
- }
\ No newline at end of file
+ /* 标题 */
+ --vp-home-hero-name-color: transparent;
+ /* 渐变色 */
+ --vp-home-hero-name-background: linear-gradient(
+ 135deg,
+ #76fddd 10%,
+ #bbe2fe 100%
+ );
+ /* 纯色 */
+ /* --vp-home-hero-name-background: red; */
+ --vp-home-hero-image-background-image: linear-gradient(
+ 135deg,
+ #bbe2fe 10%,
+ #76fddd 100%
+ );
+ /* 设置模糊度 */
+ --vp-home-hero-image-filter: blur(150px);
+}
diff --git a/docs/cn/debug-tips.md b/docs/cn/debug-tips.md
new file mode 100644
index 0000000..5789a0f
--- /dev/null
+++ b/docs/cn/debug-tips.md
@@ -0,0 +1,77 @@
+# Debug Tips
+
+## 构建相关
+
+注意每次修改eBPF相关代码后都需要使用`make build-bpf`重新生成一些bpf相关代码,然后再用`make`构建或者在IDE里调试。
+
+使用 `kyanos-debug` 来构建带有调试信息的二进制文件, 以便更好地进行调试。
+
+```sh
+make kyanos-debug
+```
+
+## 日志相关
+
+启动kyanos开启日志,日志分为几个模块可分别开启,5为debug级别,默认是warn级别。如下是每个模块的日志选项:
+
+| 参数 | 含义 |
+| --------------------- | ----------------------------------------------------------------------------------------- |
+| --agent-log-level | 指定agent模块日志级别,主要是和Agent启动等相关的日志 |
+| --bpf-event-log-level | 指定bpf事件日志级别,一些内核上报的和syscall层上报的事件会打印出来 |
+| --conntrack-log-level | 指定conntrack模块日志级别,一些连接相关的事件比如连接创建、协议推断、连接关闭等会打印出来 |
+| --protocol-log-level | 指定协议模块日志级别,主要是具体协议解析相关的日志 |
+| --uprobe-log-level | 指定uprobe模块日志级别,主要是和ssl探针相关的日志 |
+
+比如如果你在调试协议解析相关部分的代码建议加上:`--bpf-event-log-level 5 --conntrack-log-level 5 --protocol-log-level 5`。
+
+如果你碰到eBPF代码加载失败的情况,可以加上`--agent-log-level 5`日志打印一些Agent启动时的日志。
+
+日志输出默认到/tmp下,加上 `--debug-output`
+选项可以让日志输出到标准输出,而且不再展示tui会展示的表格,抓取到的请求都会直接输出到控制台:
+
+```
+WARN[0023] [ Request ]
+GET /health HTTP/1.1
+Host: :8080
+User-Agent: Go-http-client/1.1
+Accept-Encoding: gzip
+
+[ Response ]
+HTTP/1.1 200 OK
+Date: Wed, 01 Jan 2025 16:20:20 GMT
+Content-Length: 2
+Content-Type: text/plain; charset=utf-8
+
+OK
+
+[conn] [pid=2252][local addr]=127.0.0.1:8080 [remote addr]=127.0.0.1:38664 [side]=server [ssl]=false
+[total duration] = 0.423(ms)(start=2025-01-02 00:20:20.095, end=2025-01-02 00:20:20.095)
+[read from sockbuf]=0.296(ms)
+[process internal duration]=0.078(ms)
+[syscall] [read count]=1 [read bytes]=92 [write count]=1 [write bytes]=118
+```
+
+> [!TIP]
+>
+> 调试协议解析相关代码时可以使用:`--bpf-event-log-level 5 --conntrack-log-level 5 --protocol-log-level 5 --debug-output`
+> 选项就基本上足够了。
+
+## 源码结构
+
+```
+> agent
+ > analysis (聚合分析模块,stat命令用到)
+ > conn (连接跟踪模块)
+ > protocol(协议解析模块)
+ > render(TUI渲染模块)
+ > uprobe(uprobe相关主要是ssl探针)
+> bpf
+ > loader (bpf 程序加载逻辑)
+ pktlatency.bpf.go (内核态核心代码,包括系统调用和内核部分的事件上报等逻辑)
+ gotls.bpf.go (gotls探针相关)
+ protocol_inference.h (协议推断相关)
+ openssl* (openssl相关)
+> cmd (命令行相关)
+> common (一些工具类)
+> docs (基于vitepress的文档)
+```
diff --git a/docs/cn/how-to-add-a-new-protocol.md b/docs/cn/how-to-add-a-new-protocol.md
index d54df54..7ed0325 100644
--- a/docs/cn/how-to-add-a-new-protocol.md
+++ b/docs/cn/how-to-add-a-new-protocol.md
@@ -85,12 +85,12 @@ type ParsedMessage interface {
}
```
-| 方法名 | 作用 |
-| ------------------ | ------------------------------------------------------------------------ |
-| `FormatToString()` | 将消息格式化为字符串表示形式。 |
-| `TimestampNs()` | 返回消息的时间戳(以纳秒为单位)。 |
-| `ByteSize()` | 返回消息的字节大小。 |
-| `IsReq()` | 判断消息是否为请求。 |
+| 方法名 | 作用 |
+| ------------------ | -------------------------------------------------------------------------- |
+| `FormatToString()` | 将消息格式化为字符串表示形式。 |
+| `TimestampNs()` | 返回消息的时间戳(以纳秒为单位)。 |
+| `ByteSize()` | 返回消息的字节大小。 |
+| `IsReq()` | 判断消息是否为请求。 |
| `Seq()` | 返回消息的字节流序列号, 可以从 `streamBuffer.Head().LeftBoundary()` 获取。 |
HTTP 的例子:
@@ -137,10 +137,11 @@ ParseStream(streamBuffer *buffer.StreamBuffer, messageType MessageType) ParseRes
注意 eBPF 数据事件可能会无序到达,或者丢失事件,因此数据缓冲区中的数据可能缺少数据块,参数 streamBuffer 中通过
`streamBuffer.Head`
-函数获取到目前为止已接收到的缓冲区前面的所有连续数据。因此,此时 **无法保证数据有效或缓冲区与数据包的开头对齐**。
+函数获取到目前为止已接收到的缓冲区前面的所有连续数据。因此,此时
+**无法保证数据有效或缓冲区与数据包的开头对齐**。
-如果返回 `ParseResult` 中的 `state` 为
-`success`,且那么 kyanos 会自动删除掉 `ParseResult.ReadBytes` 个字节的数据;如果返回 `invalid`,那么通过
+如果返回 `ParseResult` 中的 `state` 为 `success`,且那么 kyanos 会自动删除掉
+`ParseResult.ReadBytes` 个字节的数据;如果返回 `invalid`,那么通过
`FindBoundary` 找到下一个可能的 `Message` 边界;如果返回
`needsMoreData`,则不会删除数据,而是稍后重试。
@@ -242,7 +243,8 @@ func init() {
## Step.6-添加 e2e 测试
-在 testdata 目录下添加对应协议的 e2e 测试,可以参考其他协议的写法(比如 `test_redis.sh` 等)。
+在 testdata 目录下添加对应协议的 e2e 测试,可以参考其他协议的写法(比如
+`test_redis.sh` 等)。
## 其他
@@ -252,7 +254,9 @@ func init() {
`common.ProtocolParserLog`. 打开 protocol 解析日志:`--protocol-log-level 5`
设置协议解析相关 log 日志为 debug 级别。
-协议解析框架代码在 conntrack.go 的 `addDataToBufferAndTryParse` 函数里。
+协议解析框架代码在 conntrack.go 的 `addDataToBufferAndTryParse` 函数里。
+
+更多调试建议参考:[Debug Tips](./debug-tips)
### 协议解析持久化信息
diff --git a/docs/debug-tips.md b/docs/debug-tips.md
new file mode 100644
index 0000000..0c00c92
--- /dev/null
+++ b/docs/debug-tips.md
@@ -0,0 +1,87 @@
+# Debug Tips
+
+## Build Related
+
+Note that every time you modify the eBPF-related code, you need to use
+`make build-bpf` to regenerate some bpf-related code, and then use `make` to
+build or debug in the IDE.
+
+Use `kyanos-debug` to build binary files with debug information for better
+debugging.
+
+```sh
+make kyanos-debug
+```
+
+## Log Related
+
+Start kyanos with logging enabled. Logs are divided into several modules that
+can be enabled separately. Level 5 is the debug level, and the default is the
+warn level. The following are the log options for each module:
+
+| Parameter | Meaning |
+| --------------------- | -------------------------------------------------------------------------------------- |
+| --agent-log-level | Specify the log level for the agent module, mainly related to Agent startup logs |
+| --bpf-event-log-level | Specify the log level for bpf events, logs related to kernel and syscall layer events |
+| --conntrack-log-level | Specify the log level for the conntrack module, logs related to connection events |
+| --protocol-log-level | Specify the log level for the protocol module, mainly related to protocol parsing logs |
+| --uprobe-log-level | Specify the log level for the uprobe module, mainly related to ssl probe logs |
+
+For example, if you are debugging the protocol parsing part of the code, it is
+recommended to add:
+`--bpf-event-log-level 5 --conntrack-log-level 5 --protocol-log-level 5`.
+
+If you encounter a situation where the eBPF code fails to load, you can add
+`--agent-log-level 5` to print some logs during Agent startup.
+
+Logs are output to /tmp by default. Adding the `--debug-output` option allows
+logs to be output to standard output, and the tables displayed by the TUI will
+not be shown. All captured requests will be directly output to the console:
+
+```
+WARN[0023] [ Request ]
+GET /health HTTP/1.1
+Host: :8080
+User-Agent: Go-http-client/1.1
+Accept-Encoding: gzip
+
+[ Response ]
+HTTP/1.1 200 OK
+Date: Wed, 01 Jan 2025 16:20:20 GMT
+Content-Length: 2
+Content-Type: text/plain; charset=utf-8
+
+OK
+
+[conn] [pid=2252][local addr]=127.0.0.1:8080 [remote addr]=127.0.0.1:38664 [side]=server [ssl]=false
+[total duration] = 0.423(ms)(start=2025-01-02 00:20:20.095, end=2025-01-02 00:20:20.095)
+[read from sockbuf]=0.296(ms)
+[process internal duration]=0.078(ms)
+[syscall] [read count]=1 [read bytes]=92 [write count]=1 [write bytes]=118
+```
+
+> [!TIP]
+>
+> When debugging protocol parsing related code, you can use:
+> `--bpf-event-log-level 5 --conntrack-log-level 5 --protocol-log-level 5 --debug-output`
+> This option is generally sufficient.
+
+## Source Code Structure
+
+```
+> agent
+ > analysis (aggregation analysis module, used by the stat command)
+ > conn (connection tracking module)
+ > protocol (protocol parsing module)
+ > render (TUI rendering module)
+ > uprobe (uprobe related, mainly ssl probe)
+> bpf
+ > loader (bpf program loading logic)
+ pktlatency.bpf.go (kernel core code, including syscall and kernel event reporting logic)
+ gotls.bpf.go (gotls probe related)
+ protocol_inference.h (protocol inference related)
+ openssl* (openssl related)
+> cmd (command line related)
+> common (some utility classes)
+> docs (documentation based on vitepress)
+```
diff --git a/docs/how-to-add-a-new-protocol.md b/docs/how-to-add-a-new-protocol.md
index 085b333..df60d42 100644
--- a/docs/how-to-add-a-new-protocol.md
+++ b/docs/how-to-add-a-new-protocol.md
@@ -300,6 +300,8 @@ protocol parsing-related log levels to debug.
The protocol parsing framework code is in the `addDataToBufferAndTryParse`
function in conntrack.go.
+More debug tips are here:[Debug Tips](./debug-tips)
+
### Persisting Protocol Parsing Information
In some protocols, if you need to retain some data during the parsing process