diff --git a/clang-tools-extra/clangd/index/remote/CMakeLists.txt b/clang-tools-extra/clangd/index/remote/CMakeLists.txt --- a/clang-tools-extra/clangd/index/remote/CMakeLists.txt +++ b/clang-tools-extra/clangd/index/remote/CMakeLists.txt @@ -38,6 +38,7 @@ 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 --- /dev/null +++ b/clang-tools-extra/clangd/index/remote/monitor/CMakeLists.txt @@ -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 --- /dev/null +++ b/clang-tools-extra/clangd/index/remote/monitor/Monitor.cpp @@ -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 +#include +#include + +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 + 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; +} diff --git a/clang-tools-extra/clangd/test/CMakeLists.txt b/clang-tools-extra/clangd/test/CMakeLists.txt --- a/clang-tools-extra/clangd/test/CMakeLists.txt +++ b/clang-tools-extra/clangd/test/CMakeLists.txt @@ -22,7 +22,7 @@ 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) diff --git a/clang-tools-extra/clangd/test/remote-index/pipeline.test b/clang-tools-extra/clangd/test/remote-index/pipeline.test --- a/clang-tools-extra/clangd/test/remote-index/pipeline.test +++ b/clang-tools-extra/clangd/test/remote-index/pipeline.test @@ -1,8 +1,13 @@ # RUN: rm -rf %t # RUN: clangd-indexer %S/Inputs/Source.cpp > %t.idx -# RUN: %python %S/pipeline_helper.py --input-file-name=%s --project-root=%S --index-file=%t.idx | FileCheck %s +# RUN: %python %S/pipeline_helper.py --with-monitor --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", diff --git a/clang-tools-extra/clangd/test/remote-index/pipeline_helper.py b/clang-tools-extra/clangd/test/remote-index/pipeline_helper.py --- a/clang-tools-extra/clangd/test/remote-index/pipeline_helper.py +++ b/clang-tools-extra/clangd/test/remote-index/pipeline_helper.py @@ -17,7 +17,7 @@ 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 @@ # 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 @@ 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 @@ 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()