Introduce clangd-server-monitor tool
authorKirill Bobyrev <kbobyrev@google.com>
Tue, 4 May 2021 10:48:20 +0000 (12:48 +0200)
committerKirill Bobyrev <kbobyrev@google.com>
Tue, 4 May 2021 10:48:21 +0000 (12:48 +0200)
Reviewed By: kadircet

Differential Revision: https://reviews.llvm.org/D101516

clang-tools-extra/clangd/index/remote/CMakeLists.txt
clang-tools-extra/clangd/index/remote/monitor/CMakeLists.txt [new file with mode: 0644]
clang-tools-extra/clangd/index/remote/monitor/Monitor.cpp [new file with mode: 0644]
clang-tools-extra/clangd/test/CMakeLists.txt
clang-tools-extra/clangd/test/remote-index/pipeline.test
clang-tools-extra/clangd/test/remote-index/pipeline_helper.py

index 2aa6e9b..beae5be 100644 (file)
@@ -38,6 +38,7 @@ if (CLANGD_ENABLE_REMOTE)
 
   add_subdirectory(marshalling)
   add_subdirectory(server)
+  add_subdirectory(monitor)
 else()
   # Provides a no-op implementation of clangdRemoteIndex.
   add_subdirectory(unimplemented)
diff --git a/clang-tools-extra/clangd/index/remote/monitor/CMakeLists.txt b/clang-tools-extra/clangd/index/remote/monitor/CMakeLists.txt
new file mode 100644 (file)
index 0000000..602cb3e
--- /dev/null
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+add_clang_executable(clangd-index-server-monitor
+  Monitor.cpp
+
+  DEPENDS
+  RemoteIndexServiceProto
+  )
+
+target_link_libraries(clangd-index-server-monitor
+  PRIVATE
+  clangBasic
+  clangdSupport
+
+  MonitoringServiceProto
+  RemoteIndexServiceProto
+  )
diff --git a/clang-tools-extra/clangd/index/remote/monitor/Monitor.cpp b/clang-tools-extra/clangd/index/remote/monitor/Monitor.cpp
new file mode 100644 (file)
index 0000000..96451f7
--- /dev/null
@@ -0,0 +1,75 @@
+//===--- Monitor.cpp - Request server monitoring information through CLI --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MonitoringService.grpc.pb.h"
+#include "MonitoringService.pb.h"
+
+#include "support/Logger.h"
+#include "clang/Basic/Version.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Signals.h"
+
+#include <chrono>
+#include <google/protobuf/util/json_util.h>
+#include <grpc++/grpc++.h>
+
+namespace clang {
+namespace clangd {
+namespace remote {
+namespace {
+
+static constexpr char Overview[] = R"(
+This tool requests monitoring information (uptime, index freshness) from the
+server and prints it to stdout.
+)";
+
+llvm::cl::opt<std::string>
+    ServerAddress("server-address", llvm::cl::Positional,
+                  llvm::cl::desc("Address of the invoked server."),
+                  llvm::cl::Required);
+
+} // namespace
+} // namespace remote
+} // namespace clangd
+} // namespace clang
+
+int main(int argc, char *argv[]) {
+  using namespace clang::clangd::remote;
+  llvm::cl::ParseCommandLineOptions(argc, argv, Overview);
+  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+
+  const auto Channel =
+      grpc::CreateChannel(ServerAddress, grpc::InsecureChannelCredentials());
+  const auto Stub = clang::clangd::remote::v1::Monitor::NewStub(Channel);
+  grpc::ClientContext Context;
+  Context.set_deadline(std::chrono::system_clock::now() +
+                       std::chrono::seconds(10));
+  Context.AddMetadata("version", clang::getClangToolFullVersion("clangd"));
+  const clang::clangd::remote::v1::MonitoringInfoRequest Request;
+  clang::clangd::remote::v1::MonitoringInfoReply Response;
+  const auto Status = Stub->MonitoringInfo(&Context, Request, &Response);
+  if (!Status.ok()) {
+    clang::clangd::elog("Can not request monitoring information ({0}): {1}\n",
+                        Status.error_code(), Status.error_message());
+    return -1;
+  }
+  std::string Output;
+  google::protobuf::util::JsonPrintOptions Options;
+  Options.add_whitespace = true;
+  Options.always_print_primitive_fields = true;
+  Options.preserve_proto_field_names = true;
+  const auto JsonStatus =
+      google::protobuf::util::MessageToJsonString(Response, &Output, Options);
+  if (!JsonStatus.ok()) {
+    clang::clangd::elog("Can not convert response ({0}) to JSON ({1}): {2}\n",
+                        Response.DebugString(), JsonStatus.error_code(),
+                        JsonStatus.error_message().as_string());
+    return -1;
+  }
+  llvm::outs() << Output;
+}
index 4c983c5..f4c4fb6 100644 (file)
@@ -22,7 +22,7 @@ if(CLANGD_BUILD_XPC)
 endif()
 
 if(CLANGD_ENABLE_REMOTE)
-  list(APPEND CLANGD_TEST_DEPS clangd-index-server)
+  list(APPEND CLANGD_TEST_DEPS clangd-index-server clangd-index-server-monitor)
 endif()
 
 foreach(dep FileCheck count not llvm-config)
index 69f4c67..8a1ad66 100644 (file)
@@ -3,6 +3,11 @@
 # RUN: %python %S/pipeline_helper.py --input-file-name=%s --project-root=%S --index-file=%t.idx | FileCheck %s
 # REQUIRES: clangd-remote-index
 
+#      CHECK:  "uptime_seconds": "{{.*}}",
+# CHECK-NEXT:  "index_age_seconds": "{{.*}}",
+# CHECK-NEXT:  "index_commit_hash": "{{.*}}",
+# CHECK-NEXT:  "index_link": "{{.*}}"
+
 {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
 #      CHECK:  "id": 0,
 # CHECK-NEXT:  "jsonrpc": "2.0",
index 859792d..75ff5ff 100644 (file)
@@ -17,7 +17,7 @@ import time
 import threading
 
 
-def kill_server_after_delay(server_process):
+def kill_process_after_delay(server_process):
   time.sleep(10)
   if server_process.poll() is None:
     server_process.kill()
@@ -48,7 +48,7 @@ def main():
   # This will kill index_server_process if it hangs without printing init
   # message.
   shutdown_thread = threading.Thread(
-      target=kill_server_after_delay, args=(index_server_process,))
+      target=kill_process_after_delay, args=(index_server_process,))
   shutdown_thread.daemon = True
   shutdown_thread.start()
 
@@ -67,6 +67,13 @@ def main():
     print('Server initialization failed. Shutting down.', file=sys.stderr)
     sys.exit(1)
 
+  print('Running clangd-index-server-monitor...', file=sys.stderr)
+  index_server_monitor_process = subprocess.Popen([
+      'clangd-index-server-monitor', server_address,
+  ], stderr=subprocess.PIPE)
+
+  index_server_monitor_process.wait()
+
   in_file = open(args.input_file_name)
 
   print('Staring clangd...', file=sys.stderr)
@@ -84,6 +91,10 @@ def main():
     args.server_log.write(line)
     args.server_log.flush()
 
+  for line in index_server_monitor_process.stderr:
+    args.server_log.write(line)
+    args.server_log.flush()
+
 
 if __name__ == '__main__':
   main()