package main import ( "context" "encoding/json" "fmt" "log" "os" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) const ( oldDBName = "test" oldPidColName = "pids" oldFdColName = "fds" oldFileColName = "files" newDBName = "cooked" newPidColName = "tgids" newFileColName = "files" ) // 进程树信息 var findTgid map[int]int var helloTree map[int]*tgidNode // 文件信息 var files []File func main() { // 连接到MongoDB client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://192.168.192.136:27017")) if err != nil { log.Fatal(err) } defer client.Disconnect(context.TODO()) oldDB := client.Database(oldDBName) /* * Step 1: 进程数据处理 */ oldPidCol := oldDB.Collection(oldPidColName) // 数据提取 var rawPidData []Process cursor, err := oldPidCol.Find(context.Background(), bson.M{}) if err != nil { fmt.Fprintf(os.Stderr, "Err: %v\n", err) return } err = cursor.All(context.Background(), &rawPidData) if err != nil { fmt.Fprintf(os.Stderr, "Err All: %v\n", err) return } cursor.Close(context.Background()) filtPids(&rawPidData) /* * Step 2: 文件数据处理 * - 将已经关闭的和未关闭的同等看待 * - 未关闭的将关闭时间修改为对应进程退出时间 * - 值得注意的是,同一进程各线程共享文件描述符……需要处理吗? */ // 提取files和fds里的数据 // TODO:是否可以只筛选被写过的记录? var rawFileData []File oldFileCol := oldDB.Collection(oldFileColName) cursor, err = oldFileCol.Find(context.Background(), bson.M{}) if err != nil { fmt.Fprintf(os.Stderr, "Err: %v\n", err) return } err = cursor.All(context.Background(), &rawFileData) if err != nil { fmt.Fprintf(os.Stderr, "Err All: %v\n", err) return } cursor.Close(context.Background()) var rawFdData []File oldFdCol := oldDB.Collection(oldFdColName) cursor, err = oldFdCol.Find(context.Background(), bson.M{}) if err != nil { fmt.Fprintf(os.Stderr, "Err: %v\n", err) return } err = cursor.All(context.Background(), &rawFdData) if err != nil { fmt.Fprintf(os.Stderr, "Err All: %v\n", err) return } cursor.Close(context.Background()) // 合并,处理 rawFileData = append(rawFileData, rawFdData...) filtFiles(&rawFileData) // 扔回数据库 newDB := client.Database(newDBName) newDB.Drop(context.Background()) newPidCol := newDB.Collection(newPidColName) for _, pTgidNode := range helloTree { newPidCol.InsertOne(context.Background(), *pTgidNode) } newFileCol := newDB.Collection(newFileColName) for _, file := range files { newFileCol.InsertOne(context.Background(), file) } /* Step 3: 输出到文件 * - 所有内容输出到logs目录,所有文本存在则覆盖,不存在则创建 * - 进程树输出到logs/tree.log * - 每个进程以json格式输出到logs/pids.log * - 文件信息输出到logs/files.log */ stat, err := os.Stat("logs") if err != nil || !stat.IsDir() { os.Mkdir("logs", 0755) } // 进程树 treeFile, err := os.OpenFile("logs/tree.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { fmt.Fprintf(os.Stderr, "Err: %v\n", err) return } defer treeFile.Close() pidFile, err := os.OpenFile("logs/pid.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { fmt.Fprintf(os.Stderr, "Err: %v\n", err) return } defer pidFile.Close() // 从starTgid开始,按照树的形状输出 drawTree(treeFile, pidFile, helloTree[starTgid], "", true) // 文件信息,json格式 fileFile, err := os.OpenFile("logs/files.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { fmt.Fprintf(os.Stderr, "Err: %v\n", err) return } defer fileFile.Close() for _, file := range files { jsonData, err := json.MarshalIndent(file, "", " ") if err != nil { fmt.Fprintf(os.Stderr, "Err: %v\n", err) return } fileFile.Write(jsonData) fileFile.WriteString("\n\n") } }