From 660da3f80eae70b6f00579bb7b8e9c295e5ba80d Mon Sep 17 00:00:00 2001 From: John Knox Date: Wed, 15 Aug 2018 05:06:34 -0700 Subject: [PATCH] Add getStateSummary method for diagnostics Summary: Adds a more structured representation of state updates than a multiline string. Also changes the string form to omit [started] records. Reviewed By: danielbuechele Differential Revision: D9315503 fbshipit-source-id: 55b8f9572091fd42fe852c8d26a8f2a53f76c82a --- android/src/main/cpp/sonar.cpp | 33 +++++++++++++++- .../sonar/android/SonarClientImpl.java | 4 ++ .../com/facebook/sonar/core/SonarClient.java | 2 + .../com/facebook/sonar/core/StateElement.java | 13 +++++++ .../com/facebook/sonar/core/StateSummary.java | 38 +++++++++++++++++++ xplat/Sonar/SonarClient.cpp | 7 +++- xplat/Sonar/SonarClient.h | 3 ++ xplat/Sonar/SonarState.cpp | 29 ++++++++++---- xplat/Sonar/SonarState.h | 24 +++++++++++- xplat/Sonar/SonarWebSocketImpl.cpp | 4 +- 10 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 android/src/main/java/com/facebook/sonar/core/StateElement.java create mode 100644 android/src/main/java/com/facebook/sonar/core/StateSummary.java diff --git a/android/src/main/cpp/sonar.cpp b/android/src/main/cpp/sonar.cpp index 9161d30df..6b3020bd8 100644 --- a/android/src/main/cpp/sonar.cpp +++ b/android/src/main/cpp/sonar.cpp @@ -23,6 +23,7 @@ #include #include #include +#include using namespace facebook; using namespace facebook::sonar; @@ -249,6 +250,21 @@ class JSonarPluginWrapper : public SonarPlugin { JSonarPluginWrapper(jni::global_ref plugin): jplugin(plugin) {} }; +struct JStateSummary : public jni::JavaClass { +public: + constexpr static auto kJavaDescriptor = "Lcom/facebook/sonar/core/StateSummary;"; + + static jni::local_ref create() { + return newInstance(); + } + + void addEntry(std::string name, std::string state) { + static const auto method = javaClassStatic()->getMethod("addEntry"); + return method(self(), name, state); + } + +}; + class JSonarClient : public jni::HybridClass { public: constexpr static auto kJavaDescriptor = "Lcom/facebook/sonar/android/SonarClientImpl;"; @@ -265,6 +281,7 @@ class JSonarClient : public jni::HybridClass { makeNativeMethod("unsubscribe", JSonarClient::unsubscribe), makeNativeMethod("getPlugin", JSonarClient::getPlugin), makeNativeMethod("getState", JSonarClient::getState), + makeNativeMethod("getStateSummary", JSonarClient::getStateSummary), }); } @@ -307,6 +324,21 @@ class JSonarClient : public jni::HybridClass { return SonarClient::instance()->getState(); } + jni::global_ref getStateSummary() { + auto summary = jni::make_global(JStateSummary::create()); + auto elements = SonarClient::instance()->getStateElements(); + for (auto&& element : elements) { + std::string status; + switch (element.state_) { + case State::in_progress: status = "IN_PROGRESS"; break; + case State::failed: status = "FAILED"; break; + case State::success: status = "SUCCESS"; break; + } + summary->addEntry(element.name_, status); + } + return summary; + } + jni::alias_ref getPlugin(const std::string& identifier) { auto plugin = SonarClient::instance()->getPlugin(identifier); if (plugin) { @@ -347,7 +379,6 @@ class JSonarClient : public jni::HybridClass { private: friend HybridBase; std::shared_ptr mStateListener = nullptr; - JSonarClient() {} }; diff --git a/android/src/main/java/com/facebook/sonar/android/SonarClientImpl.java b/android/src/main/java/com/facebook/sonar/android/SonarClientImpl.java index 3d55e2108..11ca1a467 100644 --- a/android/src/main/java/com/facebook/sonar/android/SonarClientImpl.java +++ b/android/src/main/java/com/facebook/sonar/android/SonarClientImpl.java @@ -14,6 +14,7 @@ import com.facebook.sonar.BuildConfig; import com.facebook.sonar.core.SonarClient; import com.facebook.sonar.core.SonarPlugin; import com.facebook.sonar.core.SonarStateUpdateListener; +import com.facebook.sonar.core.StateSummary; @DoNotStrip class SonarClientImpl implements SonarClient { @@ -65,4 +66,7 @@ class SonarClientImpl implements SonarClient { @Override public native String getState(); + + @Override + public native StateSummary getStateSummary(); } diff --git a/android/src/main/java/com/facebook/sonar/core/SonarClient.java b/android/src/main/java/com/facebook/sonar/core/SonarClient.java index 2cbf33ece..583335d6d 100644 --- a/android/src/main/java/com/facebook/sonar/core/SonarClient.java +++ b/android/src/main/java/com/facebook/sonar/core/SonarClient.java @@ -23,4 +23,6 @@ public interface SonarClient { void unsubscribe(); String getState(); + + StateSummary getStateSummary(); } diff --git a/android/src/main/java/com/facebook/sonar/core/StateElement.java b/android/src/main/java/com/facebook/sonar/core/StateElement.java new file mode 100644 index 000000000..0dc7af096 --- /dev/null +++ b/android/src/main/java/com/facebook/sonar/core/StateElement.java @@ -0,0 +1,13 @@ +package com.facebook.sonar.core; + +public class StateElement { + private final String mName; + private final String mState; + public StateElement(String name, String state) { + mName = name; + mState = state; + } + public String getName() { + return mName; + } +} diff --git a/android/src/main/java/com/facebook/sonar/core/StateSummary.java b/android/src/main/java/com/facebook/sonar/core/StateSummary.java new file mode 100644 index 000000000..c036ee995 --- /dev/null +++ b/android/src/main/java/com/facebook/sonar/core/StateSummary.java @@ -0,0 +1,38 @@ +package com.facebook.sonar.core; + +import java.util.List; +import java.util.ArrayList; + +public class StateSummary { + + public enum State { + IN_PROGRESS, SUCCESS, FAILED, UNKNOWN; + } + + public static class StateElement { + private final String mName; + private final State mState; + public StateElement(String name, State state) { + mName = name; + mState = state; + } + public String getName() { + return mName; + } + public State getState() { + return mState; + } + } + + public final List mList = new ArrayList<>(); + + public void addEntry(String name, String state) { + State s; + try { + s = State.valueOf(state); + } catch (RuntimeException e) { + s = State.UNKNOWN; + } + mList.add(new StateElement(name, s)); + } +} diff --git a/xplat/Sonar/SonarClient.cpp b/xplat/Sonar/SonarClient.cpp index f9d1db84a..01913095e 100644 --- a/xplat/Sonar/SonarClient.cpp +++ b/xplat/Sonar/SonarClient.cpp @@ -12,6 +12,7 @@ #include "SonarState.h" #include "SonarStep.h" #include "SonarWebSocketImpl.h" +#include #ifdef __ANDROID__ #include @@ -110,10 +111,8 @@ void SonarClient::refreshPlugins() { void SonarClient::onConnected() { SONAR_LOG("SonarClient::onConnected"); - auto step = sonarState_->start("Connect"); std::lock_guard lock(mutex_); connected_ = true; - step->complete(); } void SonarClient::onDisconnected() { @@ -216,6 +215,10 @@ std::string SonarClient::getState() { return sonarState_->getState(); } +std::vector SonarClient::getStateElements() { + return sonarState_->getStateElements(); +} + } // namespace sonar } // namespace facebook diff --git a/xplat/Sonar/SonarClient.h b/xplat/Sonar/SonarClient.h index 79d0a8a46..0556bc4a6 100644 --- a/xplat/Sonar/SonarClient.h +++ b/xplat/Sonar/SonarClient.h @@ -16,6 +16,7 @@ #include #include #include "SonarStep.h" +#include namespace facebook { namespace sonar { @@ -77,6 +78,8 @@ class SonarClient : public SonarWebSocket::Callbacks { std::string getState(); + std::vector getStateElements(); + template std::shared_ptr

getPlugin(const std::string& identifier) { return std::static_pointer_cast

(getPlugin(identifier)); diff --git a/xplat/Sonar/SonarState.cpp b/xplat/Sonar/SonarState.cpp index 0660e1b36..75a1195c8 100644 --- a/xplat/Sonar/SonarState.cpp +++ b/xplat/Sonar/SonarState.cpp @@ -8,34 +8,41 @@ #include "SonarState.h" #include "SonarStateUpdateListener.h" #include "SonarStep.h" +#include + +using namespace facebook::sonar; /* Class responsible for collecting state updates and combining them into a * view of the current state of the sonar client. */ -SonarState::SonarState() { - stateUpdates = ""; -} + +SonarState::SonarState(): log("") {} void SonarState::setUpdateListener( std::shared_ptr listener) { mListener = listener; } void SonarState::started(std::string step) { - stateUpdates = stateUpdates + "[Started] " + step + "\n"; + if (stateMap.find(step) == stateMap.end()) { + insertOrder.push_back(step); + } + stateMap[step] = State::in_progress; if (mListener) { mListener->onUpdate(); } } void SonarState::success(std::string step) { - stateUpdates = stateUpdates + "[Success] " + step + "\n"; + log = log + "[Success] " + step + "\n"; + stateMap[step] = State::success; if (mListener) { mListener->onUpdate(); } } void SonarState::failed(std::string step, std::string errorMessage) { - stateUpdates = stateUpdates + "[Failed] " + step + "\n"; + log = log + "[Failed] " + step + "\n"; + stateMap[step] = State::failed; if (mListener) { mListener->onUpdate(); } @@ -45,7 +52,15 @@ void SonarState::failed(std::string step, std::string errorMessage) { // representation of the current state so the UI can show it in a more intuitive // way std::string SonarState::getState() { - return stateUpdates; + return log; +} + +std::vector SonarState::getStateElements() { + std::vector v; + for (auto stepName : insertOrder) { + v.push_back(StateElement(stepName, stateMap[stepName])); + } + return v; } std::shared_ptr SonarState::start(std::string step_name) { diff --git a/xplat/Sonar/SonarState.h b/xplat/Sonar/SonarState.h index 705bc3dc0..ecdb2f7df 100644 --- a/xplat/Sonar/SonarState.h +++ b/xplat/Sonar/SonarState.h @@ -10,11 +10,27 @@ #include #include -#include +#include +#include class SonarStep; class SonarStateUpdateListener; +namespace facebook { +namespace sonar { + +enum State { success, in_progress, failed }; + +class StateElement { +public: + StateElement(std::string name, State state): name_(name), state_(state) {}; + std::string name_; + State state_; +}; + +} +} + class SonarState { friend SonarStep; @@ -22,6 +38,7 @@ class SonarState { SonarState(); void setUpdateListener(std::shared_ptr); std::string getState(); + std::vector getStateElements(); /* To record a state update, call start() with the name of the step to get a SonarStep object. Call complete on this to register it successful, @@ -33,6 +50,9 @@ class SonarState { void success(std::string); void failed(std::string, std::string); void started(std::string); + std::shared_ptr mListener = nullptr; - std::string stateUpdates; + std::string log; + std::vector insertOrder; + std::map stateMap; }; diff --git a/xplat/Sonar/SonarWebSocketImpl.cpp b/xplat/Sonar/SonarWebSocketImpl.cpp index 618c93e49..0b0dde106 100644 --- a/xplat/Sonar/SonarWebSocketImpl.cpp +++ b/xplat/Sonar/SonarWebSocketImpl.cpp @@ -7,6 +7,7 @@ */ #include "SonarWebSocketImpl.h" +#include "SonarStep.h" #include #include #include @@ -224,11 +225,12 @@ void SonarWebSocketImpl::sendMessage(const folly::dynamic& message) { } bool SonarWebSocketImpl::isCertificateExchangeNeeded() { - auto step = sonarState_->start("Check required certificates are present"); + if (failedConnectionAttempts_ >= 2) { return true; } + auto step = sonarState_->start("Check required certificates are present"); std::string caCert = loadStringFromFile(absoluteFilePath(SONAR_CA_FILE_NAME)); std::string clientCert = loadStringFromFile(absoluteFilePath(CLIENT_CERT_FILE_NAME));