aboutsummaryrefslogtreecommitdiffstats
path: root/filter/filter.go
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2024-09-02 16:45:07 +0800
committerWe-unite <3205135446@qq.com>2024-09-02 16:45:07 +0800
commit08207d77be79afc6f75d1611726b92bdf622717f (patch)
tree918991217807ff18025b998407b87bcd31d4ddc3 /filter/filter.go
parentf9f8f35ccd8b505a827d40f95c52ed039512b79d (diff)
downloadgodo-08207d77be79afc6f75d1611726b92bdf622717f.tar.gz
godo-08207d77be79afc6f75d1611726b92bdf622717f.zip
Show filt result in tree&json, fix sth in listenerHEADmasterdev
In the listener, I change the order coroutines are started to avoid 'send on a closed channel'. Besides, the method to get syscall names and numbers are not so universial, so let's go back to check unistd.h. In the filter, the output is set to be written to ./log dir. Pid tree are shown in logs/tree.log, and detail info in pids.log, while file info in the logs/files.log. tree.log shows a tree just like `tree` command, the other two files are written in json. What's more, the flags while opening files are also checked ans showed in files.log.
Diffstat (limited to 'filter/filter.go')
-rw-r--r--filter/filter.go328
1 files changed, 36 insertions, 292 deletions
diff --git a/filter/filter.go b/filter/filter.go
index 98c326c..6391afc 100644
--- a/filter/filter.go
+++ b/filter/filter.go
@@ -2,11 +2,10 @@ package main
2 2
3import ( 3import (
4 "context" 4 "context"
5 "encoding/json"
5 "fmt" 6 "fmt"
6 "log" 7 "log"
7 "os" 8 "os"
8 "path"
9 "sort"
10 9
11 "go.mongodb.org/mongo-driver/bson" 10 "go.mongodb.org/mongo-driver/bson"
12 "go.mongodb.org/mongo-driver/mongo" 11 "go.mongodb.org/mongo-driver/mongo"
@@ -33,7 +32,7 @@ var files []File
33 32
34func main() { 33func main() {
35 // 连接到MongoDB 34 // 连接到MongoDB
36 client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://localhost:27017")) 35 client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://192.168.192.136:27017"))
37 if err != nil { 36 if err != nil {
38 log.Fatal(err) 37 log.Fatal(err)
39 } 38 }
@@ -114,303 +113,48 @@ func main() {
114 for _, file := range files { 113 for _, file := range files {
115 newFileCol.InsertOne(context.Background(), file) 114 newFileCol.InsertOne(context.Background(), file)
116 } 115 }
117}
118
119func ProMerge(a, b Process) (res Process) {
120 // 合并过程中会遇到什么问题?
121 res.Star = false
122
123 if a.StartTimestamp.IsZero() {
124 res.StartTimestamp = b.StartTimestamp
125 } else if b.StartTimestamp.IsZero() {
126 res.StartTimestamp = a.StartTimestamp
127 } else if a.StartTimestamp.Before(b.StartTimestamp) {
128 res.StartTimestamp = a.StartTimestamp
129 } else {
130 res.StartTimestamp = b.StartTimestamp
131 }
132
133 res.Ppid = a.Ppid
134 if a.ParentTgid == 0 {
135 res.ParentTgid = b.ParentTgid
136 } else {
137 res.ParentTgid = a.ParentTgid
138 }
139
140 res.Pid = a.Pid
141 if a.Tgid == 0 {
142 res.Tgid = b.Tgid
143 } else {
144 res.Tgid = a.Tgid
145 }
146
147 if len(a.Args) == 0 {
148 res.Args = b.Args
149 } else {
150 res.Args = a.Args
151 }
152
153 if a.Comm == "" {
154 res.Comm = b.Comm
155 } else {
156 res.Comm = a.Comm
157 }
158
159 if a.RootFS == "" {
160 res.RootFS = b.RootFS
161 } else {
162 res.RootFS = a.RootFS
163 }
164
165 if a.Cwd == "" {
166 res.Cwd = b.Cwd
167 } else {
168 res.Cwd = a.Cwd
169 }
170
171 res.Execve = append(a.Execve, b.Execve...)
172 res.Children = append(a.Children, b.Children...)
173 116
174 var flag bool // 真a假b 117 /* Step 3: 输出到文件
175 if a.ExitTimestamp.IsZero() { 118 * - 所有内容输出到logs目录,所有文本存在则覆盖,不存在则创建
176 flag = false 119 * - 进程树输出到logs/tree.log
177 } else if b.ExitTimestamp.IsZero() { 120 * - 每个进程以json格式输出到logs/pids.log
178 flag = true 121 * - 文件信息输出到logs/files.log
179 } else if a.ExitTimestamp.Before(b.ExitTimestamp) { 122 */
180 flag = true 123 stat, err := os.Stat("logs")
181 } else { 124 if err != nil || !stat.IsDir() {
182 flag = false 125 os.Mkdir("logs", 0755)
183 }
184
185 if flag {
186 res.ExitCode = a.ExitCode
187 res.ExitSignal = a.ExitSignal
188 res.ExitTimestamp = a.ExitTimestamp
189 } else {
190 res.ExitCode = b.ExitCode
191 res.ExitSignal = b.ExitSignal
192 res.ExitTimestamp = b.ExitTimestamp
193 }
194
195 return res
196}
197
198func mergeProcess(pRawPidData *[]Process) (merged []Process) {
199 rawPidData := *pRawPidData
200 // 合并由多线程导致的重复记录,顺便按照pid升序
201 index := make(map[int]int)
202 for _, process := range rawPidData {
203 i, exists := index[process.Pid]
204 if exists {
205 // 已存在,合并
206 merged[i] = ProMerge(merged[i], process)
207 } else {
208 // 不存在,直接添加
209 merged = append(merged, process)
210 index[process.Pid] = len(merged) - 1
211 }
212 }
213 sort.Slice(merged, func(i, j int) bool {
214 return merged[i].Pid < merged[j].Pid
215 })
216 return merged
217}
218
219func getTgidNodes(merged []Process) (tgidMap map[int]*tgidNode, starTgid int, rootfsPids []int) {
220 // 合并出来的进程整理为tgidNode
221 tgidMap = make(map[int]*tgidNode)
222 findTgid = make(map[int]int) // pid --> tgid
223 // var starTgid, rootFsPid int
224 starTgid = -1
225 // rootfsPid = -1
226 rootfsPids = make([]int, 0)
227 for _, val := range merged {
228 if val.Star {
229 starTgid = val.Tgid
230 } else if val.RootFS != "" {
231 rootfsPids = append(rootfsPids, val.Pid)
232 }
233 // 登记tgid
234 findTgid[val.Pid] = val.Tgid
235 nodeval, exists := tgidMap[val.Tgid]
236 if exists {
237 // 直接记录
238 nodeval.Threads = append(nodeval.Threads, val)
239 nodeval.FindPid[val.Pid] = len(nodeval.Threads) - 1
240 } else {
241 node := tgidNode{
242 Tgid: val.Tgid,
243 FindPid: make(map[int]int),
244 Threads: make([]Process, 0),
245 ChildTgid: make([]int, 0),
246 }
247 node.Threads = append(node.Threads, val)
248 node.FindPid[val.Pid] = 0
249 tgidMap[val.Tgid] = &node
250 }
251 } 126 }
252 return tgidMap, starTgid, rootfsPids
253}
254 127
255func buildTree(tgidMap map[int]*tgidNode, starTgid int) { 128 // 进程树
256 // 从tgid==starTgid开始,构建树 129 treeFile, err := os.OpenFile("logs/tree.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
257 helloTree = make(map[int]*tgidNode) // 在树上的tgid节点,tgid --> *tgidNode 130 if err != nil {
258 var q Queue // 记录每一个整理好的结构体,bfs 131 fmt.Fprintf(os.Stderr, "Err: %v\n", err)
259 visited := make(map[int]bool) // 哪些tgid已经访问过
260
261 tmp, exists := tgidMap[starTgid]
262 if !exists {
263 return 132 return
264 } 133 }
265 134 defer treeFile.Close()
266 // helloTree负责在遍历到该节点时记录 135 pidFile, err := os.OpenFile("logs/pid.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
267 // 队列仅负责搞明白哪些节点在树上 136 if err != nil {
268 // 因而所有添加子代tgid的行为只针对helloTree 137 fmt.Fprintf(os.Stderr, "Err: %v\n", err)
269 // q不添加,直接把新的tgid对应的tgidNode入队就是了 138 return
270 q.Enqueue(tmp)
271 visited[starTgid] = true
272 for !q.IsEmpty() {
273 tmp, ok := q.Dequeue()
274 if !ok {
275 continue
276 }
277 node := tmp.(*tgidNode) // 队列里的一个节点,这里必须重新申请node
278 helloTree[node.Tgid] = node
279 for i := 0; i < len(node.Threads); i++ {
280 for j := 0; j < len(node.Threads[i].Children); j++ {
281 tgid := findTgid[node.Threads[i].Children[j]]
282 _, exists := visited[tgid]
283 if !exists {
284 // 子代里有没见过的tgid
285 tgidNode, exists := tgidMap[tgid]
286 if !exists {
287 continue
288 }
289 helloTree[node.Tgid].ChildTgid = append(helloTree[node.Tgid].ChildTgid, tgid)
290 q.Enqueue(tgidNode)
291 visited[tgid] = true
292 }
293 }
294 }
295 }
296}
297
298func optimazePid(starTgid int, rootfsPids []int) {
299 getDockerRootFs := make(map[string]string) // dockerId --> rootfs
300 // 首先处理一下记录有pivot_root信息的进程,防止pivot先于fork
301 for _, rootfsPid := range rootfsPids {
302 rootfsTgid := findTgid[rootfsPid]
303 i := helloTree[rootfsTgid].FindPid[rootfsPid]
304 rootfsProcess := &(helloTree[rootfsTgid].Threads[i])
305 if rootfsProcess.RootFS == "cwd" {
306 rootfsProcess.RootFS = rootfsProcess.Cwd
307 }
308 getDockerRootFs[rootfsProcess.DockerId] = rootfsProcess.RootFS
309 } 139 }
140 defer pidFile.Close()
141 // 从starTgid开始,按照树的形状输出
142 drawTree(treeFile, pidFile, helloTree[starTgid], "", true)
310 143
311 count := 0 144 // 文件信息,json格式
312 for _, val := range helloTree { 145 fileFile, err := os.OpenFile("logs/files.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
313 // 处理一下pid结束时间,顺便找找爹 146 if err != nil {
314 // 结束时间是因为很多线程结束时间没获取到,默认按照进程退出时间处理 147 fmt.Fprintf(os.Stderr, "Err: %v\n", err)
315 // Ppid是因为进程产生之初收到的信息写的爹一定是亲爹 148 return
316 // 但是产生线程时候该进程很可能已作为孤儿被收养,导致线程里关于爹的记录是继父
317 for i := 0; i < len(val.Threads); i++ {
318 if i != 0 {
319 if val.Threads[i].Tgid < val.Threads[0].Tgid {
320 val.Threads[i].ParentTgid = val.Threads[0].ParentTgid
321 val.Threads[i].Ppid = val.Threads[0].Ppid
322 }
323 if val.Threads[i].ExitTimestamp.IsZero() {
324 val.Threads[i].ExitCode = val.Threads[0].ExitCode
325 val.Threads[i].ExitTimestamp = val.Threads[0].ExitTimestamp
326 val.Threads[i].ExitSignal = val.Threads[0].ExitSignal
327 }
328 }
329
330 dockerId := val.Threads[i].DockerId
331 if dockerId != "" {
332 rootfs, exists := getDockerRootFs[dockerId]
333 if !exists {
334 fmt.Fprintf(os.Stderr, "Err: the docker rootfs of pid %d is not known!\n", val.Threads[i].Pid)
335 continue
336 }
337 val.Threads[i].RootFS = rootfs
338 }
339 }
340
341 count++
342 fmt.Printf("%v\n", *val)
343 } 149 }
344 fmt.Printf("Star: %d, res: %d\n", starTgid, count) 150 defer fileFile.Close()
345} 151 for _, file := range files {
346 152 jsonData, err := json.MarshalIndent(file, "", " ")
347func filtPids(pRawPidData *[]Process) { 153 if err != nil {
348 /* ATTENTION: 把map/slice直接传参是危险的 154 fmt.Fprintf(os.Stderr, "Err: %v\n", err)
349 * 传递的是指针,不会引起大的复制开销, 155 return
350 * 但是map/slice在callee func内被修改**可能**导致内存更改
351 * 而这样的内存更改对caller function来说是不可见的,看到的还是原来的东西
352 * 这里由于参数几乎都是只读不写,因而用一下
353 */
354
355 // 合并由多线程导致的重复记录,顺便按照pid升序
356 // 多线程已经取消了,但保险起见还是留着
357 merged := mergeProcess(pRawPidData)
358 // 将Process按照tgid合并
359 tgidMap, starTgid, rootfsPids := getTgidNodes(merged)
360 // 建树,helloTree
361 buildTree(tgidMap, starTgid)
362 // 对树上的进程做一些优化处理
363 optimazePid(starTgid, rootfsPids)
364}
365
366func filtFiles(pRawFileData *[]File) {
367 rawFileData := *pRawFileData
368 files = make([]File, 0)
369
370 // 所有文件按照特定顺序排
371 sort.Slice(rawFileData, func(i, j int) bool {
372 pi := &rawFileData[i]
373 pj := &rawFileData[j]
374
375 if pi.FileName < pj.FileName {
376 return true
377 } else if pi.FileName > pj.FileName {
378 return false
379 }
380 if pi.Pid < pj.Pid {
381 return true
382 } else if pi.Pid > pj.Pid {
383 return false
384 }
385 if pi.Fd < pj.Fd {
386 return true
387 } else if pi.Fd > pj.Fd {
388 return false
389 }
390 if pi.OpenTimestamp.Before(pj.OpenTimestamp) {
391 return true
392 } else {
393 return false
394 }
395 })
396
397 for _, file := range rawFileData {
398 if file.FileName == "/root/test/1/../.hello.c.swp" {
399 fmt.Printf("Test\n")
400 }
401 tgid := findTgid[file.Pid]
402 pTgidNode, exists := helloTree[tgid]
403 if !exists {
404 continue
405 }
406 if file.CloseTimestamp.IsZero() {
407 index, exists := pTgidNode.FindPid[file.Pid]
408 if !exists || index < 0 || index >= len(pTgidNode.Threads) {
409 continue
410 }
411 file.CloseTimestamp = pTgidNode.Threads[index].ExitTimestamp
412 } 156 }
413 file.FileName = path.Clean(file.FileName) 157 fileFile.Write(jsonData)
414 files = append(files, file) 158 fileFile.WriteString("\n\n")
415 } 159 }
416} 160}