| 361 | } |
| 362 | |
| 363 | int Client::FollowLogs(const std::string& vm_id) const { |
| 364 | auto conn = ipc::UnixSocketClient::Connect(socket_path_); |
| 365 | if (!conn.IsValid()) { |
| 366 | std::cerr << "failed to connect to " << socket_path_ << "\n"; |
| 367 | return 1; |
| 368 | } |
| 369 | if (!WriteJsonLine(conn, {{"type", "vm.logs.follow"}, {"vm_id", vm_id}})) { |
| 370 | std::cerr << "failed to send logs follow request\n"; |
| 371 | return 1; |
| 372 | } |
| 373 | const std::string first = conn.ReadLine(); |
| 374 | auto response = nlohmann::json::parse(first, nullptr, false); |
| 375 | if (response.is_discarded() || !response.value("ok", false)) { |
| 376 | std::cerr << (response.is_object() ? response.value("error", "logs follow failed") |
| 377 | : "logs follow failed") |
| 378 | << "\n"; |
| 379 | return 1; |
| 380 | } |
| 381 | std::cerr << "Following logs for " << vm_id << ". Press Ctrl-C to stop.\n"; |
| 382 | while (true) { |
| 383 | const std::string line = conn.ReadLine(); |
| 384 | if (line.empty()) break; |
| 385 | auto event = nlohmann::json::parse(line, nullptr, false); |
| 386 | if (event.is_discarded()) continue; |
| 387 | if (event.value("type", "") != "vm.logs.append") continue; |
| 388 | const auto& payload = event["payload"]; |
| 389 | if (!payload.contains("lines") || !payload["lines"].is_array()) continue; |
| 390 | for (const auto& l : payload["lines"]) { |
| 391 | if (!l.is_string()) continue; |
| 392 | const std::string& s = l.get_ref<const std::string&>(); |
| 393 | ::write(STDOUT_FILENO, s.data(), s.size()); |
| 394 | ::write(STDOUT_FILENO, "\n", 1); |
| 395 | } |
| 396 | } |
| 397 | return 0; |
| 398 | } |
| 399 | |
| 400 | } // namespace tenbox::client |